mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
Merge pull request #978 from AppFlowy-IO/feat/support_group_checkbox
chore: support group by checkbox field
This commit is contained in:
commit
d9aba78727
@ -1,4 +1,6 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
import 'dart:collection';
|
||||||
|
|
||||||
import 'package:app_flowy/plugins/grid/application/block/block_cache.dart';
|
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/field/field_controller.dart';
|
||||||
import 'package:app_flowy/plugins/grid/application/row/row_cache.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:flowy_sdk/protobuf/flowy-grid/protobuf.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||||
import 'dart:collection';
|
|
||||||
|
|
||||||
import 'board_data_controller.dart';
|
import 'board_data_controller.dart';
|
||||||
import 'group_controller.dart';
|
import 'group_controller.dart';
|
||||||
@ -164,12 +165,17 @@ class BoardBloc extends Bloc<BoardEvent, BoardState> {
|
|||||||
boardController.clear();
|
boardController.clear();
|
||||||
|
|
||||||
//
|
//
|
||||||
List<AFBoardColumnData> columns = groups.map((group) {
|
List<AFBoardColumnData> columns = groups
|
||||||
|
.where((group) => fieldController.getField(group.fieldId) != null)
|
||||||
|
.map((group) {
|
||||||
return AFBoardColumnData(
|
return AFBoardColumnData(
|
||||||
id: group.groupId,
|
id: group.groupId,
|
||||||
name: group.desc,
|
name: group.desc,
|
||||||
items: _buildRows(group),
|
items: _buildRows(group),
|
||||||
customData: group,
|
customData: BoardCustomData(
|
||||||
|
group: group,
|
||||||
|
fieldContext: fieldController.getField(group.fieldId)!,
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}).toList();
|
}).toList();
|
||||||
boardController.addColumns(columns);
|
boardController.addColumns(columns);
|
||||||
@ -177,6 +183,7 @@ class BoardBloc extends Bloc<BoardEvent, BoardState> {
|
|||||||
for (final group in groups) {
|
for (final group in groups) {
|
||||||
final delegate = GroupControllerDelegateImpl(
|
final delegate = GroupControllerDelegateImpl(
|
||||||
controller: boardController,
|
controller: boardController,
|
||||||
|
fieldController: fieldController,
|
||||||
onNewColumnItem: (groupId, row, index) {
|
onNewColumnItem: (groupId, row, index) {
|
||||||
add(BoardEvent.didCreateRow(groupId, row, index));
|
add(BoardEvent.didCreateRow(groupId, row, index));
|
||||||
},
|
},
|
||||||
@ -238,10 +245,8 @@ class BoardBloc extends Bloc<BoardEvent, BoardState> {
|
|||||||
|
|
||||||
List<AFColumnItem> _buildRows(GroupPB group) {
|
List<AFColumnItem> _buildRows(GroupPB group) {
|
||||||
final items = group.rows.map((row) {
|
final items = group.rows.map((row) {
|
||||||
return BoardColumnItem(
|
final fieldContext = fieldController.getField(group.fieldId);
|
||||||
row: row,
|
return BoardColumnItem(row: row, fieldContext: fieldContext!);
|
||||||
fieldId: group.fieldId,
|
|
||||||
);
|
|
||||||
}).toList();
|
}).toList();
|
||||||
|
|
||||||
return <AFColumnItem>[...items];
|
return <AFColumnItem>[...items];
|
||||||
@ -332,15 +337,11 @@ class GridFieldEquatable extends Equatable {
|
|||||||
|
|
||||||
class BoardColumnItem extends AFColumnItem {
|
class BoardColumnItem extends AFColumnItem {
|
||||||
final RowPB row;
|
final RowPB row;
|
||||||
|
final GridFieldContext fieldContext;
|
||||||
final String fieldId;
|
|
||||||
|
|
||||||
final bool requestFocus;
|
|
||||||
|
|
||||||
BoardColumnItem({
|
BoardColumnItem({
|
||||||
required this.row,
|
required this.row,
|
||||||
required this.fieldId,
|
required this.fieldContext,
|
||||||
this.requestFocus = false,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -348,24 +349,29 @@ class BoardColumnItem extends AFColumnItem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class GroupControllerDelegateImpl extends GroupControllerDelegate {
|
class GroupControllerDelegateImpl extends GroupControllerDelegate {
|
||||||
|
final GridFieldController fieldController;
|
||||||
final AFBoardDataController controller;
|
final AFBoardDataController controller;
|
||||||
final void Function(String, RowPB, int?) onNewColumnItem;
|
final void Function(String, RowPB, int?) onNewColumnItem;
|
||||||
|
|
||||||
GroupControllerDelegateImpl({
|
GroupControllerDelegateImpl({
|
||||||
required this.controller,
|
required this.controller,
|
||||||
|
required this.fieldController,
|
||||||
required this.onNewColumnItem,
|
required this.onNewColumnItem,
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void insertRow(GroupPB group, RowPB row, int? index) {
|
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) {
|
if (index != null) {
|
||||||
final item = BoardColumnItem(row: row, fieldId: group.fieldId);
|
final item = BoardColumnItem(row: row, fieldContext: fieldContext);
|
||||||
controller.insertColumnItem(group.groupId, index, item);
|
controller.insertColumnItem(group.groupId, index, item);
|
||||||
} else {
|
} else {
|
||||||
final item = BoardColumnItem(
|
final item = BoardColumnItem(row: row, fieldContext: fieldContext);
|
||||||
row: row,
|
|
||||||
fieldId: group.fieldId,
|
|
||||||
);
|
|
||||||
controller.addColumnItem(group.groupId, item);
|
controller.addColumnItem(group.groupId, item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -377,22 +383,25 @@ class GroupControllerDelegateImpl extends GroupControllerDelegate {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
void updateRow(GroupPB group, RowPB row) {
|
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(
|
controller.updateColumnItem(
|
||||||
group.groupId,
|
group.groupId,
|
||||||
BoardColumnItem(
|
BoardColumnItem(row: row, fieldContext: fieldContext),
|
||||||
row: row,
|
|
||||||
fieldId: group.fieldId,
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void addNewRow(GroupPB group, RowPB row, int? index) {
|
void addNewRow(GroupPB group, RowPB row, int? index) {
|
||||||
final item = BoardColumnItem(
|
final fieldContext = fieldController.getField(group.fieldId);
|
||||||
row: row,
|
if (fieldContext == null) {
|
||||||
fieldId: group.fieldId,
|
Log.warn("FieldContext should not be null");
|
||||||
requestFocus: true,
|
return;
|
||||||
);
|
}
|
||||||
|
final item = BoardColumnItem(row: row, fieldContext: fieldContext);
|
||||||
|
|
||||||
if (index != null) {
|
if (index != null) {
|
||||||
controller.insertColumnItem(group.groupId, index, item);
|
controller.insertColumnItem(group.groupId, index, item);
|
||||||
@ -414,3 +423,29 @@ class BoardEditingRow {
|
|||||||
required this.index,
|
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";
|
||||||
|
}
|
||||||
|
@ -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_infra_ui/widget/error_page.dart';
|
||||||
import 'package:flowy_sdk/protobuf/flowy-folder/view.pb.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/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/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import '../../grid/application/row/row_cache.dart';
|
import '../../grid/application/row/row_cache.dart';
|
||||||
@ -36,8 +36,7 @@ class BoardPage extends StatelessWidget {
|
|||||||
create: (context) =>
|
create: (context) =>
|
||||||
BoardBloc(view: view)..add(const BoardEvent.initial()),
|
BoardBloc(view: view)..add(const BoardEvent.initial()),
|
||||||
child: BlocBuilder<BoardBloc, BoardState>(
|
child: BlocBuilder<BoardBloc, BoardState>(
|
||||||
buildWhen: (previous, current) =>
|
buildWhen: (p, c) => p.loadingState != c.loadingState,
|
||||||
previous.loadingState != current.loadingState,
|
|
||||||
builder: (context, state) {
|
builder: (context, state) {
|
||||||
return state.loadingState.map(
|
return state.loadingState.map(
|
||||||
loading: (_) =>
|
loading: (_) =>
|
||||||
@ -84,36 +83,15 @@ class _BoardContentState extends State<BoardContent> {
|
|||||||
child: BlocBuilder<BoardBloc, BoardState>(
|
child: BlocBuilder<BoardBloc, BoardState>(
|
||||||
buildWhen: (previous, current) => previous.groupIds != current.groupIds,
|
buildWhen: (previous, current) => previous.groupIds != current.groupIds,
|
||||||
builder: (context, state) {
|
builder: (context, state) {
|
||||||
final theme = context.read<AppTheme>();
|
final column = Column(
|
||||||
|
children: [const _ToolbarBlocAdaptor(), _buildBoard(context)],
|
||||||
|
);
|
||||||
|
|
||||||
return Container(
|
return Container(
|
||||||
color: theme.surface,
|
color: context.read<AppTheme>().surface,
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 20),
|
padding: const EdgeInsets.symmetric(horizontal: 20),
|
||||||
child: Column(
|
child: column,
|
||||||
children: [
|
|
||||||
const _ToolbarBlocAdaptor(),
|
|
||||||
Expanded(
|
|
||||||
child: AFBoard(
|
|
||||||
key: UniqueKey(),
|
|
||||||
scrollManager: scrollManager,
|
|
||||||
scrollController: scrollController,
|
|
||||||
dataController: context.read<BoardBloc>().boardController,
|
|
||||||
headerBuilder: _buildHeader,
|
|
||||||
footBuilder: _buildFooter,
|
|
||||||
cardBuilder: (_, column, columnItem) => _buildCard(
|
|
||||||
context,
|
|
||||||
column,
|
|
||||||
columnItem,
|
|
||||||
),
|
|
||||||
columnConstraints:
|
|
||||||
const BoxConstraints.tightFor(width: 300),
|
|
||||||
config: AFBoardConfig(
|
|
||||||
columnBackgroundColor: HexColor.fromHex('#F7F8FC'),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
@ -121,6 +99,27 @@ class _BoardContentState extends State<BoardContent> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Expanded _buildBoard(BuildContext context) {
|
||||||
|
return Expanded(
|
||||||
|
child: AFBoard(
|
||||||
|
scrollManager: scrollManager,
|
||||||
|
scrollController: scrollController,
|
||||||
|
dataController: context.read<BoardBloc>().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) {
|
void _handleEditState(BoardState state, BuildContext context) {
|
||||||
state.editingRow.fold(
|
state.editingRow.fold(
|
||||||
() => null,
|
() => null,
|
||||||
@ -152,6 +151,7 @@ class _BoardContentState extends State<BoardContent> {
|
|||||||
BuildContext context,
|
BuildContext context,
|
||||||
AFBoardColumnData columnData,
|
AFBoardColumnData columnData,
|
||||||
) {
|
) {
|
||||||
|
final boardCustomData = columnData.customData as BoardCustomData;
|
||||||
return AppFlowyColumnHeader(
|
return AppFlowyColumnHeader(
|
||||||
title: Flexible(
|
title: Flexible(
|
||||||
fit: FlexFit.tight,
|
fit: FlexFit.tight,
|
||||||
@ -162,6 +162,7 @@ class _BoardContentState extends State<BoardContent> {
|
|||||||
color: context.read<AppTheme>().textColor,
|
color: context.read<AppTheme>().textColor,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
icon: _buildHeaderIcon(boardCustomData),
|
||||||
addIcon: SizedBox(
|
addIcon: SizedBox(
|
||||||
height: 20,
|
height: 20,
|
||||||
width: 20,
|
width: 20,
|
||||||
@ -181,7 +182,9 @@ class _BoardContentState extends State<BoardContent> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildFooter(BuildContext context, AFBoardColumnData columnData) {
|
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) {
|
if (group.isDefault) {
|
||||||
return const SizedBox();
|
return const SizedBox();
|
||||||
} else {
|
} else {
|
||||||
@ -246,7 +249,7 @@ class _BoardContentState extends State<BoardContent> {
|
|||||||
child: BoardCard(
|
child: BoardCard(
|
||||||
gridId: gridId,
|
gridId: gridId,
|
||||||
groupId: column.id,
|
groupId: column.id,
|
||||||
fieldId: boardColumnItem.fieldId,
|
fieldId: boardColumnItem.fieldContext.id,
|
||||||
isEditing: isEditing,
|
isEditing: isEditing,
|
||||||
cellBuilder: cellBuilder,
|
cellBuilder: cellBuilder,
|
||||||
dataController: cardController,
|
dataController: cardController,
|
||||||
@ -319,3 +322,38 @@ extension HexColor on Color {
|
|||||||
return Color(int.parse(buffer.toString(), radix: 16));
|
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;
|
||||||
|
}
|
||||||
|
@ -7,6 +7,7 @@ import 'package:dartz/dartz.dart';
|
|||||||
import 'package:flowy_sdk/log.dart';
|
import 'package:flowy_sdk/log.dart';
|
||||||
import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.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/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:flowy_sdk/protobuf/flowy-grid/setting_entities.pb.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import '../row/row_cache.dart';
|
import '../row/row_cache.dart';
|
||||||
@ -35,12 +36,12 @@ class GridFieldController {
|
|||||||
final SettingListener _settingListener;
|
final SettingListener _settingListener;
|
||||||
final Map<OnReceiveFields, VoidCallback> _fieldCallbackMap = {};
|
final Map<OnReceiveFields, VoidCallback> _fieldCallbackMap = {};
|
||||||
final Map<OnChangeset, OnChangeset> _changesetCallbackMap = {};
|
final Map<OnChangeset, OnChangeset> _changesetCallbackMap = {};
|
||||||
|
|
||||||
_GridFieldNotifier? _fieldNotifier = _GridFieldNotifier();
|
|
||||||
List<String> _groupFieldIds = [];
|
|
||||||
final GridFFIService _gridFFIService;
|
final GridFFIService _gridFFIService;
|
||||||
final SettingFFIService _settingFFIService;
|
final SettingFFIService _settingFFIService;
|
||||||
|
|
||||||
|
_GridFieldNotifier? _fieldNotifier = _GridFieldNotifier();
|
||||||
|
final Map<String, GridGroupConfigurationPB> _configurationByFieldId = {};
|
||||||
|
|
||||||
List<GridFieldContext> get fieldContexts =>
|
List<GridFieldContext> get fieldContexts =>
|
||||||
[..._fieldNotifier?.fieldContexts ?? []];
|
[..._fieldNotifier?.fieldContexts ?? []];
|
||||||
|
|
||||||
@ -67,31 +68,43 @@ class GridFieldController {
|
|||||||
//Listen on setting changes
|
//Listen on setting changes
|
||||||
_settingListener.start(onSettingUpdated: (result) {
|
_settingListener.start(onSettingUpdated: (result) {
|
||||||
result.fold(
|
result.fold(
|
||||||
(setting) => _updateFieldsWhenSettingChanged(setting),
|
(setting) => _updateGroupConfiguration(setting),
|
||||||
(r) => Log.error(r),
|
(r) => Log.error(r),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
_settingFFIService.getSetting().then((result) {
|
_settingFFIService.getSetting().then((result) {
|
||||||
result.fold(
|
result.fold(
|
||||||
(setting) => _updateFieldsWhenSettingChanged(setting),
|
(setting) => _updateGroupConfiguration(setting),
|
||||||
(err) => Log.error(err),
|
(err) => Log.error(err),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void _updateFieldsWhenSettingChanged(GridSettingPB setting) {
|
GridFieldContext? getField(String fieldId) {
|
||||||
_groupFieldIds = setting.groupConfigurations.items
|
final fields = _fieldNotifier?.fieldContexts
|
||||||
.map((item) => item.groupFieldId)
|
.where(
|
||||||
|
(element) => element.id == fieldId,
|
||||||
|
)
|
||||||
.toList();
|
.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();
|
_updateFieldContexts();
|
||||||
}
|
}
|
||||||
|
|
||||||
void _updateFieldContexts() {
|
void _updateFieldContexts() {
|
||||||
if (_fieldNotifier != null) {
|
if (_fieldNotifier != null) {
|
||||||
for (var field in _fieldNotifier!.fieldContexts) {
|
for (var field in _fieldNotifier!.fieldContexts) {
|
||||||
if (_groupFieldIds.contains(field.id)) {
|
if (_configurationByFieldId[field.id] != null) {
|
||||||
field._isGroupField = true;
|
field._isGroupField = true;
|
||||||
} else {
|
} else {
|
||||||
field._isGroupField = false;
|
field._isGroupField = false;
|
||||||
|
@ -31,7 +31,7 @@ typedef AFBoardColumnCardBuilder = Widget Function(
|
|||||||
|
|
||||||
typedef AFBoardColumnHeaderBuilder = Widget? Function(
|
typedef AFBoardColumnHeaderBuilder = Widget? Function(
|
||||||
BuildContext context,
|
BuildContext context,
|
||||||
AFBoardColumnData headerData,
|
AFBoardColumnData columnData,
|
||||||
);
|
);
|
||||||
|
|
||||||
typedef AFBoardColumnFooterBuilder = Widget Function(
|
typedef AFBoardColumnFooterBuilder = Widget Function(
|
||||||
|
@ -44,14 +44,14 @@ pub struct GridGroupConfigurationPB {
|
|||||||
pub id: String,
|
pub id: String,
|
||||||
|
|
||||||
#[pb(index = 2)]
|
#[pb(index = 2)]
|
||||||
pub group_field_id: String,
|
pub field_id: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::convert::From<&GroupConfigurationRevision> for GridGroupConfigurationPB {
|
impl std::convert::From<&GroupConfigurationRevision> for GridGroupConfigurationPB {
|
||||||
fn from(rev: &GroupConfigurationRevision) -> Self {
|
fn from(rev: &GroupConfigurationRevision) -> Self {
|
||||||
GridGroupConfigurationPB {
|
GridGroupConfigurationPB {
|
||||||
id: rev.id.clone(),
|
id: rev.id.clone(),
|
||||||
group_field_id: rev.field_id.clone(),
|
field_id: rev.field_id.clone(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -182,7 +182,6 @@ pub fn delete_select_option_cell(option_id: String, field_rev: &FieldRevision) -
|
|||||||
CellRevision::new(data)
|
CellRevision::new(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// If the cell data is not String type, it should impl this trait.
|
|
||||||
/// Deserialize the String into cell specific data type.
|
/// Deserialize the String into cell specific data type.
|
||||||
pub trait FromCellString {
|
pub trait FromCellString {
|
||||||
fn from_cell_str(s: &str) -> FlowyResult<Self>
|
fn from_cell_str(s: &str) -> FlowyResult<Self>
|
||||||
|
@ -1,13 +1,16 @@
|
|||||||
use crate::entities::GroupChangesetPB;
|
use crate::entities::GroupChangesetPB;
|
||||||
|
|
||||||
use crate::services::group::controller::MoveGroupRowContext;
|
use crate::services::group::controller::MoveGroupRowContext;
|
||||||
use flowy_grid_data_model::revision::RowRevision;
|
use flowy_grid_data_model::revision::{CellRevision, RowRevision};
|
||||||
|
|
||||||
pub trait GroupAction: Send + Sync {
|
pub trait GroupAction: Send + Sync {
|
||||||
type CellDataType;
|
type CellDataType;
|
||||||
|
fn default_cell_rev(&self) -> Option<CellRevision> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
fn can_group(&self, content: &str, cell_data: &Self::CellDataType) -> bool;
|
fn can_group(&self, content: &str, cell_data: &Self::CellDataType) -> bool;
|
||||||
fn add_row_if_match(&mut self, row_rev: &RowRevision, cell_data: &Self::CellDataType) -> Vec<GroupChangesetPB>;
|
fn add_row_if_match(&mut self, row_rev: &RowRevision, cell_data: &Self::CellDataType) -> Vec<GroupChangesetPB>;
|
||||||
fn remove_row_if_match(&mut self, row_rev: &RowRevision, cell_data: &Self::CellDataType) -> Vec<GroupChangesetPB>;
|
fn remove_row_if_match(&mut self, row_rev: &RowRevision, cell_data: &Self::CellDataType) -> Vec<GroupChangesetPB>;
|
||||||
|
|
||||||
fn move_row(&mut self, cell_data: &Self::CellDataType, context: MoveGroupRowContext) -> Vec<GroupChangesetPB>;
|
fn move_row(&mut self, cell_data: &Self::CellDataType, context: MoveGroupRowContext) -> Vec<GroupChangesetPB>;
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,6 @@ use flowy_error::FlowyResult;
|
|||||||
use flowy_grid_data_model::revision::{
|
use flowy_grid_data_model::revision::{
|
||||||
FieldRevision, GroupConfigurationContentSerde, GroupRevision, RowChangeset, RowRevision, TypeOptionDataDeserializer,
|
FieldRevision, GroupConfigurationContentSerde, GroupRevision, RowChangeset, RowRevision, TypeOptionDataDeserializer,
|
||||||
};
|
};
|
||||||
|
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
@ -193,9 +192,14 @@ where
|
|||||||
#[tracing::instrument(level = "trace", skip_all, fields(row_count=%row_revs.len(), group_result))]
|
#[tracing::instrument(level = "trace", skip_all, fields(row_count=%row_revs.len(), group_result))]
|
||||||
fn fill_groups(&mut self, row_revs: &[Arc<RowRevision>], field_rev: &FieldRevision) -> FlowyResult<()> {
|
fn fill_groups(&mut self, row_revs: &[Arc<RowRevision>], field_rev: &FieldRevision) -> FlowyResult<()> {
|
||||||
for row_rev in row_revs {
|
for row_rev in row_revs {
|
||||||
if let Some(cell_rev) = row_rev.cells.get(&self.field_id) {
|
let cell_rev = match row_rev.cells.get(&self.field_id) {
|
||||||
|
None => self.default_cell_rev(),
|
||||||
|
Some(cell_rev) => Some(cell_rev.clone()),
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(cell_rev) = cell_rev {
|
||||||
let mut grouped_rows: Vec<GroupedRow> = vec![];
|
let mut grouped_rows: Vec<GroupedRow> = vec![];
|
||||||
let cell_bytes = decode_any_cell_data(cell_rev.data.clone(), field_rev);
|
let cell_bytes = decode_any_cell_data(cell_rev.data, field_rev);
|
||||||
let cell_data = cell_bytes.parser::<P>()?;
|
let cell_data = cell_bytes.parser::<P>()?;
|
||||||
for group in self.group_ctx.concrete_groups() {
|
for group in self.group_ctx.concrete_groups() {
|
||||||
if self.can_group(&group.filter_content, &cell_data) {
|
if self.can_group(&group.filter_content, &cell_data) {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use crate::entities::GroupChangesetPB;
|
use crate::entities::{GroupChangesetPB, InsertedRowPB, RowPB};
|
||||||
use crate::services::field::{CheckboxCellData, CheckboxCellDataParser, CheckboxTypeOptionPB, CHECK, UNCHECK};
|
use crate::services::field::{CheckboxCellData, CheckboxCellDataParser, CheckboxTypeOptionPB, CHECK, UNCHECK};
|
||||||
use crate::services::group::action::GroupAction;
|
use crate::services::group::action::GroupAction;
|
||||||
use crate::services::group::configuration::GroupContext;
|
use crate::services::group::configuration::GroupContext;
|
||||||
@ -6,8 +6,11 @@ use crate::services::group::controller::{
|
|||||||
GenericGroupController, GroupController, GroupGenerator, MoveGroupRowContext,
|
GenericGroupController, GroupController, GroupGenerator, MoveGroupRowContext,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::services::group::GeneratedGroup;
|
use crate::services::cell::insert_checkbox_cell;
|
||||||
use flowy_grid_data_model::revision::{CheckboxGroupConfigurationRevision, FieldRevision, GroupRevision, RowRevision};
|
use crate::services::group::{move_group_row, GeneratedGroup};
|
||||||
|
use flowy_grid_data_model::revision::{
|
||||||
|
CellRevision, CheckboxGroupConfigurationRevision, FieldRevision, GroupRevision, RowRevision,
|
||||||
|
};
|
||||||
|
|
||||||
pub type CheckboxGroupController = GenericGroupController<
|
pub type CheckboxGroupController = GenericGroupController<
|
||||||
CheckboxGroupConfigurationRevision,
|
CheckboxGroupConfigurationRevision,
|
||||||
@ -20,30 +23,79 @@ pub type CheckboxGroupContext = GroupContext<CheckboxGroupConfigurationRevision>
|
|||||||
|
|
||||||
impl GroupAction for CheckboxGroupController {
|
impl GroupAction for CheckboxGroupController {
|
||||||
type CellDataType = CheckboxCellData;
|
type CellDataType = CheckboxCellData;
|
||||||
fn can_group(&self, _content: &str, _cell_data: &Self::CellDataType) -> bool {
|
fn default_cell_rev(&self) -> Option<CellRevision> {
|
||||||
false
|
Some(CellRevision::new(UNCHECK.to_string()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_row_if_match(&mut self, _row_rev: &RowRevision, _cell_data: &Self::CellDataType) -> Vec<GroupChangesetPB> {
|
fn can_group(&self, content: &str, cell_data: &Self::CellDataType) -> bool {
|
||||||
todo!()
|
return if cell_data.is_check() {
|
||||||
|
content == CHECK
|
||||||
|
} else {
|
||||||
|
content == UNCHECK
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn remove_row_if_match(
|
fn add_row_if_match(&mut self, row_rev: &RowRevision, cell_data: &Self::CellDataType) -> Vec<GroupChangesetPB> {
|
||||||
&mut self,
|
let mut changesets = vec![];
|
||||||
_row_rev: &RowRevision,
|
self.group_ctx.iter_mut_groups(|group| {
|
||||||
_cell_data: &Self::CellDataType,
|
let mut changeset = GroupChangesetPB::new(group.id.clone());
|
||||||
) -> Vec<GroupChangesetPB> {
|
let is_contained = group.contains_row(&row_rev.id);
|
||||||
todo!()
|
if group.id == CHECK && cell_data.is_check() {
|
||||||
|
if !is_contained {
|
||||||
|
let row_pb = RowPB::from(row_rev);
|
||||||
|
changeset.inserted_rows.push(InsertedRowPB::new(row_pb.clone()));
|
||||||
|
group.add_row(row_pb);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if is_contained {
|
||||||
|
changeset.deleted_rows.push(row_rev.id.clone());
|
||||||
|
group.remove_row(&row_rev.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !changeset.is_empty() {
|
||||||
|
changesets.push(changeset);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
changesets
|
||||||
}
|
}
|
||||||
|
|
||||||
fn move_row(&mut self, _cell_data: &Self::CellDataType, _context: MoveGroupRowContext) -> Vec<GroupChangesetPB> {
|
fn remove_row_if_match(&mut self, row_rev: &RowRevision, _cell_data: &Self::CellDataType) -> Vec<GroupChangesetPB> {
|
||||||
todo!()
|
let mut changesets = vec![];
|
||||||
|
self.group_ctx.iter_mut_groups(|group| {
|
||||||
|
let mut changeset = GroupChangesetPB::new(group.id.clone());
|
||||||
|
if group.contains_row(&row_rev.id) {
|
||||||
|
changeset.deleted_rows.push(row_rev.id.clone());
|
||||||
|
group.remove_row(&row_rev.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if !changeset.is_empty() {
|
||||||
|
changesets.push(changeset);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
changesets
|
||||||
|
}
|
||||||
|
|
||||||
|
fn move_row(&mut self, _cell_data: &Self::CellDataType, mut context: MoveGroupRowContext) -> Vec<GroupChangesetPB> {
|
||||||
|
let mut group_changeset = vec![];
|
||||||
|
self.group_ctx.iter_mut_groups(|group| {
|
||||||
|
if let Some(changeset) = move_group_row(group, &mut context) {
|
||||||
|
group_changeset.push(changeset);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
group_changeset
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GroupController for CheckboxGroupController {
|
impl GroupController for CheckboxGroupController {
|
||||||
fn will_create_row(&mut self, _row_rev: &mut RowRevision, _field_rev: &FieldRevision, _group_id: &str) {
|
fn will_create_row(&mut self, row_rev: &mut RowRevision, field_rev: &FieldRevision, group_id: &str) {
|
||||||
todo!()
|
match self.group_ctx.get_group(group_id) {
|
||||||
|
None => tracing::warn!("Can not find the group: {}", group_id),
|
||||||
|
Some((_, group)) => {
|
||||||
|
let is_check = group.id == CHECK;
|
||||||
|
let cell_rev = insert_checkbox_cell(is_check, field_rev);
|
||||||
|
row_rev.cells.insert(field_rev.id.clone(), cell_rev);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -58,13 +110,13 @@ impl GroupGenerator for CheckboxGroupGenerator {
|
|||||||
_type_option: &Option<Self::TypeOptionType>,
|
_type_option: &Option<Self::TypeOptionType>,
|
||||||
) -> Vec<GeneratedGroup> {
|
) -> Vec<GeneratedGroup> {
|
||||||
let check_group = GeneratedGroup {
|
let check_group = GeneratedGroup {
|
||||||
group_rev: GroupRevision::new("true".to_string(), CHECK.to_string()),
|
group_rev: GroupRevision::new(CHECK.to_string(), "".to_string()),
|
||||||
filter_content: "".to_string(),
|
filter_content: CHECK.to_string(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let uncheck_group = GeneratedGroup {
|
let uncheck_group = GeneratedGroup {
|
||||||
group_rev: GroupRevision::new("false".to_string(), UNCHECK.to_string()),
|
group_rev: GroupRevision::new(UNCHECK.to_string(), "".to_string()),
|
||||||
filter_content: "".to_string(),
|
filter_content: UNCHECK.to_string(),
|
||||||
};
|
};
|
||||||
vec![check_group, uncheck_group]
|
vec![check_group, uncheck_group]
|
||||||
}
|
}
|
||||||
|
@ -46,10 +46,10 @@ impl GroupAction for MultiSelectGroupController {
|
|||||||
changesets
|
changesets
|
||||||
}
|
}
|
||||||
|
|
||||||
fn move_row(&mut self, cell_data: &Self::CellDataType, mut context: MoveGroupRowContext) -> Vec<GroupChangesetPB> {
|
fn move_row(&mut self, _cell_data: &Self::CellDataType, mut context: MoveGroupRowContext) -> Vec<GroupChangesetPB> {
|
||||||
let mut group_changeset = vec![];
|
let mut group_changeset = vec![];
|
||||||
self.group_ctx.iter_mut_groups(|group| {
|
self.group_ctx.iter_mut_groups(|group| {
|
||||||
if let Some(changeset) = move_select_option_row(group, cell_data, &mut context) {
|
if let Some(changeset) = move_group_row(group, &mut context) {
|
||||||
group_changeset.push(changeset);
|
group_changeset.push(changeset);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -46,10 +46,10 @@ impl GroupAction for SingleSelectGroupController {
|
|||||||
changesets
|
changesets
|
||||||
}
|
}
|
||||||
|
|
||||||
fn move_row(&mut self, cell_data: &Self::CellDataType, mut context: MoveGroupRowContext) -> Vec<GroupChangesetPB> {
|
fn move_row(&mut self, _cell_data: &Self::CellDataType, mut context: MoveGroupRowContext) -> Vec<GroupChangesetPB> {
|
||||||
let mut group_changeset = vec![];
|
let mut group_changeset = vec![];
|
||||||
self.group_ctx.iter_mut_groups(|group| {
|
self.group_ctx.iter_mut_groups(|group| {
|
||||||
if let Some(changeset) = move_select_option_row(group, cell_data, &mut context) {
|
if let Some(changeset) = move_group_row(group, &mut context) {
|
||||||
group_changeset.push(changeset);
|
group_changeset.push(changeset);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -62,11 +62,7 @@ pub fn remove_select_option_row(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn move_select_option_row(
|
pub fn move_group_row(group: &mut Group, context: &mut MoveGroupRowContext) -> Option<GroupChangesetPB> {
|
||||||
group: &mut Group,
|
|
||||||
_cell_data: &SelectOptionCellDataPB,
|
|
||||||
context: &mut MoveGroupRowContext,
|
|
||||||
) -> Option<GroupChangesetPB> {
|
|
||||||
let mut changeset = GroupChangesetPB::new(group.id.clone());
|
let mut changeset = GroupChangesetPB::new(group.id.clone());
|
||||||
let MoveGroupRowContext {
|
let MoveGroupRowContext {
|
||||||
row_rev,
|
row_rev,
|
||||||
|
Loading…
Reference in New Issue
Block a user