diff --git a/frontend/app_flowy/lib/plugins/board/application/board_bloc.dart b/frontend/app_flowy/lib/plugins/board/application/board_bloc.dart index 26dd15038a..11f4cf6910 100644 --- a/frontend/app_flowy/lib/plugins/board/application/board_bloc.dart +++ b/frontend/app_flowy/lib/plugins/board/application/board_bloc.dart @@ -1,4 +1,6 @@ import 'dart:async'; +import 'dart:collection'; + import 'package:app_flowy/plugins/grid/application/block/block_cache.dart'; import 'package:app_flowy/plugins/grid/application/field/field_controller.dart'; import 'package:app_flowy/plugins/grid/application/row/row_cache.dart'; @@ -12,7 +14,6 @@ import 'package:flowy_sdk/protobuf/flowy-folder/view.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-grid/protobuf.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; -import 'dart:collection'; import 'board_data_controller.dart'; import 'group_controller.dart'; @@ -164,12 +165,17 @@ class BoardBloc extends Bloc { boardController.clear(); // - List columns = groups.map((group) { + List columns = groups + .where((group) => fieldController.getField(group.fieldId) != null) + .map((group) { return AFBoardColumnData( id: group.groupId, name: group.desc, items: _buildRows(group), - customData: group, + customData: BoardCustomData( + group: group, + fieldContext: fieldController.getField(group.fieldId)!, + ), ); }).toList(); boardController.addColumns(columns); @@ -177,6 +183,7 @@ class BoardBloc extends Bloc { for (final group in groups) { final delegate = GroupControllerDelegateImpl( controller: boardController, + fieldController: fieldController, onNewColumnItem: (groupId, row, index) { add(BoardEvent.didCreateRow(groupId, row, index)); }, @@ -238,10 +245,8 @@ class BoardBloc extends Bloc { List _buildRows(GroupPB group) { final items = group.rows.map((row) { - return BoardColumnItem( - row: row, - fieldId: group.fieldId, - ); + final fieldContext = fieldController.getField(group.fieldId); + return BoardColumnItem(row: row, fieldContext: fieldContext!); }).toList(); return [...items]; @@ -332,15 +337,11 @@ class GridFieldEquatable extends Equatable { class BoardColumnItem extends AFColumnItem { final RowPB row; - - final String fieldId; - - final bool requestFocus; + final GridFieldContext fieldContext; BoardColumnItem({ required this.row, - required this.fieldId, - this.requestFocus = false, + required this.fieldContext, }); @override @@ -348,24 +349,29 @@ class BoardColumnItem extends AFColumnItem { } class GroupControllerDelegateImpl extends GroupControllerDelegate { + final GridFieldController fieldController; final AFBoardDataController controller; final void Function(String, RowPB, int?) onNewColumnItem; GroupControllerDelegateImpl({ required this.controller, + required this.fieldController, required this.onNewColumnItem, }); @override void insertRow(GroupPB group, RowPB row, int? index) { + final fieldContext = fieldController.getField(group.fieldId); + if (fieldContext == null) { + Log.warn("FieldContext should not be null"); + return; + } + if (index != null) { - final item = BoardColumnItem(row: row, fieldId: group.fieldId); + final item = BoardColumnItem(row: row, fieldContext: fieldContext); controller.insertColumnItem(group.groupId, index, item); } else { - final item = BoardColumnItem( - row: row, - fieldId: group.fieldId, - ); + final item = BoardColumnItem(row: row, fieldContext: fieldContext); controller.addColumnItem(group.groupId, item); } } @@ -377,22 +383,25 @@ class GroupControllerDelegateImpl extends GroupControllerDelegate { @override void updateRow(GroupPB group, RowPB row) { + final fieldContext = fieldController.getField(group.fieldId); + if (fieldContext == null) { + Log.warn("FieldContext should not be null"); + return; + } controller.updateColumnItem( group.groupId, - BoardColumnItem( - row: row, - fieldId: group.fieldId, - ), + BoardColumnItem(row: row, fieldContext: fieldContext), ); } @override void addNewRow(GroupPB group, RowPB row, int? index) { - final item = BoardColumnItem( - row: row, - fieldId: group.fieldId, - requestFocus: true, - ); + final fieldContext = fieldController.getField(group.fieldId); + if (fieldContext == null) { + Log.warn("FieldContext should not be null"); + return; + } + final item = BoardColumnItem(row: row, fieldContext: fieldContext); if (index != null) { controller.insertColumnItem(group.groupId, index, item); @@ -414,3 +423,29 @@ class BoardEditingRow { required this.index, }); } + +class BoardCustomData { + final GroupPB group; + final GridFieldContext fieldContext; + BoardCustomData({ + required this.group, + required this.fieldContext, + }); + + CheckboxGroup? asCheckboxGroup() { + if (fieldType != FieldType.Checkbox) return null; + return CheckboxGroup(group); + } + + FieldType get fieldType => fieldContext.fieldType; +} + +class CheckboxGroup { + final GroupPB group; + + CheckboxGroup(this.group); + +// Hardcode value: "Yes" that equal to the value defined in Rust +// pub const CHECK: &str = "Yes"; + bool get isCheck => group.groupId == "Yes"; +} diff --git a/frontend/app_flowy/lib/plugins/board/presentation/board_page.dart b/frontend/app_flowy/lib/plugins/board/presentation/board_page.dart index d6c5dca609..0fd29867c6 100644 --- a/frontend/app_flowy/lib/plugins/board/presentation/board_page.dart +++ b/frontend/app_flowy/lib/plugins/board/presentation/board_page.dart @@ -17,7 +17,7 @@ import 'package:flowy_infra_ui/style_widget/text.dart'; import 'package:flowy_infra_ui/widget/error_page.dart'; import 'package:flowy_sdk/protobuf/flowy-folder/view.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-grid/block_entities.pb.dart'; -import 'package:flowy_sdk/protobuf/flowy-grid/group.pbserver.dart'; +import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pb.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import '../../grid/application/row/row_cache.dart'; @@ -36,8 +36,7 @@ class BoardPage extends StatelessWidget { create: (context) => BoardBloc(view: view)..add(const BoardEvent.initial()), child: BlocBuilder( - buildWhen: (previous, current) => - previous.loadingState != current.loadingState, + buildWhen: (p, c) => p.loadingState != c.loadingState, builder: (context, state) { return state.loadingState.map( loading: (_) => @@ -84,36 +83,15 @@ class _BoardContentState extends State { child: BlocBuilder( buildWhen: (previous, current) => previous.groupIds != current.groupIds, builder: (context, state) { - final theme = context.read(); + final column = Column( + children: [const _ToolbarBlocAdaptor(), _buildBoard(context)], + ); + return Container( - color: theme.surface, + color: context.read().surface, child: Padding( padding: const EdgeInsets.symmetric(horizontal: 20), - child: Column( - children: [ - const _ToolbarBlocAdaptor(), - Expanded( - child: AFBoard( - key: UniqueKey(), - scrollManager: scrollManager, - scrollController: scrollController, - dataController: context.read().boardController, - headerBuilder: _buildHeader, - footBuilder: _buildFooter, - cardBuilder: (_, column, columnItem) => _buildCard( - context, - column, - columnItem, - ), - columnConstraints: - const BoxConstraints.tightFor(width: 300), - config: AFBoardConfig( - columnBackgroundColor: HexColor.fromHex('#F7F8FC'), - ), - ), - ), - ], - ), + child: column, ), ); }, @@ -121,6 +99,27 @@ class _BoardContentState extends State { ); } + Expanded _buildBoard(BuildContext context) { + return Expanded( + child: AFBoard( + scrollManager: scrollManager, + scrollController: scrollController, + dataController: context.read().boardController, + headerBuilder: _buildHeader, + footBuilder: _buildFooter, + cardBuilder: (_, column, columnItem) => _buildCard( + context, + column, + columnItem, + ), + columnConstraints: const BoxConstraints.tightFor(width: 300), + config: AFBoardConfig( + columnBackgroundColor: HexColor.fromHex('#F7F8FC'), + ), + ), + ); + } + void _handleEditState(BoardState state, BuildContext context) { state.editingRow.fold( () => null, @@ -152,6 +151,7 @@ class _BoardContentState extends State { BuildContext context, AFBoardColumnData columnData, ) { + final boardCustomData = columnData.customData as BoardCustomData; return AppFlowyColumnHeader( title: Flexible( fit: FlexFit.tight, @@ -162,6 +162,7 @@ class _BoardContentState extends State { color: context.read().textColor, ), ), + icon: _buildHeaderIcon(boardCustomData), addIcon: SizedBox( height: 20, width: 20, @@ -181,7 +182,9 @@ class _BoardContentState extends State { } Widget _buildFooter(BuildContext context, AFBoardColumnData columnData) { - final group = columnData.customData as GroupPB; + final boardCustomData = columnData.customData as BoardCustomData; + final group = boardCustomData.group; + if (group.isDefault) { return const SizedBox(); } else { @@ -246,7 +249,7 @@ class _BoardContentState extends State { child: BoardCard( gridId: gridId, groupId: column.id, - fieldId: boardColumnItem.fieldId, + fieldId: boardColumnItem.fieldContext.id, isEditing: isEditing, cellBuilder: cellBuilder, dataController: cardController, @@ -319,3 +322,38 @@ extension HexColor on Color { return Color(int.parse(buffer.toString(), radix: 16)); } } + +Widget? _buildHeaderIcon(BoardCustomData customData) { + Widget? widget; + switch (customData.fieldType) { + case FieldType.Checkbox: + final group = customData.asCheckboxGroup()!; + if (group.isCheck) { + widget = svgWidget('editor/editor_check'); + } else { + widget = svgWidget('editor/editor_uncheck'); + } + break; + case FieldType.DateTime: + break; + case FieldType.MultiSelect: + break; + case FieldType.Number: + break; + case FieldType.RichText: + break; + case FieldType.SingleSelect: + break; + case FieldType.URL: + break; + } + + if (widget != null) { + widget = SizedBox( + width: 20, + height: 20, + child: widget, + ); + } + return widget; +} diff --git a/frontend/app_flowy/lib/plugins/grid/application/field/field_controller.dart b/frontend/app_flowy/lib/plugins/grid/application/field/field_controller.dart index e9bda8eef5..7eb20a8a06 100644 --- a/frontend/app_flowy/lib/plugins/grid/application/field/field_controller.dart +++ b/frontend/app_flowy/lib/plugins/grid/application/field/field_controller.dart @@ -7,6 +7,7 @@ import 'package:dartz/dartz.dart'; import 'package:flowy_sdk/log.dart'; import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pb.dart'; +import 'package:flowy_sdk/protobuf/flowy-grid/group.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-grid/setting_entities.pb.dart'; import 'package:flutter/foundation.dart'; import '../row/row_cache.dart'; @@ -35,12 +36,12 @@ class GridFieldController { final SettingListener _settingListener; final Map _fieldCallbackMap = {}; final Map _changesetCallbackMap = {}; - - _GridFieldNotifier? _fieldNotifier = _GridFieldNotifier(); - List _groupFieldIds = []; final GridFFIService _gridFFIService; final SettingFFIService _settingFFIService; + _GridFieldNotifier? _fieldNotifier = _GridFieldNotifier(); + final Map _configurationByFieldId = {}; + List get fieldContexts => [..._fieldNotifier?.fieldContexts ?? []]; @@ -67,31 +68,43 @@ class GridFieldController { //Listen on setting changes _settingListener.start(onSettingUpdated: (result) { result.fold( - (setting) => _updateFieldsWhenSettingChanged(setting), + (setting) => _updateGroupConfiguration(setting), (r) => Log.error(r), ); }); _settingFFIService.getSetting().then((result) { result.fold( - (setting) => _updateFieldsWhenSettingChanged(setting), + (setting) => _updateGroupConfiguration(setting), (err) => Log.error(err), ); }); } - void _updateFieldsWhenSettingChanged(GridSettingPB setting) { - _groupFieldIds = setting.groupConfigurations.items - .map((item) => item.groupFieldId) + GridFieldContext? getField(String fieldId) { + final fields = _fieldNotifier?.fieldContexts + .where( + (element) => element.id == fieldId, + ) .toList(); + if (fields?.isEmpty ?? true) { + return null; + } + return fields!.first; + } + void _updateGroupConfiguration(GridSettingPB setting) { + _configurationByFieldId.clear(); + for (final configuration in setting.groupConfigurations.items) { + _configurationByFieldId[configuration.fieldId] = configuration; + } _updateFieldContexts(); } void _updateFieldContexts() { if (_fieldNotifier != null) { for (var field in _fieldNotifier!.fieldContexts) { - if (_groupFieldIds.contains(field.id)) { + if (_configurationByFieldId[field.id] != null) { field._isGroupField = true; } else { field._isGroupField = false; diff --git a/frontend/app_flowy/packages/appflowy_board/lib/src/widgets/board_column/board_column.dart b/frontend/app_flowy/packages/appflowy_board/lib/src/widgets/board_column/board_column.dart index 79fe534941..ce998b365e 100644 --- a/frontend/app_flowy/packages/appflowy_board/lib/src/widgets/board_column/board_column.dart +++ b/frontend/app_flowy/packages/appflowy_board/lib/src/widgets/board_column/board_column.dart @@ -31,7 +31,7 @@ typedef AFBoardColumnCardBuilder = Widget Function( typedef AFBoardColumnHeaderBuilder = Widget? Function( BuildContext context, - AFBoardColumnData headerData, + AFBoardColumnData columnData, ); typedef AFBoardColumnFooterBuilder = Widget Function( diff --git a/frontend/rust-lib/flowy-grid/src/entities/group_entities/group.rs b/frontend/rust-lib/flowy-grid/src/entities/group_entities/group.rs index de6f920341..d2c6eb0efb 100644 --- a/frontend/rust-lib/flowy-grid/src/entities/group_entities/group.rs +++ b/frontend/rust-lib/flowy-grid/src/entities/group_entities/group.rs @@ -44,14 +44,14 @@ pub struct GridGroupConfigurationPB { pub id: String, #[pb(index = 2)] - pub group_field_id: String, + pub field_id: String, } impl std::convert::From<&GroupConfigurationRevision> for GridGroupConfigurationPB { fn from(rev: &GroupConfigurationRevision) -> Self { GridGroupConfigurationPB { id: rev.id.clone(), - group_field_id: rev.field_id.clone(), + field_id: rev.field_id.clone(), } } }