|
@@ -2,11 +2,15 @@ import 'package:appflowy/generated/flowy_svgs.g.dart';
|
|
|
import 'package:appflowy/generated/locale_keys.g.dart';
|
|
|
import 'package:appflowy/plugins/database_view/application/database_controller.dart';
|
|
|
import 'package:appflowy/plugins/database_view/calendar/application/calendar_bloc.dart';
|
|
|
+import 'package:appflowy/plugins/database_view/calendar/application/unschedule_event_bloc.dart';
|
|
|
+import 'package:appflowy/plugins/database_view/grid/presentation/layout/sizes.dart';
|
|
|
import 'package:appflowy/plugins/database_view/tar_bar/tab_bar_view.dart';
|
|
|
import 'package:appflowy_backend/protobuf/flowy-database2/calendar_entities.pb.dart';
|
|
|
import 'package:appflowy_backend/protobuf/flowy-folder2/view.pb.dart';
|
|
|
+import 'package:appflowy_popover/appflowy_popover.dart';
|
|
|
import 'package:calendar_view/calendar_view.dart';
|
|
|
import 'package:easy_localization/easy_localization.dart';
|
|
|
+import 'package:flowy_infra/size.dart';
|
|
|
|
|
|
import 'package:flowy_infra/theme_extension.dart';
|
|
|
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
|
@@ -119,19 +123,6 @@ class _CalendarPageState extends State<CalendarPage> {
|
|
|
);
|
|
|
},
|
|
|
),
|
|
|
- BlocListener<CalendarBloc, CalendarState>(
|
|
|
- listenWhen: (p, c) => p.editingEvent != c.editingEvent,
|
|
|
- listener: (context, state) {
|
|
|
- if (state.editingEvent != null) {
|
|
|
- showEventDetails(
|
|
|
- context: context,
|
|
|
- event: state.editingEvent!.event!.event,
|
|
|
- viewId: widget.view.id,
|
|
|
- rowCache: _calendarBloc.rowCache,
|
|
|
- );
|
|
|
- }
|
|
|
- },
|
|
|
- ),
|
|
|
BlocListener<CalendarBloc, CalendarState>(
|
|
|
// Event create by click the + button or double click on the
|
|
|
// calendar
|
|
@@ -211,40 +202,49 @@ class _CalendarPageState extends State<CalendarPage> {
|
|
|
}
|
|
|
|
|
|
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: const FlowySvg(FlowySvgs.arrow_left_s),
|
|
|
- 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: const FlowySvg(FlowySvgs.arrow_right_s),
|
|
|
- tooltipText: LocaleKeys.calendar_navigation_nextMonth.tr(),
|
|
|
- hoverColor: AFThemeExtension.of(context).lightGreyHover,
|
|
|
- onPressed: () => _calendarState?.currentState?.nextPage(),
|
|
|
- ),
|
|
|
- ],
|
|
|
+ return SizedBox(
|
|
|
+ height: 24,
|
|
|
+ child: Row(
|
|
|
+ crossAxisAlignment: CrossAxisAlignment.center,
|
|
|
+ children: [
|
|
|
+ FlowyText.medium(
|
|
|
+ DateFormat('MMMM y', context.locale.toLanguageTag())
|
|
|
+ .format(currentMonth),
|
|
|
+ ),
|
|
|
+ const Spacer(),
|
|
|
+ FlowyIconButton(
|
|
|
+ width: CalendarSize.navigatorButtonWidth,
|
|
|
+ height: CalendarSize.navigatorButtonHeight,
|
|
|
+ icon: const FlowySvg(FlowySvgs.arrow_left_s),
|
|
|
+ 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.w400,
|
|
|
+ fontSize: 10,
|
|
|
+ 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: const FlowySvg(FlowySvgs.arrow_right_s),
|
|
|
+ tooltipText: LocaleKeys.calendar_navigation_nextMonth.tr(),
|
|
|
+ hoverColor: AFThemeExtension.of(context).lightGreyHover,
|
|
|
+ onPressed: () => _calendarState?.currentState?.nextPage(),
|
|
|
+ ),
|
|
|
+ const HSpace(6.0),
|
|
|
+ UnscheduledEventsButton(
|
|
|
+ databaseController: widget.databaseController,
|
|
|
+ ),
|
|
|
+ ],
|
|
|
+ ),
|
|
|
);
|
|
|
}
|
|
|
|
|
@@ -255,8 +255,9 @@ class _CalendarPageState extends State<CalendarPage> {
|
|
|
return Center(
|
|
|
child: Padding(
|
|
|
padding: CalendarSize.daysOfWeekInsets,
|
|
|
- child: FlowyText.medium(
|
|
|
+ child: FlowyText.regular(
|
|
|
weekDayString,
|
|
|
+ fontSize: 9,
|
|
|
color: Theme.of(context).hintColor,
|
|
|
),
|
|
|
),
|
|
@@ -321,3 +322,150 @@ void showEventDetails({
|
|
|
},
|
|
|
);
|
|
|
}
|
|
|
+
|
|
|
+class UnscheduledEventsButton extends StatefulWidget {
|
|
|
+ final DatabaseController databaseController;
|
|
|
+
|
|
|
+ const UnscheduledEventsButton({super.key, required this.databaseController});
|
|
|
+
|
|
|
+ @override
|
|
|
+ State<UnscheduledEventsButton> createState() =>
|
|
|
+ _UnscheduledEventsButtonState();
|
|
|
+}
|
|
|
+
|
|
|
+class _UnscheduledEventsButtonState extends State<UnscheduledEventsButton> {
|
|
|
+ late final PopoverController _popoverController;
|
|
|
+
|
|
|
+ @override
|
|
|
+ void initState() {
|
|
|
+ super.initState();
|
|
|
+ _popoverController = PopoverController();
|
|
|
+ }
|
|
|
+
|
|
|
+ @override
|
|
|
+ Widget build(BuildContext context) {
|
|
|
+ return BlocProvider<UnscheduleEventsBloc>(
|
|
|
+ create: (_) =>
|
|
|
+ UnscheduleEventsBloc(databaseController: widget.databaseController)
|
|
|
+ ..add(const UnscheduleEventsEvent.initial()),
|
|
|
+ child: BlocBuilder<UnscheduleEventsBloc, UnscheduleEventsState>(
|
|
|
+ builder: (context, state) {
|
|
|
+ return AppFlowyPopover(
|
|
|
+ direction: PopoverDirection.bottomWithCenterAligned,
|
|
|
+ triggerActions: PopoverTriggerFlags.none,
|
|
|
+ controller: _popoverController,
|
|
|
+ offset: const Offset(0, 8),
|
|
|
+ constraints: const BoxConstraints(maxWidth: 282, maxHeight: 600),
|
|
|
+ child: OutlinedButton(
|
|
|
+ style: OutlinedButton.styleFrom(
|
|
|
+ shape: RoundedRectangleBorder(
|
|
|
+ side: BorderSide(
|
|
|
+ color: Theme.of(context).dividerColor,
|
|
|
+ width: 1,
|
|
|
+ ),
|
|
|
+ borderRadius: Corners.s6Border,
|
|
|
+ ),
|
|
|
+ side:
|
|
|
+ BorderSide(color: Theme.of(context).dividerColor, width: 1),
|
|
|
+ padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
|
|
|
+ visualDensity: VisualDensity.compact,
|
|
|
+ ),
|
|
|
+ onPressed: () {
|
|
|
+ if (state.unscheduleEvents.isNotEmpty) {
|
|
|
+ _popoverController.show();
|
|
|
+ }
|
|
|
+ },
|
|
|
+ child: FlowyText.regular(
|
|
|
+ "${LocaleKeys.calendar_settings_noDateTitle.tr()} (${state.unscheduleEvents.length})",
|
|
|
+ fontSize: 10,
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ popupBuilder: (context) {
|
|
|
+ return UnscheduleEventsList(
|
|
|
+ viewId: widget.databaseController.viewId,
|
|
|
+ rowCache: widget.databaseController.rowCache,
|
|
|
+ unscheduleEvents: state.unscheduleEvents,
|
|
|
+ );
|
|
|
+ },
|
|
|
+ );
|
|
|
+ },
|
|
|
+ ),
|
|
|
+ );
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+class UnscheduleEventsList extends StatelessWidget {
|
|
|
+ final String viewId;
|
|
|
+ final RowCache rowCache;
|
|
|
+ final List<CalendarEventPB> unscheduleEvents;
|
|
|
+ const UnscheduleEventsList({
|
|
|
+ required this.viewId,
|
|
|
+ required this.unscheduleEvents,
|
|
|
+ required this.rowCache,
|
|
|
+ super.key,
|
|
|
+ });
|
|
|
+
|
|
|
+ @override
|
|
|
+ Widget build(BuildContext context) {
|
|
|
+ final cells = <Widget>[
|
|
|
+ Padding(
|
|
|
+ padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 4),
|
|
|
+ child: FlowyText.medium(
|
|
|
+ LocaleKeys.calendar_settings_clickToAdd.tr(),
|
|
|
+ fontSize: 10,
|
|
|
+ color: Theme.of(context).hintColor,
|
|
|
+ overflow: TextOverflow.ellipsis,
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ ...unscheduleEvents.map(
|
|
|
+ (e) => UnscheduledEventCell(
|
|
|
+ event: e,
|
|
|
+ onPressed: () {
|
|
|
+ showEventDetails(
|
|
|
+ context: context,
|
|
|
+ event: e,
|
|
|
+ viewId: viewId,
|
|
|
+ rowCache: rowCache,
|
|
|
+ );
|
|
|
+ PopoverContainer.of(context).close();
|
|
|
+ },
|
|
|
+ ),
|
|
|
+ )
|
|
|
+ ];
|
|
|
+
|
|
|
+ return ListView.separated(
|
|
|
+ itemBuilder: (context, index) => cells[index],
|
|
|
+ itemCount: cells.length,
|
|
|
+ separatorBuilder: (context, index) =>
|
|
|
+ VSpace(GridSize.typeOptionSeparatorHeight),
|
|
|
+ shrinkWrap: true,
|
|
|
+ );
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+class UnscheduledEventCell extends StatelessWidget {
|
|
|
+ final CalendarEventPB event;
|
|
|
+ final VoidCallback onPressed;
|
|
|
+ const UnscheduledEventCell({
|
|
|
+ required this.event,
|
|
|
+ required this.onPressed,
|
|
|
+ Key? key,
|
|
|
+ }) : super(key: key);
|
|
|
+
|
|
|
+ @override
|
|
|
+ Widget build(BuildContext context) {
|
|
|
+ return SizedBox(
|
|
|
+ height: 26,
|
|
|
+ child: FlowyButton(
|
|
|
+ margin: const EdgeInsets.symmetric(horizontal: 8.0, vertical: 4.0),
|
|
|
+ text: FlowyText.medium(
|
|
|
+ event.title.isEmpty
|
|
|
+ ? LocaleKeys.calendar_defaultNewCalendarTitle.tr()
|
|
|
+ : event.title,
|
|
|
+ fontSize: 11,
|
|
|
+ ),
|
|
|
+ onTap: onPressed,
|
|
|
+ ),
|
|
|
+ );
|
|
|
+ }
|
|
|
+}
|