|
@@ -1,20 +1,20 @@
|
|
import 'package:appflowy/plugins/database_view/application/row/row_cache.dart';
|
|
import 'package:appflowy/plugins/database_view/application/row/row_cache.dart';
|
|
import 'package:appflowy/plugins/database_view/application/row/row_data_controller.dart';
|
|
import 'package:appflowy/plugins/database_view/application/row/row_data_controller.dart';
|
|
|
|
+import 'package:appflowy/plugins/database_view/widgets/card/card.dart';
|
|
import 'package:appflowy/plugins/database_view/widgets/card/card_cell_builder.dart';
|
|
import 'package:appflowy/plugins/database_view/widgets/card/card_cell_builder.dart';
|
|
-import 'package:appflowy/plugins/database_view/widgets/card/cells/text_card_cell.dart';
|
|
|
|
|
|
+import 'package:appflowy/plugins/database_view/widgets/card/cells/card_cell.dart';
|
|
import 'package:appflowy/plugins/database_view/widgets/row/cell_builder.dart';
|
|
import 'package:appflowy/plugins/database_view/widgets/row/cell_builder.dart';
|
|
import 'package:appflowy/plugins/database_view/widgets/row/row_detail.dart';
|
|
import 'package:appflowy/plugins/database_view/widgets/row/row_detail.dart';
|
|
-import 'package:appflowy_backend/protobuf/flowy-database/field_entities.pbenum.dart';
|
|
|
|
import 'package:easy_localization/easy_localization.dart';
|
|
import 'package:easy_localization/easy_localization.dart';
|
|
import 'package:flowy_infra/image.dart';
|
|
import 'package:flowy_infra/image.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_ui/flowy_infra_ui.dart';
|
|
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
|
-import 'package:flowy_infra_ui/style_widget/hover.dart';
|
|
|
|
import 'package:flutter/material.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:provider/provider.dart';
|
|
import 'package:provider/provider.dart';
|
|
|
|
|
|
import '../../grid/presentation/layout/sizes.dart';
|
|
import '../../grid/presentation/layout/sizes.dart';
|
|
|
|
+import '../../widgets/row/cells/select_option_cell/extension.dart';
|
|
import '../application/calendar_bloc.dart';
|
|
import '../application/calendar_bloc.dart';
|
|
|
|
|
|
class CalendarDayCard extends StatelessWidget {
|
|
class CalendarDayCard extends StatelessWidget {
|
|
@@ -23,11 +23,10 @@ class CalendarDayCard extends StatelessWidget {
|
|
final bool isInMonth;
|
|
final bool isInMonth;
|
|
final DateTime date;
|
|
final DateTime date;
|
|
final RowCache _rowCache;
|
|
final RowCache _rowCache;
|
|
- final CardCellBuilder _cellBuilder;
|
|
|
|
final List<CalendarDayEvent> events;
|
|
final List<CalendarDayEvent> events;
|
|
final void Function(DateTime) onCreateEvent;
|
|
final void Function(DateTime) onCreateEvent;
|
|
|
|
|
|
- CalendarDayCard({
|
|
|
|
|
|
+ const CalendarDayCard({
|
|
required this.viewId,
|
|
required this.viewId,
|
|
required this.isToday,
|
|
required this.isToday,
|
|
required this.isInMonth,
|
|
required this.isInMonth,
|
|
@@ -37,7 +36,6 @@ class CalendarDayCard extends StatelessWidget {
|
|
required this.events,
|
|
required this.events,
|
|
Key? key,
|
|
Key? key,
|
|
}) : _rowCache = rowCache,
|
|
}) : _rowCache = rowCache,
|
|
- _cellBuilder = CardCellBuilder(rowCache.cellCache),
|
|
|
|
super(key: key);
|
|
super(key: key);
|
|
|
|
|
|
@override
|
|
@override
|
|
@@ -50,42 +48,38 @@ class CalendarDayCard extends StatelessWidget {
|
|
return ChangeNotifierProvider(
|
|
return ChangeNotifierProvider(
|
|
create: (_) => _CardEnterNotifier(),
|
|
create: (_) => _CardEnterNotifier(),
|
|
builder: (context, child) {
|
|
builder: (context, child) {
|
|
- final children = events.map((event) {
|
|
|
|
- return _DayEventCell(
|
|
|
|
- event: event,
|
|
|
|
- viewId: viewId,
|
|
|
|
- onClick: () => _showRowDetailPage(event, context),
|
|
|
|
- child: _cellBuilder.buildCell(
|
|
|
|
- cellId: event.cellId,
|
|
|
|
- styles: {FieldType.RichText: TextCardCellStyle(10)},
|
|
|
|
|
|
+ List<GestureDetector> cards = _buildCards(context);
|
|
|
|
+
|
|
|
|
+ Widget? multipleCards;
|
|
|
|
+ if (cards.isNotEmpty) {
|
|
|
|
+ multipleCards = Flexible(
|
|
|
|
+ child: ListView.separated(
|
|
|
|
+ itemBuilder: (BuildContext context, int index) {
|
|
|
|
+ return cards[index];
|
|
|
|
+ },
|
|
|
|
+ itemCount: cards.length,
|
|
|
|
+ padding: const EdgeInsets.symmetric(horizontal: 8.0),
|
|
|
|
+ separatorBuilder: (BuildContext context, int index) =>
|
|
|
|
+ VSpace(GridSize.typeOptionSeparatorHeight),
|
|
),
|
|
),
|
|
);
|
|
);
|
|
- }).toList();
|
|
|
|
|
|
+ }
|
|
|
|
|
|
final child = Column(
|
|
final child = Column(
|
|
mainAxisSize: MainAxisSize.min,
|
|
mainAxisSize: MainAxisSize.min,
|
|
children: [
|
|
children: [
|
|
- Padding(
|
|
|
|
- padding: const EdgeInsets.symmetric(horizontal: 8.0),
|
|
|
|
- child: _Header(
|
|
|
|
- date: date,
|
|
|
|
- isInMonth: isInMonth,
|
|
|
|
- isToday: isToday,
|
|
|
|
- onCreate: () => onCreateEvent(date),
|
|
|
|
- ),
|
|
|
|
|
|
+ _Header(
|
|
|
|
+ date: date,
|
|
|
|
+ isInMonth: isInMonth,
|
|
|
|
+ isToday: isToday,
|
|
|
|
+ onCreate: () => onCreateEvent(date),
|
|
),
|
|
),
|
|
|
|
+
|
|
|
|
+ // Add a separator between the header and the content.
|
|
VSpace(GridSize.typeOptionSeparatorHeight),
|
|
VSpace(GridSize.typeOptionSeparatorHeight),
|
|
- Flexible(
|
|
|
|
- child: ListView.separated(
|
|
|
|
- itemBuilder: (BuildContext context, int index) {
|
|
|
|
- return children[index];
|
|
|
|
- },
|
|
|
|
- itemCount: children.length,
|
|
|
|
- padding: const EdgeInsets.symmetric(horizontal: 8.0),
|
|
|
|
- separatorBuilder: (BuildContext context, int index) =>
|
|
|
|
- VSpace(GridSize.typeOptionSeparatorHeight),
|
|
|
|
- ),
|
|
|
|
- ),
|
|
|
|
|
|
+
|
|
|
|
+ // Use SizedBox instead of ListView if there are no cards.
|
|
|
|
+ multipleCards ?? const SizedBox(),
|
|
],
|
|
],
|
|
);
|
|
);
|
|
|
|
|
|
@@ -96,7 +90,7 @@ class CalendarDayCard extends StatelessWidget {
|
|
onEnter: (p) => notifyEnter(context, true),
|
|
onEnter: (p) => notifyEnter(context, true),
|
|
onExit: (p) => notifyEnter(context, false),
|
|
onExit: (p) => notifyEnter(context, false),
|
|
child: Padding(
|
|
child: Padding(
|
|
- padding: const EdgeInsets.symmetric(vertical: 8.0),
|
|
|
|
|
|
+ padding: const EdgeInsets.symmetric(vertical: 2.0),
|
|
child: child,
|
|
child: child,
|
|
),
|
|
),
|
|
),
|
|
),
|
|
@@ -105,6 +99,113 @@ class CalendarDayCard extends StatelessWidget {
|
|
);
|
|
);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ List<GestureDetector> _buildCards(BuildContext context) {
|
|
|
|
+ final children = events.map((CalendarDayEvent event) {
|
|
|
|
+ final cellBuilder = CardCellBuilder<String>(_rowCache.cellCache);
|
|
|
|
+ final rowInfo = _rowCache.getRow(event.eventId);
|
|
|
|
+
|
|
|
|
+ final renderHook = RowCardRenderHook<String>();
|
|
|
|
+ renderHook.addTextFieldHook((cellData, primaryFieldId, _) {
|
|
|
|
+ if (cellData.isEmpty) {
|
|
|
|
+ return const SizedBox();
|
|
|
|
+ }
|
|
|
|
+ return Align(
|
|
|
|
+ alignment: Alignment.centerLeft,
|
|
|
|
+ child: FlowyText.medium(
|
|
|
|
+ cellData,
|
|
|
|
+ textAlign: TextAlign.left,
|
|
|
|
+ fontSize: 11,
|
|
|
|
+ maxLines: null, // Enable multiple lines
|
|
|
|
+ ),
|
|
|
|
+ );
|
|
|
|
+ });
|
|
|
|
+
|
|
|
|
+ renderHook.addDateFieldHook((cellData, cardData, _) {
|
|
|
|
+ return Align(
|
|
|
|
+ alignment: Alignment.centerLeft,
|
|
|
|
+ child: Padding(
|
|
|
|
+ padding: const EdgeInsets.symmetric(vertical: 2),
|
|
|
|
+ child: Row(
|
|
|
|
+ children: [
|
|
|
|
+ FlowyText.regular(
|
|
|
|
+ cellData.date,
|
|
|
|
+ fontSize: 10,
|
|
|
|
+ color: Theme.of(context).hintColor,
|
|
|
|
+ ),
|
|
|
|
+ const Spacer(),
|
|
|
|
+ FlowyText.regular(
|
|
|
|
+ cellData.time,
|
|
|
|
+ fontSize: 10,
|
|
|
|
+ color: Theme.of(context).hintColor,
|
|
|
|
+ )
|
|
|
|
+ ],
|
|
|
|
+ ),
|
|
|
|
+ ),
|
|
|
|
+ );
|
|
|
|
+ });
|
|
|
|
+
|
|
|
|
+ renderHook.addSelectOptionHook((selectedOptions, cardData, _) {
|
|
|
|
+ final children = selectedOptions.map(
|
|
|
|
+ (option) {
|
|
|
|
+ return SelectOptionTag.fromOption(
|
|
|
|
+ context: context,
|
|
|
|
+ option: option,
|
|
|
|
+ );
|
|
|
|
+ },
|
|
|
|
+ ).toList();
|
|
|
|
+
|
|
|
|
+ return IntrinsicHeight(
|
|
|
|
+ child: Padding(
|
|
|
|
+ padding: const EdgeInsets.symmetric(vertical: 2),
|
|
|
|
+ child: SizedBox.expand(
|
|
|
|
+ child: Wrap(spacing: 4, runSpacing: 4, children: children),
|
|
|
|
+ ),
|
|
|
|
+ ),
|
|
|
|
+ );
|
|
|
|
+ });
|
|
|
|
+
|
|
|
|
+ // renderHook.addDateFieldHook((cellData, cardData) {
|
|
|
|
+
|
|
|
|
+ final card = RowCard<String>(
|
|
|
|
+ // Add the key here to make sure the card is rebuilt when the cells
|
|
|
|
+ // in this row are updated.
|
|
|
|
+ key: ValueKey(event.eventId),
|
|
|
|
+ row: rowInfo!.rowPB,
|
|
|
|
+ viewId: viewId,
|
|
|
|
+ rowCache: _rowCache,
|
|
|
|
+ cardData: event.fieldId,
|
|
|
|
+ isEditing: false,
|
|
|
|
+ cellBuilder: cellBuilder,
|
|
|
|
+ openCard: (context) => _showRowDetailPage(event, context),
|
|
|
|
+ styleConfiguration: const RowCardStyleConfiguration(
|
|
|
|
+ showAccessory: false,
|
|
|
|
+ cellPadding: EdgeInsets.zero,
|
|
|
|
+ ),
|
|
|
|
+ renderHook: renderHook,
|
|
|
|
+ onStartEditing: () {},
|
|
|
|
+ onEndEditing: () {},
|
|
|
|
+ );
|
|
|
|
+
|
|
|
|
+ return GestureDetector(
|
|
|
|
+ onTap: () => _showRowDetailPage(event, context),
|
|
|
|
+ child: Container(
|
|
|
|
+ padding: const EdgeInsets.symmetric(horizontal: 2),
|
|
|
|
+ decoration: BoxDecoration(
|
|
|
|
+ border: Border.fromBorderSide(
|
|
|
|
+ BorderSide(
|
|
|
|
+ color: Theme.of(context).dividerColor,
|
|
|
|
+ width: 1.5,
|
|
|
|
+ ),
|
|
|
|
+ ),
|
|
|
|
+ borderRadius: Corners.s6Border,
|
|
|
|
+ ),
|
|
|
|
+ child: card,
|
|
|
|
+ ),
|
|
|
|
+ );
|
|
|
|
+ }).toList();
|
|
|
|
+ return children;
|
|
|
|
+ }
|
|
|
|
+
|
|
void _showRowDetailPage(CalendarDayEvent event, BuildContext context) {
|
|
void _showRowDetailPage(CalendarDayEvent event, BuildContext context) {
|
|
final dataController = RowController(
|
|
final dataController = RowController(
|
|
rowId: event.cellId.rowId,
|
|
rowId: event.cellId.rowId,
|
|
@@ -133,42 +234,6 @@ class CalendarDayCard extends StatelessWidget {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
-class _DayEventCell extends StatelessWidget {
|
|
|
|
- final String viewId;
|
|
|
|
- final CalendarDayEvent event;
|
|
|
|
- final VoidCallback onClick;
|
|
|
|
- final Widget child;
|
|
|
|
- const _DayEventCell({
|
|
|
|
- required this.viewId,
|
|
|
|
- required this.event,
|
|
|
|
- required this.onClick,
|
|
|
|
- required this.child,
|
|
|
|
- Key? key,
|
|
|
|
- }) : super(key: key);
|
|
|
|
-
|
|
|
|
- @override
|
|
|
|
- Widget build(BuildContext context) {
|
|
|
|
- return FlowyHover(
|
|
|
|
- child: GestureDetector(
|
|
|
|
- onTap: onClick,
|
|
|
|
- child: Container(
|
|
|
|
- padding: const EdgeInsets.symmetric(horizontal: 8),
|
|
|
|
- decoration: BoxDecoration(
|
|
|
|
- border: Border.fromBorderSide(
|
|
|
|
- BorderSide(
|
|
|
|
- color: Theme.of(context).dividerColor,
|
|
|
|
- width: 1.0,
|
|
|
|
- ),
|
|
|
|
- ),
|
|
|
|
- borderRadius: Corners.s6Border,
|
|
|
|
- ),
|
|
|
|
- child: child,
|
|
|
|
- ),
|
|
|
|
- ),
|
|
|
|
- );
|
|
|
|
- }
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
class _Header extends StatelessWidget {
|
|
class _Header extends StatelessWidget {
|
|
final bool isToday;
|
|
final bool isToday;
|
|
final bool isInMonth;
|
|
final bool isInMonth;
|
|
@@ -191,12 +256,16 @@ class _Header extends StatelessWidget {
|
|
isInMonth: isInMonth,
|
|
isInMonth: isInMonth,
|
|
date: date,
|
|
date: date,
|
|
);
|
|
);
|
|
- return Row(
|
|
|
|
- children: [
|
|
|
|
- if (notifier.onEnter) _NewEventButton(onClick: onCreate),
|
|
|
|
- const Spacer(),
|
|
|
|
- badge,
|
|
|
|
- ],
|
|
|
|
|
|
+
|
|
|
|
+ return Padding(
|
|
|
|
+ padding: const EdgeInsets.symmetric(horizontal: 8.0),
|
|
|
|
+ child: Row(
|
|
|
|
+ children: [
|
|
|
|
+ if (notifier.onEnter) _NewEventButton(onClick: onCreate),
|
|
|
|
+ const Spacer(),
|
|
|
|
+ badge,
|
|
|
|
+ ],
|
|
|
|
+ ),
|
|
);
|
|
);
|
|
},
|
|
},
|
|
);
|
|
);
|