|
@@ -1,13 +1,14 @@
|
|
import 'package:appflowy/generated/flowy_svgs.g.dart';
|
|
import 'package:appflowy/generated/flowy_svgs.g.dart';
|
|
|
|
+import 'package:appflowy/generated/locale_keys.g.dart';
|
|
import 'package:appflowy/plugins/database_view/application/row/row_cache.dart';
|
|
import 'package:appflowy/plugins/database_view/application/row/row_cache.dart';
|
|
import 'package:easy_localization/easy_localization.dart';
|
|
import 'package:easy_localization/easy_localization.dart';
|
|
-
|
|
|
|
import 'package:flowy_infra/size.dart';
|
|
import 'package:flowy_infra/size.dart';
|
|
|
|
+
|
|
import 'package:flowy_infra/theme_extension.dart';
|
|
import 'package:flowy_infra/theme_extension.dart';
|
|
|
|
+import 'package:flowy_infra/time/duration.dart';
|
|
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
|
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:provider/provider.dart';
|
|
import 'package:provider/provider.dart';
|
|
-import 'package:table_calendar/table_calendar.dart';
|
|
|
|
|
|
|
|
import '../../grid/presentation/layout/sizes.dart';
|
|
import '../../grid/presentation/layout/sizes.dart';
|
|
import '../application/calendar_bloc.dart';
|
|
import '../application/calendar_bloc.dart';
|
|
@@ -18,7 +19,7 @@ class CalendarDayCard extends StatelessWidget {
|
|
final bool isToday;
|
|
final bool isToday;
|
|
final bool isInMonth;
|
|
final bool isInMonth;
|
|
final DateTime date;
|
|
final DateTime date;
|
|
- final RowCache _rowCache;
|
|
|
|
|
|
+ final RowCache rowCache;
|
|
final List<CalendarDayEvent> events;
|
|
final List<CalendarDayEvent> events;
|
|
final void Function(DateTime) onCreateEvent;
|
|
final void Function(DateTime) onCreateEvent;
|
|
|
|
|
|
@@ -28,18 +29,21 @@ class CalendarDayCard extends StatelessWidget {
|
|
required this.isInMonth,
|
|
required this.isInMonth,
|
|
required this.date,
|
|
required this.date,
|
|
required this.onCreateEvent,
|
|
required this.onCreateEvent,
|
|
- required RowCache rowCache,
|
|
|
|
|
|
+ required this.rowCache,
|
|
required this.events,
|
|
required this.events,
|
|
- Key? key,
|
|
|
|
- }) : _rowCache = rowCache,
|
|
|
|
- super(key: key);
|
|
|
|
|
|
+ super.key,
|
|
|
|
+ });
|
|
|
|
|
|
@override
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
Widget build(BuildContext context) {
|
|
- Color backgroundColor = Theme.of(context).colorScheme.surface;
|
|
|
|
- if (!isInMonth) {
|
|
|
|
- backgroundColor = AFThemeExtension.of(context).lightGreyHover;
|
|
|
|
|
|
+ Color backgroundColor = Colors.transparent;
|
|
|
|
+ if (date.isWeekend) {
|
|
|
|
+ backgroundColor = AFThemeExtension.of(context).calendarWeekendBGColor;
|
|
}
|
|
}
|
|
|
|
+ final hoverBackgroundColor =
|
|
|
|
+ Theme.of(context).brightness == Brightness.light
|
|
|
|
+ ? Theme.of(context).colorScheme.secondaryContainer
|
|
|
|
+ : Colors.transparent;
|
|
|
|
|
|
return LayoutBuilder(
|
|
return LayoutBuilder(
|
|
builder: (BuildContext context, BoxConstraints constraints) {
|
|
builder: (BuildContext context, BoxConstraints constraints) {
|
|
@@ -57,14 +61,14 @@ class CalendarDayCard extends StatelessWidget {
|
|
),
|
|
),
|
|
|
|
|
|
// Add a separator between the header and the content.
|
|
// Add a separator between the header and the content.
|
|
- VSpace(GridSize.typeOptionSeparatorHeight),
|
|
|
|
|
|
+ const VSpace(6.0),
|
|
|
|
|
|
// List of cards or empty space
|
|
// List of cards or empty space
|
|
if (events.isNotEmpty)
|
|
if (events.isNotEmpty)
|
|
_EventList(
|
|
_EventList(
|
|
events: events,
|
|
events: events,
|
|
viewId: viewId,
|
|
viewId: viewId,
|
|
- rowCache: _rowCache,
|
|
|
|
|
|
+ rowCache: rowCache,
|
|
constraints: constraints,
|
|
constraints: constraints,
|
|
),
|
|
),
|
|
],
|
|
],
|
|
@@ -79,34 +83,29 @@ class CalendarDayCard extends StatelessWidget {
|
|
DragTarget<CalendarDayEvent>(
|
|
DragTarget<CalendarDayEvent>(
|
|
builder: (context, candidate, __) {
|
|
builder: (context, candidate, __) {
|
|
return Stack(
|
|
return Stack(
|
|
- fit: StackFit.expand,
|
|
|
|
children: [
|
|
children: [
|
|
- if (candidate.isNotEmpty)
|
|
|
|
- Container(
|
|
|
|
- color: Theme.of(context)
|
|
|
|
- .colorScheme
|
|
|
|
- .secondaryContainer,
|
|
|
|
- ),
|
|
|
|
- Padding(
|
|
|
|
- padding: const EdgeInsets.only(top: 8.0),
|
|
|
|
|
|
+ Container(
|
|
|
|
+ width: double.infinity,
|
|
|
|
+ height: double.infinity,
|
|
|
|
+ color:
|
|
|
|
+ candidate.isEmpty ? null : hoverBackgroundColor,
|
|
|
|
+ padding: const EdgeInsets.only(top: 5.0),
|
|
child: child,
|
|
child: child,
|
|
- )
|
|
|
|
|
|
+ ),
|
|
|
|
+ if (candidate.isEmpty)
|
|
|
|
+ NewEventButton(onCreate: () => onCreateEvent(date)),
|
|
],
|
|
],
|
|
);
|
|
);
|
|
},
|
|
},
|
|
- onWillAccept: (CalendarDayEvent? event) {
|
|
|
|
- if (event == null) {
|
|
|
|
- return false;
|
|
|
|
- }
|
|
|
|
- return !isSameDay(event.date, date);
|
|
|
|
- },
|
|
|
|
onAccept: (CalendarDayEvent event) {
|
|
onAccept: (CalendarDayEvent event) {
|
|
|
|
+ if (event.date == date) {
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
context
|
|
context
|
|
.read<CalendarBloc>()
|
|
.read<CalendarBloc>()
|
|
.add(CalendarEvent.moveEvent(event, date));
|
|
.add(CalendarEvent.moveEvent(event, date));
|
|
},
|
|
},
|
|
),
|
|
),
|
|
- NewEventButton(onCreate: () => onCreateEvent(date)),
|
|
|
|
MouseRegion(
|
|
MouseRegion(
|
|
onEnter: (p) => notifyEnter(context, true),
|
|
onEnter: (p) => notifyEnter(context, true),
|
|
onExit: (p) => notifyEnter(context, false),
|
|
onExit: (p) => notifyEnter(context, false),
|
|
@@ -143,7 +142,7 @@ class _Header extends StatelessWidget {
|
|
@override
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
Widget build(BuildContext context) {
|
|
return Padding(
|
|
return Padding(
|
|
- padding: const EdgeInsets.symmetric(horizontal: 8.0),
|
|
|
|
|
|
+ padding: const EdgeInsets.symmetric(horizontal: 6.0),
|
|
child: _DayBadge(
|
|
child: _DayBadge(
|
|
isToday: isToday,
|
|
isToday: isToday,
|
|
isInMonth: isInMonth,
|
|
isInMonth: isInMonth,
|
|
@@ -166,7 +165,7 @@ class NewEventButton extends StatelessWidget {
|
|
return const SizedBox.shrink();
|
|
return const SizedBox.shrink();
|
|
}
|
|
}
|
|
return Padding(
|
|
return Padding(
|
|
- padding: const EdgeInsets.all(8.0),
|
|
|
|
|
|
+ padding: const EdgeInsets.all(4.0),
|
|
child: FlowyIconButton(
|
|
child: FlowyIconButton(
|
|
onPressed: onCreate,
|
|
onPressed: onCreate,
|
|
iconPadding: EdgeInsets.zero,
|
|
iconPadding: EdgeInsets.zero,
|
|
@@ -174,6 +173,35 @@ class NewEventButton extends StatelessWidget {
|
|
fillColor: Theme.of(context).colorScheme.background,
|
|
fillColor: Theme.of(context).colorScheme.background,
|
|
hoverColor: AFThemeExtension.of(context).lightGreyHover,
|
|
hoverColor: AFThemeExtension.of(context).lightGreyHover,
|
|
width: 22,
|
|
width: 22,
|
|
|
|
+ tooltipText: LocaleKeys.calendar_newEventButtonTooltip.tr(),
|
|
|
|
+ decoration: BoxDecoration(
|
|
|
|
+ border: Border.fromBorderSide(
|
|
|
|
+ BorderSide(
|
|
|
|
+ color: Theme.of(context).brightness == Brightness.light
|
|
|
|
+ ? const Color(0xffd0d3d6)
|
|
|
|
+ : const Color(0xff59647a),
|
|
|
|
+ width: 0.5,
|
|
|
|
+ ),
|
|
|
|
+ ),
|
|
|
|
+ borderRadius: Corners.s5Border,
|
|
|
|
+ boxShadow: [
|
|
|
|
+ BoxShadow(
|
|
|
|
+ spreadRadius: -2,
|
|
|
|
+ color: const Color(0xFF1F2329).withOpacity(0.02),
|
|
|
|
+ blurRadius: 2,
|
|
|
|
+ ),
|
|
|
|
+ BoxShadow(
|
|
|
|
+ spreadRadius: 0,
|
|
|
|
+ color: const Color(0xFF1F2329).withOpacity(0.02),
|
|
|
|
+ blurRadius: 4,
|
|
|
|
+ ),
|
|
|
|
+ BoxShadow(
|
|
|
|
+ spreadRadius: 2,
|
|
|
|
+ color: const Color(0xFF1F2329).withOpacity(0.02),
|
|
|
|
+ blurRadius: 8,
|
|
|
|
+ ),
|
|
|
|
+ ],
|
|
|
|
+ ),
|
|
),
|
|
),
|
|
);
|
|
);
|
|
},
|
|
},
|
|
@@ -195,37 +223,49 @@ class _DayBadge extends StatelessWidget {
|
|
@override
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
Widget build(BuildContext context) {
|
|
Color dayTextColor = Theme.of(context).colorScheme.onBackground;
|
|
Color dayTextColor = Theme.of(context).colorScheme.onBackground;
|
|
|
|
+ Color monthTextColor = Theme.of(context).colorScheme.onBackground;
|
|
final String monthString =
|
|
final String monthString =
|
|
DateFormat("MMM ", context.locale.toLanguageTag()).format(date);
|
|
DateFormat("MMM ", context.locale.toLanguageTag()).format(date);
|
|
final String dayString = date.day.toString();
|
|
final String dayString = date.day.toString();
|
|
|
|
|
|
if (!isInMonth) {
|
|
if (!isInMonth) {
|
|
dayTextColor = Theme.of(context).disabledColor;
|
|
dayTextColor = Theme.of(context).disabledColor;
|
|
|
|
+ monthTextColor = Theme.of(context).disabledColor;
|
|
}
|
|
}
|
|
if (isToday) {
|
|
if (isToday) {
|
|
dayTextColor = Theme.of(context).colorScheme.onPrimary;
|
|
dayTextColor = Theme.of(context).colorScheme.onPrimary;
|
|
}
|
|
}
|
|
|
|
|
|
- return Row(
|
|
|
|
- mainAxisAlignment: MainAxisAlignment.end,
|
|
|
|
- children: [
|
|
|
|
- if (date.day == 1) FlowyText.medium(monthString),
|
|
|
|
- Container(
|
|
|
|
- decoration: BoxDecoration(
|
|
|
|
- color: isToday ? Theme.of(context).colorScheme.primary : null,
|
|
|
|
- borderRadius: Corners.s6Border,
|
|
|
|
- ),
|
|
|
|
- width: isToday ? 26 : null,
|
|
|
|
- height: isToday ? 26 : null,
|
|
|
|
- padding: GridSize.typeOptionContentInsets,
|
|
|
|
- child: Center(
|
|
|
|
- child: FlowyText.medium(
|
|
|
|
- dayString,
|
|
|
|
- color: dayTextColor,
|
|
|
|
|
|
+ return SizedBox(
|
|
|
|
+ height: 18,
|
|
|
|
+ child: Row(
|
|
|
|
+ mainAxisAlignment: MainAxisAlignment.end,
|
|
|
|
+ crossAxisAlignment: CrossAxisAlignment.center,
|
|
|
|
+ children: [
|
|
|
|
+ if (date.day == 1)
|
|
|
|
+ FlowyText.medium(
|
|
|
|
+ monthString,
|
|
|
|
+ fontSize: 11,
|
|
|
|
+ color: monthTextColor,
|
|
|
|
+ ),
|
|
|
|
+ Container(
|
|
|
|
+ decoration: BoxDecoration(
|
|
|
|
+ color: isToday ? Theme.of(context).colorScheme.primary : null,
|
|
|
|
+ borderRadius: BorderRadius.circular(10),
|
|
|
|
+ ),
|
|
|
|
+ width: isToday ? 18 : null,
|
|
|
|
+ height: isToday ? 18 : null,
|
|
|
|
+ // padding: GridSize.typeOptionContentInsets,
|
|
|
|
+ child: Center(
|
|
|
|
+ child: FlowyText.medium(
|
|
|
|
+ dayString,
|
|
|
|
+ fontSize: 11,
|
|
|
|
+ color: dayTextColor,
|
|
|
|
+ ),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
- ),
|
|
|
|
- ],
|
|
|
|
|
|
+ ],
|
|
|
|
+ ),
|
|
);
|
|
);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -246,20 +286,26 @@ class _EventList extends StatelessWidget {
|
|
|
|
|
|
@override
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
Widget build(BuildContext context) {
|
|
|
|
+ final editingEvent = context.watch<CalendarBloc>().state.editingEvent;
|
|
return Flexible(
|
|
return Flexible(
|
|
child: ScrollConfiguration(
|
|
child: ScrollConfiguration(
|
|
behavior: ScrollConfiguration.of(context).copyWith(
|
|
behavior: ScrollConfiguration.of(context).copyWith(
|
|
scrollbars: true,
|
|
scrollbars: true,
|
|
),
|
|
),
|
|
child: ListView.separated(
|
|
child: ListView.separated(
|
|
- itemBuilder: (BuildContext context, int index) => EventCard(
|
|
|
|
- event: events[index],
|
|
|
|
- viewId: viewId,
|
|
|
|
- rowCache: rowCache,
|
|
|
|
- constraints: constraints,
|
|
|
|
- ),
|
|
|
|
|
|
+ itemBuilder: (BuildContext context, int index) {
|
|
|
|
+ final autoEdit =
|
|
|
|
+ editingEvent?.event?.eventId == events[index].eventId;
|
|
|
|
+ return EventCard(
|
|
|
|
+ event: events[index],
|
|
|
|
+ viewId: viewId,
|
|
|
|
+ rowCache: rowCache,
|
|
|
|
+ constraints: constraints,
|
|
|
|
+ autoEdit: autoEdit,
|
|
|
|
+ );
|
|
|
|
+ },
|
|
itemCount: events.length,
|
|
itemCount: events.length,
|
|
- padding: const EdgeInsets.fromLTRB(8.0, 0, 8.0, 8.0),
|
|
|
|
|
|
+ padding: const EdgeInsets.fromLTRB(4.0, 0, 4.0, 4.0),
|
|
separatorBuilder: (BuildContext context, int index) =>
|
|
separatorBuilder: (BuildContext context, int index) =>
|
|
VSpace(GridSize.typeOptionSeparatorHeight),
|
|
VSpace(GridSize.typeOptionSeparatorHeight),
|
|
shrinkWrap: true,
|
|
shrinkWrap: true,
|