diff --git a/frontend/app_flowy/assets/images/grid/setting/group.svg b/frontend/app_flowy/assets/images/grid/setting/group.svg
new file mode 100644
index 0000000000..f0a6dff4f9
--- /dev/null
+++ b/frontend/app_flowy/assets/images/grid/setting/group.svg
@@ -0,0 +1,7 @@
+
diff --git a/frontend/app_flowy/assets/translations/en.json b/frontend/app_flowy/assets/translations/en.json
index 953e5b02bb..3990a5acc4 100644
--- a/frontend/app_flowy/assets/translations/en.json
+++ b/frontend/app_flowy/assets/translations/en.json
@@ -160,7 +160,8 @@
"settings": {
"filter": "Filter",
"sortBy": "Sort by",
- "Properties": "Properties"
+ "Properties": "Properties",
+ "group": "Group"
},
"field": {
"hide": "Hide",
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 6913b07023..26dd15038a 100644
--- a/frontend/app_flowy/lib/plugins/board/application/board_bloc.dart
+++ b/frontend/app_flowy/lib/plugins/board/application/board_bloc.dart
@@ -1,6 +1,6 @@
import 'dart:async';
import 'package:app_flowy/plugins/grid/application/block/block_cache.dart';
-import 'package:app_flowy/plugins/grid/application/field/field_cache.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_service.dart';
import 'package:appflowy_board/appflowy_board.dart';
@@ -25,7 +25,8 @@ class BoardBloc extends Bloc {
final MoveRowFFIService _rowService;
LinkedHashMap groupControllers = LinkedHashMap();
- GridFieldCache get fieldCache => _gridDataController.fieldCache;
+ GridFieldController get fieldController =>
+ _gridDataController.fieldController;
String get gridId => _gridDataController.gridId;
BoardBloc({required ViewPB view})
@@ -110,9 +111,11 @@ class BoardBloc extends Bloc {
emit(state.copyWith(noneOrError: some(error)));
},
didReceiveGroups: (List groups) {
- emit(state.copyWith(
- groupIds: groups.map((group) => group.groupId).toList(),
- ));
+ emit(
+ state.copyWith(
+ groupIds: groups.map((group) => group.groupId).toList(),
+ ),
+ );
},
);
},
@@ -154,6 +157,23 @@ class BoardBloc extends Bloc {
}
void initializeGroups(List groups) {
+ for (var controller in groupControllers.values) {
+ controller.dispose();
+ }
+ groupControllers.clear();
+ boardController.clear();
+
+ //
+ List columns = groups.map((group) {
+ return AFBoardColumnData(
+ id: group.groupId,
+ name: group.desc,
+ items: _buildRows(group),
+ customData: group,
+ );
+ }).toList();
+ boardController.addColumns(columns);
+
for (final group in groups) {
final delegate = GroupControllerDelegateImpl(
controller: boardController,
@@ -184,38 +204,35 @@ class BoardBloc extends Bloc {
}
},
didLoadGroups: (groups) {
- List columns = groups.map((group) {
- return AFBoardColumnData(
- id: group.groupId,
- name: group.desc,
- items: _buildRows(group),
- customData: group,
- );
- }).toList();
-
- boardController.addColumns(columns);
+ if (isClosed) return;
initializeGroups(groups);
add(BoardEvent.didReceiveGroups(groups));
},
onDeletedGroup: (groupIds) {
+ if (isClosed) return;
//
},
onInsertedGroup: (insertedGroups) {
+ if (isClosed) return;
//
},
onUpdatedGroup: (updatedGroups) {
- //
+ if (isClosed) return;
for (final group in updatedGroups) {
final columnController =
boardController.getColumnController(group.groupId);
- if (columnController != null) {
- columnController.updateColumnName(group.desc);
- }
+ columnController?.updateColumnName(group.desc);
}
},
onError: (err) {
Log.error(err);
},
+ onResetGroups: (groups) {
+ if (isClosed) return;
+
+ initializeGroups(groups);
+ add(BoardEvent.didReceiveGroups(groups));
+ },
);
}
diff --git a/frontend/app_flowy/lib/plugins/board/application/board_data_controller.dart b/frontend/app_flowy/lib/plugins/board/application/board_data_controller.dart
index 4ab45c64b7..923bb4ef8c 100644
--- a/frontend/app_flowy/lib/plugins/board/application/board_data_controller.dart
+++ b/frontend/app_flowy/lib/plugins/board/application/board_data_controller.dart
@@ -1,7 +1,7 @@
import 'dart:collection';
import 'package:app_flowy/plugins/grid/application/block/block_cache.dart';
-import 'package:app_flowy/plugins/grid/application/field/field_cache.dart';
+import 'package:app_flowy/plugins/grid/application/field/field_controller.dart';
import 'package:app_flowy/plugins/grid/application/grid_service.dart';
import 'package:app_flowy/plugins/grid/application/row/row_cache.dart';
import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart';
@@ -12,12 +12,13 @@ import 'package:flowy_sdk/protobuf/flowy-grid/protobuf.dart';
import 'board_listener.dart';
-typedef OnFieldsChanged = void Function(UnmodifiableListView);
+typedef OnFieldsChanged = void Function(UnmodifiableListView);
typedef OnGridChanged = void Function(GridPB);
typedef DidLoadGroups = void Function(List);
typedef OnUpdatedGroup = void Function(List);
typedef OnDeletedGroup = void Function(List);
typedef OnInsertedGroup = void Function(List);
+typedef OnResetGroups = void Function(List);
typedef OnRowsChanged = void Function(
List,
@@ -28,7 +29,7 @@ typedef OnError = void Function(FlowyError);
class BoardDataController {
final String gridId;
final GridFFIService _gridFFIService;
- final GridFieldCache fieldCache;
+ final GridFieldController fieldController;
final BoardListener _listener;
// key: the block id
@@ -55,7 +56,7 @@ class BoardDataController {
// ignore: prefer_collection_literals
_blocks = LinkedHashMap(),
_gridFFIService = GridFFIService(gridId: view.id),
- fieldCache = GridFieldCache(gridId: view.id);
+ fieldController = GridFieldController(gridId: view.id);
void addListener({
required OnGridChanged onGridChanged,
@@ -65,6 +66,7 @@ class BoardDataController {
required OnUpdatedGroup onUpdatedGroup,
required OnDeletedGroup onDeletedGroup,
required OnInsertedGroup onInsertedGroup,
+ required OnResetGroups onResetGroups,
required OnError? onError,
}) {
_onGridChanged = onGridChanged;
@@ -73,28 +75,36 @@ class BoardDataController {
_onRowsChanged = onRowsChanged;
_onError = onError;
- fieldCache.addListener(onFields: (fields) {
+ fieldController.addListener(onFields: (fields) {
_onFieldsChanged?.call(UnmodifiableListView(fields));
});
- _listener.start(onBoardChanged: (result) {
- result.fold(
- (changeset) {
- if (changeset.updateGroups.isNotEmpty) {
- onUpdatedGroup.call(changeset.updateGroups);
- }
+ _listener.start(
+ onBoardChanged: (result) {
+ result.fold(
+ (changeset) {
+ if (changeset.updateGroups.isNotEmpty) {
+ onUpdatedGroup.call(changeset.updateGroups);
+ }
- if (changeset.insertedGroups.isNotEmpty) {
- onInsertedGroup.call(changeset.insertedGroups);
- }
+ if (changeset.insertedGroups.isNotEmpty) {
+ onInsertedGroup.call(changeset.insertedGroups);
+ }
- if (changeset.deletedGroups.isNotEmpty) {
- onDeletedGroup.call(changeset.deletedGroups);
- }
- },
- (e) => _onError?.call(e),
- );
- });
+ if (changeset.deletedGroups.isNotEmpty) {
+ onDeletedGroup.call(changeset.deletedGroups);
+ }
+ },
+ (e) => _onError?.call(e),
+ );
+ },
+ onGroupByNewField: (result) {
+ result.fold(
+ (groups) => onResetGroups(groups),
+ (e) => _onError?.call(e),
+ );
+ },
+ );
}
Future> loadData() async {
@@ -103,16 +113,15 @@ class BoardDataController {
() => result.fold(
(grid) async {
_onGridChanged?.call(grid);
-
- return await _loadFields(grid).then((result) {
- return result.fold(
- (l) {
- _loadGroups(grid.blocks);
- return left(l);
- },
- (err) => right(err),
- );
- });
+ return await fieldController.loadFields(fieldIds: grid.fields).then(
+ (result) => result.fold(
+ (l) {
+ _loadGroups(grid.blocks);
+ return left(l);
+ },
+ (err) => right(err),
+ ),
+ );
},
(err) => right(err),
),
@@ -126,33 +135,19 @@ class BoardDataController {
Future dispose() async {
await _gridFFIService.closeGrid();
- await fieldCache.dispose();
+ await fieldController.dispose();
for (final blockCache in _blocks.values) {
blockCache.dispose();
}
}
- Future> _loadFields(GridPB grid) async {
- final result = await _gridFFIService.getFields(fieldIds: grid.fields);
- return Future(
- () => result.fold(
- (fields) {
- fieldCache.fields = fields.items;
- _onFieldsChanged?.call(UnmodifiableListView(fieldCache.fields));
- return left(unit);
- },
- (err) => right(err),
- ),
- );
- }
-
Future _loadGroups(List blocks) async {
for (final block in blocks) {
final cache = GridBlockCache(
gridId: gridId,
block: block,
- fieldCache: fieldCache,
+ fieldController: fieldController,
);
cache.addListener(onRowsChanged: (reason) {
diff --git a/frontend/app_flowy/lib/plugins/board/application/board_listener.dart b/frontend/app_flowy/lib/plugins/board/application/board_listener.dart
index a953a993cc..9f8662fc5b 100644
--- a/frontend/app_flowy/lib/plugins/board/application/board_listener.dart
+++ b/frontend/app_flowy/lib/plugins/board/application/board_listener.dart
@@ -5,20 +5,26 @@ import 'package:flowy_infra/notifier.dart';
import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-grid/dart_notification.pb.dart';
import 'package:dartz/dartz.dart';
+import 'package:flowy_sdk/protobuf/flowy-grid/group.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-grid/group_changeset.pb.dart';
-typedef UpdateBoardNotifiedValue = Either;
+typedef GroupUpdateValue = Either;
+typedef GroupByNewFieldValue = Either, FlowyError>;
class BoardListener {
final String viewId;
- PublishNotifier? _groupNotifier = PublishNotifier();
+ PublishNotifier? _groupUpdateNotifier = PublishNotifier();
+ PublishNotifier? _groupByNewFieldNotifier =
+ PublishNotifier();
GridNotificationListener? _listener;
BoardListener(this.viewId);
void start({
- required void Function(UpdateBoardNotifiedValue) onBoardChanged,
+ required void Function(GroupUpdateValue) onBoardChanged,
+ required void Function(GroupByNewFieldValue) onGroupByNewField,
}) {
- _groupNotifier?.addPublishListener(onBoardChanged);
+ _groupUpdateNotifier?.addPublishListener(onBoardChanged);
+ _groupByNewFieldNotifier?.addPublishListener(onGroupByNewField);
_listener = GridNotificationListener(
objectId: viewId,
handler: _handler,
@@ -32,9 +38,16 @@ class BoardListener {
switch (ty) {
case GridNotification.DidUpdateGroupView:
result.fold(
- (payload) => _groupNotifier?.value =
+ (payload) => _groupUpdateNotifier?.value =
left(GroupViewChangesetPB.fromBuffer(payload)),
- (error) => _groupNotifier?.value = right(error),
+ (error) => _groupUpdateNotifier?.value = right(error),
+ );
+ break;
+ case GridNotification.DidGroupByNewField:
+ result.fold(
+ (payload) => _groupByNewFieldNotifier?.value =
+ left(GroupViewChangesetPB.fromBuffer(payload).newGroups),
+ (error) => _groupByNewFieldNotifier?.value = right(error),
);
break;
default:
@@ -44,7 +57,10 @@ class BoardListener {
Future stop() async {
await _listener?.stop();
- _groupNotifier?.dispose();
- _groupNotifier = null;
+ _groupUpdateNotifier?.dispose();
+ _groupUpdateNotifier = null;
+
+ _groupByNewFieldNotifier?.dispose();
+ _groupByNewFieldNotifier = null;
}
}
diff --git a/frontend/app_flowy/lib/plugins/board/application/card/board_date_cell_bloc.dart b/frontend/app_flowy/lib/plugins/board/application/card/board_date_cell_bloc.dart
index b1110f45cc..a19d7b64a8 100644
--- a/frontend/app_flowy/lib/plugins/board/application/card/board_date_cell_bloc.dart
+++ b/frontend/app_flowy/lib/plugins/board/application/card/board_date_cell_bloc.dart
@@ -1,6 +1,6 @@
import 'package:app_flowy/plugins/grid/application/cell/cell_service/cell_service.dart';
+import 'package:app_flowy/plugins/grid/application/field/field_controller.dart';
import 'package:flowy_sdk/protobuf/flowy-grid/date_type_option_entities.pb.dart';
-import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pb.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'dart:async';
@@ -20,8 +20,6 @@ class BoardDateCellBloc extends Bloc {
emit(state.copyWith(
data: cellData, dateStr: _dateStrFromCellData(cellData)));
},
- didReceiveFieldUpdate: (FieldPB value) =>
- emit(state.copyWith(field: value)),
);
},
);
@@ -53,8 +51,6 @@ class BoardDateCellEvent with _$BoardDateCellEvent {
const factory BoardDateCellEvent.initial() = _InitialCell;
const factory BoardDateCellEvent.didReceiveCellUpdate(DateCellDataPB? data) =
_DidReceiveCellUpdate;
- const factory BoardDateCellEvent.didReceiveFieldUpdate(FieldPB field) =
- _DidReceiveFieldUpdate;
}
@freezed
@@ -62,14 +58,14 @@ class BoardDateCellState with _$BoardDateCellState {
const factory BoardDateCellState({
required DateCellDataPB? data,
required String dateStr,
- required FieldPB field,
+ required GridFieldContext fieldContext,
}) = _BoardDateCellState;
factory BoardDateCellState.initial(GridDateCellController context) {
final cellData = context.getCellData();
return BoardDateCellState(
- field: context.field,
+ fieldContext: context.fieldContext,
data: cellData,
dateStr: _dateStrFromCellData(cellData),
);
diff --git a/frontend/app_flowy/lib/plugins/board/application/card/card_bloc.dart b/frontend/app_flowy/lib/plugins/board/application/card/card_bloc.dart
index ad30d2b250..e4dccbf0df 100644
--- a/frontend/app_flowy/lib/plugins/board/application/card/card_bloc.dart
+++ b/frontend/app_flowy/lib/plugins/board/application/card/card_bloc.dart
@@ -59,7 +59,7 @@ class BoardCardBloc extends Bloc {
return RowInfo(
gridId: _rowService.gridId,
fields: UnmodifiableListView(
- state.cells.map((cell) => cell.identifier.field).toList(),
+ state.cells.map((cell) => cell.identifier.fieldContext).toList(),
),
rowPB: state.rowPB,
);
@@ -120,9 +120,9 @@ class BoardCellEquatable extends Equatable {
@override
List