import 'dart:collection'; import 'package:app_flowy/plugins/grid/presentation/widgets/filter/filter_info.dart'; import 'package:flowy_sdk/log.dart'; import 'package:flowy_sdk/protobuf/flowy-error/errors.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/grid_entities.pb.dart'; import 'dart:async'; import 'package:dartz/dartz.dart'; import 'block/block_cache.dart'; import 'field/field_controller.dart'; import 'prelude.dart'; import 'row/row_cache.dart'; typedef OnFieldsChanged = void Function(List); typedef OnFiltersChanged = void Function(List); typedef OnGridChanged = void Function(GridPB); typedef OnRowsChanged = void Function( List rowInfos, RowsChangedReason, ); typedef ListenOnRowChangedCondition = bool Function(); class GridController { final String gridId; final GridFFIService _gridFFIService; final GridFieldController fieldController; OnRowsChanged? _onRowChanged; OnGridChanged? _onGridChanged; // Getters // key: the block id final LinkedHashMap _blocks; UnmodifiableMapView get blocks => UnmodifiableMapView(_blocks); List get rowInfos { final List rows = []; for (var block in _blocks.values) { rows.addAll(block.rows); } return rows; } GridController({required ViewPB view}) : gridId = view.id, // ignore: prefer_collection_literals _blocks = LinkedHashMap(), _gridFFIService = GridFFIService(gridId: view.id), fieldController = GridFieldController(gridId: view.id); void addListener({ OnGridChanged? onGridChanged, OnRowsChanged? onRowsChanged, OnFieldsChanged? onFieldsChanged, OnFiltersChanged? onFiltersChanged, }) { _onGridChanged = onGridChanged; _onRowChanged = onRowsChanged; fieldController.addListener( onFields: onFieldsChanged, onFilters: onFiltersChanged, ); } // Loads the rows from each block Future> openGrid() async { return _gridFFIService.openGrid().then((result) { return result.fold( (grid) async { _initialBlocks(grid.blocks); _onGridChanged?.call(grid); final result = await fieldController.loadFields( fieldIds: grid.fields, ); return result; }, (err) => right(err), ); }); } Future createRow() async { await _gridFFIService.createRow(); } Future dispose() async { await _gridFFIService.closeGrid(); await fieldController.dispose(); for (final blockCache in _blocks.values) { blockCache.dispose(); } } void _initialBlocks(List blocks) { for (final block in blocks) { if (_blocks[block.id] != null) { Log.warn("Initial duplicate block's cache: ${block.id}"); return; } final cache = GridBlockCache( gridId: gridId, block: block, fieldController: fieldController, ); cache.addListener(onRowsChanged: (reason) { _onRowChanged?.call(rowInfos, reason); }); _blocks[block.id] = cache; } } }