fix: sort the events in each day cell by time (#2412)

* fix: sort the events in each day cell by time

* fix: reorder issue in calendar day

---------

Co-authored-by: nathan <nathan@appflowy.io>
This commit is contained in:
Richard Shiue
2023-05-02 13:44:52 +08:00
committed by GitHub
parent 545e57448a
commit d5b70c842b
4 changed files with 112 additions and 121 deletions

View File

@ -77,7 +77,6 @@ class CalendarBloc extends Bloc<CalendarEvent, CalendarState> {
emit( emit(
state.copyWith( state.copyWith(
allEvents: allEvents, allEvents: allEvents,
updateEvent: eventData,
), ),
); );
}, },
@ -380,7 +379,6 @@ class CalendarState with _$CalendarState {
CalendarEventData<CalendarDayEvent>? createdEvent, CalendarEventData<CalendarDayEvent>? createdEvent,
CalendarEventData<CalendarDayEvent>? newEvent, CalendarEventData<CalendarDayEvent>? newEvent,
required List<String> deleteEventIds, required List<String> deleteEventIds,
CalendarEventData<CalendarDayEvent>? updateEvent,
required Option<CalendarLayoutSettingsPB> settings, required Option<CalendarLayoutSettingsPB> settings,
required DatabaseLoadingState loadingState, required DatabaseLoadingState loadingState,
required Option<FlowyError> noneOrError, required Option<FlowyError> noneOrError,

View File

@ -48,14 +48,13 @@ class CalendarDayCard extends StatelessWidget {
return ChangeNotifierProvider( return ChangeNotifierProvider(
create: (_) => _CardEnterNotifier(), create: (_) => _CardEnterNotifier(),
builder: (context, child) { builder: (context, child) {
List<GestureDetector> cards = _buildCards(context);
Widget? multipleCards; Widget? multipleCards;
if (cards.isNotEmpty) { if (events.isNotEmpty) {
multipleCards = Flexible( multipleCards = Flexible(
child: ListView.separated( child: ListView.separated(
itemBuilder: (BuildContext context, int index) => cards[index], itemBuilder: (BuildContext context, int index) =>
itemCount: cards.length, _buildCard(context, events[index]),
itemCount: events.length,
padding: const EdgeInsets.fromLTRB(8.0, 0, 8.0, 8.0), padding: const EdgeInsets.fromLTRB(8.0, 0, 8.0, 8.0),
separatorBuilder: (BuildContext context, int index) => separatorBuilder: (BuildContext context, int index) =>
VSpace(GridSize.typeOptionSeparatorHeight), VSpace(GridSize.typeOptionSeparatorHeight),
@ -97,114 +96,111 @@ class CalendarDayCard extends StatelessWidget {
); );
} }
List<GestureDetector> _buildCards(BuildContext context) { GestureDetector _buildCard(BuildContext context, CalendarDayEvent event) {
final children = events.map((CalendarDayEvent event) { final cellBuilder = CardCellBuilder<String>(_rowCache.cellCache);
final cellBuilder = CardCellBuilder<String>(_rowCache.cellCache); final rowInfo = _rowCache.getRow(event.eventId);
final rowInfo = _rowCache.getRow(event.eventId);
final renderHook = RowCardRenderHook<String>(); final renderHook = RowCardRenderHook<String>();
renderHook.addTextFieldHook((cellData, primaryFieldId, _) { renderHook.addTextFieldHook((cellData, primaryFieldId, _) {
if (cellData.isEmpty) { if (cellData.isEmpty) {
return const SizedBox(); return const SizedBox();
} }
return Align( return Align(
alignment: Alignment.centerLeft, alignment: Alignment.centerLeft,
child: FlowyText.medium( child: FlowyText.medium(
cellData, cellData,
textAlign: TextAlign.left, textAlign: TextAlign.left,
fontSize: 11, fontSize: 11,
maxLines: null, // Enable multiple lines 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( renderHook.addDateFieldHook((cellData, cardData, _) {
onTap: () => _showRowDetailPage(event, context), return Align(
child: MouseRegion( alignment: Alignment.centerLeft,
cursor: SystemMouseCursors.click, child: Padding(
child: Container( padding: const EdgeInsets.symmetric(vertical: 2),
padding: const EdgeInsets.symmetric(horizontal: 2), child: Row(
decoration: BoxDecoration( children: [
border: Border.fromBorderSide( FlowyText.regular(
BorderSide( cellData.date,
color: Theme.of(context).dividerColor, fontSize: 10,
width: 1.5, color: Theme.of(context).hintColor,
),
), ),
borderRadius: Corners.s6Border, const Spacer(),
), FlowyText.regular(
child: card, cellData.time,
fontSize: 10,
color: Theme.of(context).hintColor,
)
],
), ),
), ),
); );
}).toList(); });
return children;
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: MouseRegion(
cursor: SystemMouseCursors.click,
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,
),
),
);
} }
void _showRowDetailPage(CalendarDayEvent event, BuildContext context) { void _showRowDetailPage(CalendarDayEvent event, BuildContext context) {

View File

@ -72,19 +72,6 @@ class _CalendarPageState extends State<CalendarPage> {
); );
}, },
), ),
BlocListener<CalendarBloc, CalendarState>(
listenWhen: (p, c) => p.updateEvent != c.updateEvent,
listener: (context, state) {
if (state.updateEvent != null) {
_eventController.removeWhere(
(element) =>
state.updateEvent!.event!.eventId ==
element.event!.eventId,
);
_eventController.add(state.updateEvent!);
}
},
),
BlocListener<CalendarBloc, CalendarState>( BlocListener<CalendarBloc, CalendarState>(
listenWhen: (p, c) => p.createdEvent != c.createdEvent, listenWhen: (p, c) => p.createdEvent != c.createdEvent,
listener: (context, state) { listener: (context, state) {
@ -196,7 +183,12 @@ class _CalendarPageState extends State<CalendarPage> {
isInMonth, isInMonth,
) { ) {
final events = calenderEvents.map((value) => value.event!).toList(); final events = calenderEvents.map((value) => value.event!).toList();
// Sort the events by timestamp. Because the database view is not
// reserving the order of the events. Reserving the order of the rows/events
// is implemnted in the develop branch(WIP). Will be replaced with that.
events.sort(
(a, b) => a.event.timestamp.compareTo(b.event.timestamp),
);
return CalendarDayCard( return CalendarDayCard(
viewId: widget.view.id, viewId: widget.view.id,
isToday: isToday, isToday: isToday,

View File

@ -12,6 +12,9 @@ typedef CellRenderHook<C, CustomCardData> = Widget? Function(
); );
typedef RenderHookByFieldType<C> = Map<FieldType, CellRenderHook<dynamic, C>>; typedef RenderHookByFieldType<C> = Map<FieldType, CellRenderHook<dynamic, C>>;
/// The [RowCardRenderHook] is used to customize the rendering of the
/// card cell. Each cell has itw own field type. So the [renderHook]
/// is a map of [FieldType] to [CellRenderHook].
class RowCardRenderHook<CustomCardData> { class RowCardRenderHook<CustomCardData> {
final RenderHookByFieldType<CustomCardData> renderHook = {}; final RenderHookByFieldType<CustomCardData> renderHook = {};
RowCardRenderHook(); RowCardRenderHook();
@ -25,12 +28,14 @@ class RowCardRenderHook<CustomCardData> {
renderHook[FieldType.MultiSelect] = hookFn; renderHook[FieldType.MultiSelect] = hookFn;
} }
/// Add a render hook for the [FieldType.RichText]
void addTextFieldHook( void addTextFieldHook(
CellRenderHook<String, CustomCardData?> hook, CellRenderHook<String, CustomCardData?> hook,
) { ) {
renderHook[FieldType.RichText] = _typeSafeHook<String>(hook); renderHook[FieldType.RichText] = _typeSafeHook<String>(hook);
} }
/// Add a render hook for the [FieldType.Date]
void addDateFieldHook( void addDateFieldHook(
CellRenderHook<DateCellDataPB, CustomCardData?> hook, CellRenderHook<DateCellDataPB, CustomCardData?> hook,
) { ) {