diff --git a/frontend/app_flowy/lib/startup/deps_resolver.dart b/frontend/app_flowy/lib/startup/deps_resolver.dart index cb685cd7b2..e35f8e7f96 100644 --- a/frontend/app_flowy/lib/startup/deps_resolver.dart +++ b/frontend/app_flowy/lib/startup/deps_resolver.dart @@ -157,9 +157,10 @@ void _resolveGridDeps(GetIt getIt) { ), ); - getIt.registerFactoryParam>( - (gridId, fields) => GridHeaderBloc( - data: GridHeaderData(gridId: gridId, fields: fields), + getIt.registerFactoryParam( + (gridId, fieldCache) => GridHeaderBloc( + gridId: gridId, + fieldCache: fieldCache, ), ); diff --git a/frontend/app_flowy/lib/startup/tasks/app_widget.dart b/frontend/app_flowy/lib/startup/tasks/app_widget.dart index 1747cfd8ec..3dba94ce0a 100644 --- a/frontend/app_flowy/lib/startup/tasks/app_widget.dart +++ b/frontend/app_flowy/lib/startup/tasks/app_widget.dart @@ -113,7 +113,7 @@ class ApplicationBlocObserver extends BlocObserver { // ignore: unnecessary_overrides void onTransition(Bloc bloc, Transition transition) { // Log.debug("[current]: ${transition.currentState} \n\n[next]: ${transition.nextState}"); - // Log.debug("${transition.nextState}"); + Log.debug("${transition.nextState}"); super.onTransition(bloc, transition); } @@ -123,9 +123,9 @@ class ApplicationBlocObserver extends BlocObserver { super.onError(bloc, error, stackTrace); } - // @override - // void onEvent(Bloc bloc, Object? event) { - // Log.debug("$event"); - // super.onEvent(bloc, event); - // } + @override + void onEvent(Bloc bloc, Object? event) { + // Log.debug("$event"); + super.onEvent(bloc, event); + } } diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell_bloc/date_cell_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/cell_bloc/date_cell_bloc.dart index f235b47e4a..7dd58bf5ac 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell_bloc/date_cell_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell_bloc/date_cell_bloc.dart @@ -62,7 +62,11 @@ class DateCellBloc extends Bloc { _fieldListener.updateFieldNotifier.addPublishListener((result) { result.fold( - (field) => add(DateCellEvent.didReceiveFieldUpdate(field)), + (field) { + if (!isClosed) { + add(DateCellEvent.didReceiveFieldUpdate(field)); + } + }, (err) => Log.error(err), ); }); diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell_bloc/selection_editor_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/cell_bloc/selection_editor_bloc.dart index 59510298a7..5d2c52dc0e 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell_bloc/selection_editor_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell_bloc/selection_editor_bloc.dart @@ -144,7 +144,11 @@ class SelectOptionEditorBloc extends Bloc add(SelectOptionEditorEvent.didReceiveFieldUpdate(field)), + (field) { + if (!isClosed) { + add(SelectOptionEditorEvent.didReceiveFieldUpdate(field)); + } + }, (err) => Log.error(err), ); }); diff --git a/frontend/app_flowy/lib/workspace/application/grid/data.dart b/frontend/app_flowy/lib/workspace/application/grid/data.dart deleted file mode 100644 index 7c508a6867..0000000000 --- a/frontend/app_flowy/lib/workspace/application/grid/data.dart +++ /dev/null @@ -1,8 +0,0 @@ -import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart'; - -class GridHeaderData { - final String gridId; - final List fields; - - GridHeaderData({required this.gridId, required this.fields}); -} diff --git a/frontend/app_flowy/lib/workspace/application/grid/field/field_cell_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/field/field_cell_bloc.dart index 026be9a780..11dd1af530 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/field/field_cell_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/field/field_cell_bloc.dart @@ -47,7 +47,11 @@ class FieldCellBloc extends Bloc { void _startListening() { _fieldListener.updateFieldNotifier.addPublishListener((result) { result.fold( - (field) => add(FieldCellEvent.didReceiveFieldUpdate(field)), + (field) { + if (!isClosed) { + add(FieldCellEvent.didReceiveFieldUpdate(field)); + } + }, (err) => Log.error(err), ); }); diff --git a/frontend/app_flowy/lib/workspace/application/grid/grid_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/grid_bloc.dart index abdf73acbc..882b3eb5b4 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/grid_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/grid_bloc.dart @@ -41,10 +41,7 @@ class GridBloc extends Bloc { emit(state.copyWith(rows: value.rows, listState: value.listState)); }, didReceiveFieldUpdate: (_DidReceiveFieldUpdate value) { - emit(state.copyWith( - rows: _rowCache.rows, - fields: value.fields, - )); + emit(state.copyWith(rows: _rowCache.rows, fields: value.fields)); }, ); }, @@ -56,19 +53,17 @@ class GridBloc extends Bloc { await _gridService.closeGrid(); await _fieldListener.stop(); await _gridListener.stop(); + fieldCache.dispose(); return super.close(); } void _startListening() { - fieldCache.addListener((fields) { - _rowCache.updateFields(fields); - }); - _fieldListener.updateFieldsNotifier.addPublishListener((result) { result.fold( (changeset) { fieldCache.applyChangeset(changeset); - add(GridEvent.didReceiveFieldUpdate(List.from(fieldCache.fields))); + _rowCache.updateFields(fieldCache.unmodifiableFields); + add(GridEvent.didReceiveFieldUpdate(fieldCache.clonedFields)); }, (err) => Log.error(err), ); @@ -111,12 +106,12 @@ class GridBloc extends Bloc { return Future( () => result.fold( (fields) { - fieldCache.fields = fields.items; - _rowCache.updateWithBlock(grid.blockOrders); + fieldCache.clonedFields = fields.items; + _rowCache.updateWithBlock(grid.blockOrders, fieldCache.unmodifiableFields); emit(state.copyWith( grid: Some(grid), - fields: fieldCache.fields, + fields: fieldCache.clonedFields, rows: _rowCache.rows, loadingState: GridLoadingState.finish(left(unit)), )); diff --git a/frontend/app_flowy/lib/workspace/application/grid/grid_header_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/grid_header_bloc.dart index 18086ce6d9..c7ce6c21f1 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/grid_header_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/grid_header_bloc.dart @@ -1,6 +1,3 @@ -import 'package:app_flowy/workspace/application/grid/data.dart'; -import 'package:app_flowy/workspace/application/grid/field/grid_listenr.dart'; -import 'package:flowy_sdk/log.dart'; import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; @@ -12,17 +9,13 @@ part 'grid_header_bloc.freezed.dart'; class GridHeaderBloc extends Bloc { final FieldService _fieldService; - final GridFieldCache _fieldCache; - final GridFieldsListener _fieldListener; + final GridFieldCache fieldCache; GridHeaderBloc({ - required GridHeaderData data, - }) : _fieldListener = GridFieldsListener(gridId: data.gridId), - _fieldService = FieldService(gridId: data.gridId), - _fieldCache = GridFieldCache(), - super(GridHeaderState.initial(data.fields)) { - _fieldCache.fields = data.fields; - + required String gridId, + required this.fieldCache, + }) : _fieldService = FieldService(gridId: gridId), + super(GridHeaderState.initial(fieldCache.clonedFields)) { on( (event, emit) async { await event.map( @@ -30,7 +23,6 @@ class GridHeaderBloc extends Bloc { _startListening(); }, didReceiveFieldUpdate: (_DidReceiveFieldUpdate value) { - value.fields.retainWhere((field) => field.visibility); emit(state.copyWith(fields: value.fields)); }, ); @@ -39,22 +31,15 @@ class GridHeaderBloc extends Bloc { } Future _startListening() async { - _fieldListener.updateFieldsNotifier.addPublishListener((result) { - result.fold( - (changeset) { - _fieldCache.applyChangeset(changeset); - add(GridHeaderEvent.didReceiveFieldUpdate(List.from(_fieldCache.fields))); - }, - (err) => Log.error(err), - ); + fieldCache.listenOnFieldChanged((fields) { + if (!isClosed) { + add(GridHeaderEvent.didReceiveFieldUpdate(fields)); + } }); - - _fieldListener.start(); } @override Future close() async { - await _fieldListener.stop(); return super.close(); } } @@ -70,7 +55,8 @@ class GridHeaderState with _$GridHeaderState { const factory GridHeaderState({required List fields}) = _GridHeaderState; factory GridHeaderState.initial(List fields) { - fields.retainWhere((field) => field.visibility); + // final List newFields = List.from(fields); + // newFields.retainWhere((field) => field.visibility); return GridHeaderState(fields: fields); } } diff --git a/frontend/app_flowy/lib/workspace/application/grid/grid_service.dart b/frontend/app_flowy/lib/workspace/application/grid/grid_service.dart index f596d90be2..fc853ef8b7 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/grid_service.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/grid_service.dart @@ -62,25 +62,23 @@ class GridFieldCache { _updateFields(changeset.updatedFields); } - List get fields => _fieldNotifier.fields; + UnmodifiableListView get unmodifiableFields => UnmodifiableListView(_fieldNotifier.fields); - set fields(List fields) { - _fieldNotifier.fields = fields; + List get clonedFields => [..._fieldNotifier.fields]; + + set clonedFields(List fields) { + _fieldNotifier.fields = [...fields]; } - set onFieldChanged(void Function(List) onChanged) { - _fieldNotifier.addListener(() => onChanged(fields)); - } - - void addListener(void Function(List) onFieldChanged) { - _fieldNotifier.addListener(() => onFieldChanged(fields)); + void listenOnFieldChanged(void Function(List) onFieldChanged) { + _fieldNotifier.addListener(() => onFieldChanged(clonedFields)); } void _removeFields(List deletedFields) { if (deletedFields.isEmpty) { return; } - final List fields = List.from(_fieldNotifier.fields); + final List fields = _fieldNotifier.fields; final Map deletedFieldMap = { for (var fieldOrder in deletedFields) fieldOrder.fieldId: fieldOrder }; @@ -93,7 +91,7 @@ class GridFieldCache { if (insertedFields.isEmpty) { return; } - final List fields = List.from(_fieldNotifier.fields); + final List fields = _fieldNotifier.fields; for (final indexField in insertedFields) { if (fields.length > indexField.index) { fields.removeAt(indexField.index); @@ -109,7 +107,7 @@ class GridFieldCache { if (updatedFields.isEmpty) { return; } - final List fields = List.from(_fieldNotifier.fields); + final List fields = _fieldNotifier.fields; for (final updatedField in updatedFields) { final index = fields.indexWhere((field) => field.id == updatedField.id); if (index != -1) { @@ -119,24 +117,29 @@ class GridFieldCache { } _fieldNotifier.fields = fields; } + + void dispose() { + _fieldNotifier.dispose(); + } } class GridRowCache { final String gridId; - List _fields = []; + UnmodifiableListView _fields = UnmodifiableListView([]); List _rows = []; GridRowCache({required this.gridId}); List get rows => _rows; - void updateWithBlock(List blocks) { + void updateWithBlock(List blocks, UnmodifiableListView fields) { + _fields = fields; _rows = blocks.expand((block) => block.rowOrders).map((rowOrder) { return RowData.fromBlockRow(gridId, rowOrder, _fields); }).toList(); } - void updateFields(List fields) { + void updateFields(UnmodifiableListView fields) { if (fields.isEmpty) { return; } diff --git a/frontend/app_flowy/lib/workspace/application/grid/prelude.dart b/frontend/app_flowy/lib/workspace/application/grid/prelude.dart index 7df38179ac..1308e1a67e 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/prelude.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/prelude.dart @@ -2,7 +2,6 @@ export 'grid_bloc.dart'; export 'row/row_bloc.dart'; export 'row/row_service.dart'; export 'grid_service.dart'; -export 'data.dart'; export 'grid_header_bloc.dart'; // Field diff --git a/frontend/app_flowy/lib/workspace/application/grid/row/row_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/row/row_bloc.dart index ec9b8ff04d..d6bc43e50e 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/row/row_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/row/row_bloc.dart @@ -80,9 +80,9 @@ class RowBloc extends Bloc { ); }); - _fieldCache.addListener((fields) { + _fieldCache.listenOnFieldChanged((fields) { if (!isClosed) { - add(RowEvent.didReceiveFieldUpdate(fields)); + // add(RowEvent.didReceiveFieldUpdate(fields)); } }); diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/grid_page.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/grid_page.dart index cb1cb1c888..5a772693c7 100755 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/grid_page.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/grid_page.dart @@ -77,7 +77,7 @@ class FlowyGrid extends StatelessWidget { final child = _wrapScrollView( state.fields, [ - _GridHeader(gridId: state.gridId, fields: List.from(state.fields)), + _GridHeader(gridId: state.gridId, fields: state.fields), _GridRows(), const _GridFooter(), ], @@ -150,7 +150,8 @@ class _GridHeader extends StatelessWidget { @override Widget build(BuildContext context) { - return GridHeaderSliverAdaptor(gridId: gridId, fields: fields); + final fieldCache = context.read().fieldCache; + return GridHeaderSliverAdaptor(gridId: gridId, fieldCache: fieldCache); } } diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/grid_header.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/grid_header.dart index 3893ac7784..15fb64f990 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/grid_header.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/grid_header.dart @@ -14,18 +14,19 @@ import 'field_cell.dart'; class GridHeaderSliverAdaptor extends StatelessWidget { final String gridId; - final List fields; + final GridFieldCache fieldCache; - const GridHeaderSliverAdaptor({required this.gridId, required this.fields, Key? key}) : super(key: key); + const GridHeaderSliverAdaptor({required this.gridId, required this.fieldCache, Key? key}) : super(key: key); @override Widget build(BuildContext context) { return BlocProvider( - create: (context) => getIt(param1: gridId, param2: fields)..add(const GridHeaderEvent.initial()), + create: (context) => + getIt(param1: gridId, param2: fieldCache)..add(const GridHeaderEvent.initial()), child: BlocBuilder( builder: (context, state) { return SliverPersistentHeader( - delegate: SliverHeaderDelegateImplementation(gridId: gridId, fields: fields), + delegate: SliverHeaderDelegateImplementation(gridId: gridId, fields: state.fields), floating: true, pinned: true, ); @@ -77,6 +78,7 @@ class _GridHeader extends StatelessWidget { return BlocBuilder( builder: (context, state) { final cells = state.fields + .where((field) => field.visibility) .map((field) => GridFieldCellContext(gridId: gridId, field: field)) .map((ctx) => GridFieldCell(ctx, key: ValueKey(ctx.field.id))) .toList();