mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
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:
parent
7fa15615df
commit
72363921b0
@ -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';
|
||||
|
@ -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,
|
||||
|
@ -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) =
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
@ -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),
|
||||
);
|
||||
},
|
||||
);
|
||||
|
@ -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,
|
||||
|
@ -424,6 +424,7 @@
|
||||
"row": {
|
||||
"duplicate": "Duplicate",
|
||||
"delete": "Delete",
|
||||
"titlePlaceholder": "Untitled",
|
||||
"textPlaceholder": "Empty",
|
||||
"copyProperty": "Copied property to clipboard",
|
||||
"count": "Count",
|
||||
|
Loading…
Reference in New Issue
Block a user