From 2e7a97c8a2e3e7e1d7dce3a4e5ebc8877ab6ba31 Mon Sep 17 00:00:00 2001 From: Richard Shiue <71320345+richardshiue@users.noreply.github.com> Date: Fri, 26 Jan 2024 22:23:47 +0800 Subject: [PATCH] chore: enable timestamp field on mobile (#4506) --- .../field/mobile_field_type_grid.dart | 60 +++++---- .../mobile_field_type_option_editor.dart | 119 +++++++++++++++--- .../mobile_grid_timestamp_cell.dart | 13 +- .../lib/util/field_type_extension.dart | 4 + frontend/resources/translations/en.json | 6 +- 5 files changed, 151 insertions(+), 51 deletions(-) diff --git a/frontend/appflowy_flutter/lib/mobile/presentation/database/field/mobile_field_type_grid.dart b/frontend/appflowy_flutter/lib/mobile/presentation/database/field/mobile_field_type_grid.dart index ad9fe21302..f2b2600092 100644 --- a/frontend/appflowy_flutter/lib/mobile/presentation/database/field/mobile_field_type_grid.dart +++ b/frontend/appflowy_flutter/lib/mobile/presentation/database/field/mobile_field_type_grid.dart @@ -19,6 +19,8 @@ const _supportedFieldTypes = [ FieldType.DateTime, FieldType.Checkbox, FieldType.Checklist, + FieldType.LastEditedTime, + FieldType.CreatedTime, ]; class FieldOptions extends StatelessWidget { @@ -35,29 +37,28 @@ class FieldOptions extends StatelessWidget { @override Widget build(BuildContext context) { - return Column( - children: [ - _FieldHeader(mode: mode), - const VSpace(12.0), - Expanded( - child: SingleChildScrollView( - controller: scrollController, - child: _GridView( - crossAxisCount: 3, - mainAxisSpacing: 28, - itemWidth: 82, - children: _supportedFieldTypes - .map( - (e) => _Field( - type: e, - onTap: () => onSelectFieldType(e), - ), - ) - .toList(), - ), + return SingleChildScrollView( + controller: scrollController, + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + _FieldHeader(mode: mode), + const VSpace(12.0), + _GridView( + crossAxisCount: 3, + mainAxisSpacing: 4, + itemSize: const Size(82, 140), + children: _supportedFieldTypes + .map( + (e) => _Field( + type: e, + onTap: () => onSelectFieldType(e), + ), + ) + .toList(), ), - ), - ], + ], + ), ); } } @@ -119,6 +120,9 @@ class _Field extends StatelessWidget { FlowyText( type.i18n, fontSize: 15.0, + textAlign: TextAlign.center, + maxLines: 2, + overflow: TextOverflow.ellipsis, ), ], ), @@ -131,13 +135,13 @@ class _GridView extends StatelessWidget { required this.children, required this.crossAxisCount, required this.mainAxisSpacing, - required this.itemWidth, + required this.itemSize, }); final List children; final int crossAxisCount; final double mainAxisSpacing; - final double itemWidth; + final Size itemSize; @override Widget build(BuildContext context) { @@ -148,9 +152,15 @@ class _GridView extends StatelessWidget { padding: EdgeInsets.only(bottom: mainAxisSpacing), child: Row( mainAxisAlignment: MainAxisAlignment.spaceAround, + crossAxisAlignment: CrossAxisAlignment.start, children: [ for (var j = 0; j < crossAxisCount; j++) - i + j < children.length ? children[i + j] : HSpace(itemWidth), + i + j < children.length + ? ConstrainedBox( + constraints: BoxConstraints.tight(itemSize), + child: children[i + j], + ) + : SizedBox.fromSize(size: itemSize), ], ), ), diff --git a/frontend/appflowy_flutter/lib/mobile/presentation/database/field/mobile_field_type_option_editor.dart b/frontend/appflowy_flutter/lib/mobile/presentation/database/field/mobile_field_type_option_editor.dart index 079f972afa..215620c0e0 100644 --- a/frontend/appflowy_flutter/lib/mobile/presentation/database/field/mobile_field_type_option_editor.dart +++ b/frontend/appflowy_flutter/lib/mobile/presentation/database/field/mobile_field_type_option_editor.dart @@ -33,8 +33,9 @@ class FieldOptionValues { FieldOptionValues({ required this.type, required this.name, - this.dateFormate, + this.dateFormat, this.timeFormat, + this.includeTime, this.numberFormat, this.selectOption = const [], }); @@ -48,12 +49,26 @@ class FieldOptionValues { numberFormat: fieldType == FieldType.Number ? NumberTypeOptionPB.fromBuffer(buffer).format : null, - dateFormate: fieldType == FieldType.DateTime - ? DateTypeOptionPB.fromBuffer(buffer).dateFormat - : null, - timeFormat: fieldType == FieldType.DateTime - ? DateTypeOptionPB.fromBuffer(buffer).timeFormat - : null, + dateFormat: switch (fieldType) { + FieldType.DateTime => DateTypeOptionPB.fromBuffer(buffer).dateFormat, + FieldType.LastEditedTime || + FieldType.CreatedTime => + TimestampTypeOptionPB.fromBuffer(buffer).dateFormat, + _ => null + }, + timeFormat: switch (fieldType) { + FieldType.DateTime => DateTypeOptionPB.fromBuffer(buffer).timeFormat, + FieldType.LastEditedTime || + FieldType.CreatedTime => + TimestampTypeOptionPB.fromBuffer(buffer).timeFormat, + _ => null + }, + includeTime: switch (fieldType) { + FieldType.LastEditedTime || + FieldType.CreatedTime => + TimestampTypeOptionPB.fromBuffer(buffer).includeTime, + _ => null + }, selectOption: switch (fieldType) { FieldType.SingleSelect => SingleSelectTypeOptionPB.fromBuffer(buffer).options, @@ -67,11 +82,17 @@ class FieldOptionValues { FieldType type; String name; - // FieldType.Date - DateFormatPB? dateFormate; + // FieldType.DateTime + // FieldType.LastEditedTime + // FieldType.CreatedTime + DateFormatPB? dateFormat; TimeFormatPB? timeFormat; - // FieldType.Num + // FieldType.LastEditedTime + // FieldType.CreatedTime + bool? includeTime; + + // FieldType.Number NumberFormatPB? numberFormat; // FieldType.Select @@ -103,7 +124,7 @@ class FieldOptionValues { ).writeToBuffer(); case FieldType.DateTime: return DateTypeOptionPB( - dateFormat: dateFormate, + dateFormat: dateFormat, timeFormat: timeFormat, ).writeToBuffer(); case FieldType.SingleSelect: @@ -116,6 +137,13 @@ class FieldOptionValues { ).writeToBuffer(); case FieldType.Checklist: return ChecklistTypeOptionPB().writeToBuffer(); + case FieldType.LastEditedTime: + case FieldType.CreatedTime: + return TimestampTypeOptionPB( + dateFormat: dateFormat, + timeFormat: timeFormat, + includeTime: includeTime, + ).writeToBuffer(); default: throw UnimplementedError(); } @@ -237,9 +265,9 @@ class _FieldOptionEditorState extends State { case FieldType.DateTime: return [ _DateOption( - selectedFormat: values.dateFormate ?? DateFormatPB.Local, + selectedFormat: values.dateFormat ?? DateFormatPB.Local, onSelected: (format) => _updateOptionValues( - dateFormate: format, + dateFormat: format, ), ), const _Divider(), @@ -250,6 +278,30 @@ class _FieldOptionEditorState extends State { ), ), ]; + case FieldType.LastEditedTime: + case FieldType.CreatedTime: + return [ + _DateOption( + selectedFormat: values.dateFormat ?? DateFormatPB.Local, + onSelected: (format) => _updateOptionValues( + dateFormat: format, + ), + ), + const _Divider(), + _TimeOption( + selectedFormat: values.timeFormat ?? TimeFormatPB.TwelveHour, + onSelected: (format) => _updateOptionValues( + timeFormat: format, + ), + ), + const _Divider(), + _IncludeTimeOption( + includeTime: values.includeTime ?? true, + onToggle: (includeTime) => _updateOptionValues( + includeTime: includeTime, + ), + ), + ]; case FieldType.SingleSelect: case FieldType.MultiSelect: return [ @@ -321,8 +373,9 @@ class _FieldOptionEditorState extends State { void _updateOptionValues({ FieldType? type, String? name, - DateFormatPB? dateFormate, + DateFormatPB? dateFormat, TimeFormatPB? timeFormat, + bool? includeTime, NumberFormatPB? numberFormat, List? selectOption, }) { @@ -332,12 +385,15 @@ class _FieldOptionEditorState extends State { if (name != null) { values.name = name; } - if (dateFormate != null) { - values.dateFormate = dateFormate; + if (dateFormat != null) { + values.dateFormat = dateFormat; } if (timeFormat != null) { values.timeFormat = timeFormat; } + if (includeTime != null) { + values.includeTime = includeTime; + } if (numberFormat != null) { values.numberFormat = numberFormat; } @@ -525,6 +581,37 @@ class _TimeOptionState extends State<_TimeOption> { } } +class _IncludeTimeOption extends StatefulWidget { + const _IncludeTimeOption({ + required this.includeTime, + required this.onToggle, + }); + + final bool includeTime; + final void Function(bool includeTime) onToggle; + + @override + State<_IncludeTimeOption> createState() => _IncludeTimeOptionState(); +} + +class _IncludeTimeOptionState extends State<_IncludeTimeOption> { + late bool includeTime = widget.includeTime; + + @override + Widget build(BuildContext context) { + return FlowyOptionTile.toggle( + text: LocaleKeys.grid_field_includeTime.tr(), + isSelected: includeTime, + onValueChanged: (value) { + widget.onToggle(value); + setState(() { + includeTime = value; + }); + }, + ); + } +} + class _NumberOption extends StatelessWidget { const _NumberOption({ required this.selectedFormat, diff --git a/frontend/appflowy_flutter/lib/plugins/database/widgets/cell/mobile_grid/mobile_grid_timestamp_cell.dart b/frontend/appflowy_flutter/lib/plugins/database/widgets/cell/mobile_grid/mobile_grid_timestamp_cell.dart index 92484697a5..4640447a04 100644 --- a/frontend/appflowy_flutter/lib/plugins/database/widgets/cell/mobile_grid/mobile_grid_timestamp_cell.dart +++ b/frontend/appflowy_flutter/lib/plugins/database/widgets/cell/mobile_grid/mobile_grid_timestamp_cell.dart @@ -13,14 +13,13 @@ class MobileGridTimestampCellSkin extends IEditableTimestampCellSkin { TimestampCellBloc bloc, TimestampCellState state, ) { - return Align( + return Container( alignment: Alignment.centerLeft, - child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 12), - child: FlowyText( - state.dateStr, - fontSize: 15, - ), + padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 12), + child: FlowyText( + state.dateStr, + fontSize: 15, + overflow: TextOverflow.ellipsis, ), ); } diff --git a/frontend/appflowy_flutter/lib/util/field_type_extension.dart b/frontend/appflowy_flutter/lib/util/field_type_extension.dart index 5c8c88b5af..c929ecaa50 100644 --- a/frontend/appflowy_flutter/lib/util/field_type_extension.dart +++ b/frontend/appflowy_flutter/lib/util/field_type_extension.dart @@ -30,6 +30,8 @@ extension FieldTypeExtension on FieldType { FieldType.Checkbox => FlowySvgs.field_option_checkbox_xl, FieldType.Checklist => FlowySvgs.field_option_checklist_xl, FieldType.URL => FlowySvgs.field_option_url_xl, + FieldType.LastEditedTime => FlowySvgs.field_option_date_xl, + FieldType.CreatedTime => FlowySvgs.field_option_date_xl, _ => throw UnimplementedError(), }; @@ -42,6 +44,8 @@ extension FieldTypeExtension on FieldType { FieldType.Checkbox => FlowySvgs.field_option_checkbox_s, FieldType.URL => FlowySvgs.field_option_url_s, FieldType.Checklist => FlowySvgs.checklist_s, + FieldType.LastEditedTime => FlowySvgs.field_option_date_s, + FieldType.CreatedTime => FlowySvgs.field_option_date_s, _ => throw UnimplementedError(), }; } diff --git a/frontend/resources/translations/en.json b/frontend/resources/translations/en.json index 135278d400..b5b96c46c0 100644 --- a/frontend/resources/translations/en.json +++ b/frontend/resources/translations/en.json @@ -544,8 +544,8 @@ "textFieldName": "Text", "checkboxFieldName": "Checkbox", "dateFieldName": "Date", - "updatedAtFieldName": "Last modified time", - "createdAtFieldName": "Created time", + "updatedAtFieldName": "Last modified", + "createdAtFieldName": "Created at", "numberFieldName": "Numbers", "singleSelectFieldName": "Select", "multiSelectFieldName": "Multiselect", @@ -1231,4 +1231,4 @@ "addField": "Add field", "userIcon": "User icon" } -} +} \ No newline at end of file