fix: use empty event title and add placeholder (#3234)

* fix: use empty event title and add placeholder

* chore: update frontend/appflowy_flutter/lib/plugins/database_view/calendar/presentation/calendar_event_card.dart

Co-authored-by: Mathias Mogensen <42929161+Xazin@users.noreply.github.com>

* chore: remove unnecessary visible for testing

* chore: apply suggestions from code review

Co-authored-by: Mathias Mogensen <42929161+Xazin@users.noreply.github.com>

* fix: typo on suggested changes

---------

Co-authored-by: Mathias Mogensen <42929161+Xazin@users.noreply.github.com>
This commit is contained in:
Richard Shiue 2023-08-22 22:30:41 +08:00 committed by GitHub
parent 7fa15615df
commit 72363921b0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 207 additions and 194 deletions

View File

@ -4,6 +4,7 @@ import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/plugins/database_view/board/presentation/board_page.dart';
import 'package:appflowy/plugins/database_view/calendar/application/calendar_bloc.dart';
import 'package:appflowy/plugins/database_view/calendar/presentation/calendar_day.dart';
import 'package:appflowy/plugins/database_view/calendar/presentation/calendar_event_card.dart';
import 'package:appflowy/plugins/database_view/calendar/presentation/calendar_page.dart';
import 'package:appflowy/plugins/database_view/calendar/presentation/toolbar/calendar_layout_setting.dart';
import 'package:appflowy/plugins/database_view/grid/presentation/grid_page.dart';

View File

@ -19,6 +19,8 @@ class FieldInfo with _$FieldInfo {
String get name => field.name;
bool get isPrimary => field.isPrimary;
factory FieldInfo.initial(FieldPB field) => FieldInfo(
field: field,
hasFilter: false,

View File

@ -60,8 +60,8 @@ class CalendarBloc extends Bloc<CalendarEvent, CalendarState> {
),
);
},
createEvent: (DateTime date, String title) async {
await _createEvent(date, title);
createEvent: (DateTime date) async {
await _createEvent(date);
},
moveEvent: (CalendarDayEvent event, DateTime date) async {
await _moveEvent(event, date);
@ -120,18 +120,6 @@ class CalendarBloc extends Bloc<CalendarEvent, CalendarState> {
}
}
FieldInfo? _getTitleFieldInfo() {
final fieldInfos = databaseController.fieldController.fieldInfos;
final index = fieldInfos.indexWhere(
(element) => element.field.isPrimary,
);
if (index != -1) {
return fieldInfos[index];
} else {
return null;
}
}
Future<void> _openDatabase(Emitter<CalendarState> emit) async {
final result = await databaseController.open();
result.fold(
@ -147,19 +135,17 @@ class CalendarBloc extends Bloc<CalendarEvent, CalendarState> {
);
}
Future<void> _createEvent(DateTime date, String title) async {
Future<void> _createEvent(DateTime date) async {
return state.settings.fold(
() {
Log.warn('Calendar settings not found');
},
(settings) async {
final dateField = _getCalendarFieldInfo(settings.fieldId);
final titleField = _getTitleFieldInfo();
if (dateField != null && titleField != null) {
if (dateField != null) {
final newRow = await databaseController.createRow(
withCells: (builder) {
builder.insertDate(dateField, date);
builder.insertText(titleField, title);
},
).then(
(result) => result.fold(
@ -402,8 +388,7 @@ class CalendarEvent with _$CalendarEvent {
_DidDeleteEvents;
// Called when creating a new event
const factory CalendarEvent.createEvent(DateTime date, String title) =
_CreateEvent;
const factory CalendarEvent.createEvent(DateTime date) = _CreateEvent;
// Called when moving an event
const factory CalendarEvent.moveEvent(CalendarDayEvent event, DateTime date) =

View File

@ -1,25 +1,17 @@
import 'package:appflowy/generated/flowy_svgs.g.dart';
import 'package:appflowy/plugins/database_view/application/row/row_cache.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/cells/card_cell.dart';
import 'package:appflowy/plugins/database_view/widgets/card/cells/number_card_cell.dart';
import 'package:appflowy/plugins/database_view/widgets/card/cells/url_card_cell.dart';
import 'package:appflowy_backend/protobuf/flowy-database2/field_entities.pbenum.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';
import 'package:flowy_infra_ui/style_widget/hover.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:table_calendar/table_calendar.dart';
import '../../grid/presentation/layout/sizes.dart';
import '../../widgets/row/cells/select_option_cell/extension.dart';
import '../application/calendar_bloc.dart';
import 'calendar_page.dart';
import 'calendar_event_card.dart';
class CalendarDayCard extends StatelessWidget {
final String viewId;
@ -277,166 +269,6 @@ class _EventList extends StatelessWidget {
}
}
@visibleForTesting
class EventCard extends StatelessWidget {
final CalendarDayEvent event;
final String viewId;
final RowCache rowCache;
final BoxConstraints constraints;
const EventCard({
required this.event,
required this.viewId,
required this.rowCache,
required this.constraints,
Key? key,
}) : super(key: key);
@override
Widget build(BuildContext context) {
final rowInfo = rowCache.getRow(event.eventId);
final styles = <FieldType, CardCellStyle>{
FieldType.Number: NumberCardCellStyle(10),
FieldType.URL: URLCardCellStyle(10),
};
final cellBuilder = CardCellBuilder<String>(
rowCache.cellCache,
styles: styles,
);
final renderHook = _calendarEventCardRenderHook(context);
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),
rowMeta: rowInfo!.rowMeta,
viewId: viewId,
rowCache: rowCache,
cardData: event.dateFieldId,
isEditing: false,
cellBuilder: cellBuilder,
openCard: (context) => showEventDetails(
context: context,
event: event.event,
viewId: viewId,
rowCache: rowCache,
),
styleConfiguration: RowCardStyleConfiguration(
showAccessory: false,
cellPadding: EdgeInsets.zero,
hoverStyle: HoverStyle(
hoverColor: AFThemeExtension.of(context).lightGreyHover,
foregroundColorOnHover: Theme.of(context).colorScheme.onBackground,
),
),
renderHook: renderHook,
onStartEditing: () {},
onEndEditing: () {},
);
final decoration = BoxDecoration(
border: Border.fromBorderSide(
BorderSide(color: Theme.of(context).dividerColor),
),
borderRadius: Corners.s6Border,
);
return Draggable<CalendarDayEvent>(
data: event,
feedback: ConstrainedBox(
constraints: BoxConstraints(
maxWidth: constraints.maxWidth - 16.0,
),
child: Container(
decoration: decoration.copyWith(
color: AFThemeExtension.of(context).lightGreyHover,
),
child: card,
),
),
child: Container(
decoration: decoration,
child: card,
),
);
}
RowCardRenderHook<String> _calendarEventCardRenderHook(BuildContext context) {
final renderHook = RowCardRenderHook<String>();
renderHook.addTextCellHook((cellData, primaryFieldId, _) {
if (cellData.isEmpty) {
return const SizedBox.shrink();
}
return Align(
alignment: Alignment.centerLeft,
child: FlowyText.medium(
cellData,
textAlign: TextAlign.left,
fontSize: 11,
maxLines: null, // Enable multiple lines
),
);
});
renderHook.addDateCellHook((cellData, cardData, _) {
return Align(
alignment: Alignment.centerLeft,
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 2),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Flexible(
flex: 3,
child: FlowyText.regular(
cellData.date,
fontSize: 10,
color: Theme.of(context).hintColor,
overflow: TextOverflow.ellipsis,
),
),
if (cellData.includeTime)
Flexible(
child: FlowyText.regular(
cellData.time,
fontSize: 10,
color: Theme.of(context).hintColor,
overflow: TextOverflow.ellipsis,
),
)
],
),
),
);
});
renderHook.addSelectOptionHook((selectedOptions, cardData, _) {
if (selectedOptions.isEmpty) {
return const SizedBox.shrink();
}
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),
),
),
);
});
return renderHook;
}
}
class _CardEnterNotifier extends ChangeNotifier {
bool _onEnter = false;

View File

@ -0,0 +1,195 @@
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/widgets/card/bloc/text_card_cell_bloc.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/cells/card_cell.dart';
import 'package:appflowy/plugins/database_view/widgets/card/cells/number_card_cell.dart';
import 'package:appflowy/plugins/database_view/widgets/card/cells/url_card_cell.dart';
import 'package:appflowy/plugins/database_view/widgets/row/cells/select_option_cell/extension.dart';
import 'package:appflowy_backend/protobuf/flowy-database2/field_entities.pb.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';
import 'package:flowy_infra_ui/style_widget/hover.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import '../application/calendar_bloc.dart';
import 'calendar_page.dart';
class EventCard extends StatelessWidget {
final CalendarDayEvent event;
final String viewId;
final RowCache rowCache;
final BoxConstraints constraints;
const EventCard({
required this.event,
required this.viewId,
required this.rowCache,
required this.constraints,
super.key,
});
@override
Widget build(BuildContext context) {
final rowInfo = rowCache.getRow(event.eventId);
final styles = <FieldType, CardCellStyle>{
FieldType.Number: NumberCardCellStyle(10),
FieldType.URL: URLCardCellStyle(10),
};
final cellBuilder = CardCellBuilder<CalendarDayEvent>(
rowCache.cellCache,
styles: styles,
);
final renderHook = _calendarEventCardRenderHook(context);
final card = RowCard<CalendarDayEvent>(
// Add the key here to make sure the card is rebuilt when the cells
// in this row are updated.
key: ValueKey(event.eventId),
rowMeta: rowInfo!.rowMeta,
viewId: viewId,
rowCache: rowCache,
cardData: event,
isEditing: false,
cellBuilder: cellBuilder,
openCard: (context) => showEventDetails(
context: context,
event: event.event,
viewId: viewId,
rowCache: rowCache,
),
styleConfiguration: RowCardStyleConfiguration(
showAccessory: false,
cellPadding: EdgeInsets.zero,
hoverStyle: HoverStyle(
hoverColor: AFThemeExtension.of(context).lightGreyHover,
foregroundColorOnHover: Theme.of(context).colorScheme.onBackground,
),
),
renderHook: renderHook,
onStartEditing: () {},
onEndEditing: () {},
);
final decoration = BoxDecoration(
border: Border.fromBorderSide(
BorderSide(color: Theme.of(context).dividerColor),
),
borderRadius: Corners.s6Border,
);
return Draggable<CalendarDayEvent>(
data: event,
feedback: ConstrainedBox(
constraints: BoxConstraints(
maxWidth: constraints.maxWidth - 16.0,
),
child: DecoratedBox(
decoration: decoration.copyWith(
color: AFThemeExtension.of(context).lightGreyHover,
),
child: card,
),
),
child: DecoratedBox(
decoration: decoration,
child: card,
),
);
}
RowCardRenderHook<CalendarDayEvent> _calendarEventCardRenderHook(
BuildContext context,
) {
final renderHook = RowCardRenderHook<CalendarDayEvent>();
renderHook.addTextCellHook((cellData, eventData, _) {
return BlocBuilder<TextCardCellBloc, TextCardCellState>(
builder: (context, state) {
final isTitle = context
.read<TextCardCellBloc>()
.cellController
.fieldInfo
.isPrimary;
final text = isTitle && cellData.isEmpty
? LocaleKeys.grid_row_titlePlaceholder.tr()
: cellData;
if (text.isEmpty) {
return const SizedBox.shrink();
}
return Align(
alignment: Alignment.centerLeft,
child: FlowyText.medium(
text,
textAlign: TextAlign.left,
fontSize: 11,
maxLines: null, // Enable multiple lines
),
);
},
);
});
renderHook.addDateCellHook((cellData, cardData, _) {
return Align(
alignment: Alignment.centerLeft,
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 2),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Flexible(
flex: 3,
child: FlowyText.regular(
cellData.date,
fontSize: 10,
color: Theme.of(context).hintColor,
overflow: TextOverflow.ellipsis,
),
),
if (cellData.includeTime)
Flexible(
child: FlowyText.regular(
cellData.time,
fontSize: 10,
color: Theme.of(context).hintColor,
overflow: TextOverflow.ellipsis,
),
)
],
),
),
);
});
renderHook.addSelectOptionHook((selectedOptions, cardData, _) {
if (selectedOptions.isEmpty) {
return const SizedBox.shrink();
}
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),
),
),
);
});
return renderHook;
}
}

View File

@ -285,10 +285,7 @@ class _CalendarPageState extends State<CalendarPage> {
rowCache: _calendarBloc.rowCache,
onCreateEvent: (date) {
_calendarBloc.add(
CalendarEvent.createEvent(
date,
LocaleKeys.calendar_defaultNewCalendarTitle.tr(),
),
CalendarEvent.createEvent(date),
);
},
);

View File

@ -91,7 +91,7 @@ class _RowDetailPageState extends State<RowDetailPage> {
if (fieldInfo != null) {
final style = GridTextCellStyle(
placeholder: LocaleKeys.grid_row_textPlaceholder.tr(),
placeholder: LocaleKeys.grid_row_titlePlaceholder.tr(),
textStyle: Theme.of(context).textTheme.titleLarge,
showEmoji: false,
autofocus: true,

View File

@ -424,6 +424,7 @@
"row": {
"duplicate": "Duplicate",
"delete": "Delete",
"titlePlaceholder": "Untitled",
"textPlaceholder": "Empty",
"copyProperty": "Copied property to clipboard",
"count": "Count",