mirror of
				https://github.com/AppFlowy-IO/AppFlowy.git
				synced 2025-11-04 12:03:28 +00:00 
			
		
		
		
	refactor: add documentation to GridCellContext
This commit is contained in:
		
							parent
							
								
									6020459f76
								
							
						
					
					
						commit
						3844d6aad1
					
				@ -9,18 +9,18 @@ import 'block_listener.dart';
 | 
			
		||||
class GridBlockCacheService {
 | 
			
		||||
  final String gridId;
 | 
			
		||||
  final GridBlock block;
 | 
			
		||||
  late GridRowCacheService _rowCache;
 | 
			
		||||
  late GridRowsCache _rowCache;
 | 
			
		||||
  late GridBlockListener _listener;
 | 
			
		||||
 | 
			
		||||
  List<GridRow> get rows => _rowCache.rows;
 | 
			
		||||
  GridRowCacheService get rowCache => _rowCache;
 | 
			
		||||
  GridRowsCache get rowCache => _rowCache;
 | 
			
		||||
 | 
			
		||||
  GridBlockCacheService({
 | 
			
		||||
    required this.gridId,
 | 
			
		||||
    required this.block,
 | 
			
		||||
    required GridFieldCache fieldCache,
 | 
			
		||||
  }) {
 | 
			
		||||
    _rowCache = GridRowCacheService(
 | 
			
		||||
    _rowCache = GridRowsCache(
 | 
			
		||||
      gridId: gridId,
 | 
			
		||||
      block: block,
 | 
			
		||||
      delegate: GridRowCacheDelegateImpl(fieldCache),
 | 
			
		||||
 | 
			
		||||
@ -3,7 +3,7 @@ part of 'cell_service.dart';
 | 
			
		||||
typedef GridCellMap = LinkedHashMap<String, GridCell>;
 | 
			
		||||
 | 
			
		||||
class _GridCellCacheObject {
 | 
			
		||||
  _GridCellCacheKey key;
 | 
			
		||||
  GridCellCacheKey key;
 | 
			
		||||
  dynamic object;
 | 
			
		||||
  _GridCellCacheObject({
 | 
			
		||||
    required this.key,
 | 
			
		||||
@ -11,67 +11,26 @@ class _GridCellCacheObject {
 | 
			
		||||
  });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class _GridCellCacheKey {
 | 
			
		||||
class GridCellCacheKey {
 | 
			
		||||
  final String fieldId;
 | 
			
		||||
  final String rowId;
 | 
			
		||||
  _GridCellCacheKey({
 | 
			
		||||
  GridCellCacheKey({
 | 
			
		||||
    required this.fieldId,
 | 
			
		||||
    required this.rowId,
 | 
			
		||||
  });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
abstract class GridCellCacheDelegate {
 | 
			
		||||
  void onFieldUpdated(void Function(Field) callback);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class GridCellCacheService {
 | 
			
		||||
class GridCellsCache {
 | 
			
		||||
  final String gridId;
 | 
			
		||||
  final GridCellCacheDelegate delegate;
 | 
			
		||||
 | 
			
		||||
  /// fieldId: {objectId: callback}
 | 
			
		||||
  final Map<String, Map<String, List<VoidCallback>>> _fieldListenerByFieldId = {};
 | 
			
		||||
 | 
			
		||||
  /// fieldId: {cacheKey: cacheData}
 | 
			
		||||
  final Map<String, Map<String, dynamic>> _cellDataByFieldId = {};
 | 
			
		||||
  GridCellCacheService({
 | 
			
		||||
  GridCellsCache({
 | 
			
		||||
    required this.gridId,
 | 
			
		||||
    required this.delegate,
 | 
			
		||||
  }) {
 | 
			
		||||
    delegate.onFieldUpdated((field) {
 | 
			
		||||
      _cellDataByFieldId.remove(field.id);
 | 
			
		||||
      final map = _fieldListenerByFieldId[field.id];
 | 
			
		||||
      if (map != null) {
 | 
			
		||||
        for (final callbacks in map.values) {
 | 
			
		||||
          for (final callback in callbacks) {
 | 
			
		||||
            callback();
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  void addFieldListener(_GridCellCacheKey cacheKey, VoidCallback onFieldChanged) {
 | 
			
		||||
    var map = _fieldListenerByFieldId[cacheKey.fieldId];
 | 
			
		||||
    if (map == null) {
 | 
			
		||||
      _fieldListenerByFieldId[cacheKey.fieldId] = {};
 | 
			
		||||
      map = _fieldListenerByFieldId[cacheKey.fieldId];
 | 
			
		||||
      map![cacheKey.rowId] = [onFieldChanged];
 | 
			
		||||
    } else {
 | 
			
		||||
      var objects = map[cacheKey.rowId];
 | 
			
		||||
      if (objects == null) {
 | 
			
		||||
        map[cacheKey.rowId] = [onFieldChanged];
 | 
			
		||||
      } else {
 | 
			
		||||
        objects.add(onFieldChanged);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  void removeFieldListener(_GridCellCacheKey cacheKey, VoidCallback fn) {
 | 
			
		||||
    var callbacks = _fieldListenerByFieldId[cacheKey.fieldId]?[cacheKey.rowId];
 | 
			
		||||
    final index = callbacks?.indexWhere((callback) => callback == fn);
 | 
			
		||||
    if (index != null && index != -1) {
 | 
			
		||||
      callbacks?.removeAt(index);
 | 
			
		||||
    }
 | 
			
		||||
  void remove(String fieldId) {
 | 
			
		||||
    _cellDataByFieldId.remove(fieldId);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  void insert<T extends _GridCellCacheObject>(T item) {
 | 
			
		||||
@ -84,7 +43,7 @@ class GridCellCacheService {
 | 
			
		||||
    map![item.key.rowId] = item.object;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  T? get<T>(_GridCellCacheKey key) {
 | 
			
		||||
  T? get<T>(GridCellCacheKey key) {
 | 
			
		||||
    final map = _cellDataByFieldId[key.fieldId];
 | 
			
		||||
    if (map == null) {
 | 
			
		||||
      return null;
 | 
			
		||||
@ -103,7 +62,6 @@ class GridCellCacheService {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  Future<void> dispose() async {
 | 
			
		||||
    _fieldListenerByFieldId.clear();
 | 
			
		||||
    _cellDataByFieldId.clear();
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -3,23 +3,13 @@ part of 'cell_service.dart';
 | 
			
		||||
abstract class IGridCellDataConfig {
 | 
			
		||||
  // The cell data will reload if it receives the field's change notification.
 | 
			
		||||
  bool get reloadOnFieldChanged;
 | 
			
		||||
 | 
			
		||||
  // When the reloadOnCellChanged is true, it will load the cell data after user input.
 | 
			
		||||
  // For example: The number cell reload the cell data that carries the format
 | 
			
		||||
  // user input: 12
 | 
			
		||||
  // cell display: $12
 | 
			
		||||
  bool get reloadOnCellChanged;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class GridCellDataConfig implements IGridCellDataConfig {
 | 
			
		||||
  @override
 | 
			
		||||
  final bool reloadOnCellChanged;
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  final bool reloadOnFieldChanged;
 | 
			
		||||
 | 
			
		||||
  const GridCellDataConfig({
 | 
			
		||||
    this.reloadOnCellChanged = false,
 | 
			
		||||
    this.reloadOnFieldChanged = false,
 | 
			
		||||
  });
 | 
			
		||||
}
 | 
			
		||||
@ -72,29 +62,6 @@ class GridCellDataLoader<T> extends IGridCellDataLoader<T> {
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class SelectOptionCellDataLoader extends IGridCellDataLoader<SelectOptionCellData> {
 | 
			
		||||
  final SelectOptionService service;
 | 
			
		||||
  final GridCell gridCell;
 | 
			
		||||
  SelectOptionCellDataLoader({
 | 
			
		||||
    required this.gridCell,
 | 
			
		||||
  }) : service = SelectOptionService(gridCell: gridCell);
 | 
			
		||||
  @override
 | 
			
		||||
  Future<SelectOptionCellData?> loadData() async {
 | 
			
		||||
    return service.getOpitonContext().then((result) {
 | 
			
		||||
      return result.fold(
 | 
			
		||||
        (data) => data,
 | 
			
		||||
        (err) {
 | 
			
		||||
          Log.error(err);
 | 
			
		||||
          return null;
 | 
			
		||||
        },
 | 
			
		||||
      );
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  IGridCellDataConfig get config => const GridCellDataConfig(reloadOnFieldChanged: true);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class StringCellDataParser implements ICellDataParser<String> {
 | 
			
		||||
  @override
 | 
			
		||||
  String? parserData(List<int> data) {
 | 
			
		||||
 | 
			
		||||
@ -1,10 +1,10 @@
 | 
			
		||||
part of 'cell_service.dart';
 | 
			
		||||
 | 
			
		||||
abstract class _GridCellDataPersistence<D> {
 | 
			
		||||
abstract class IGridCellDataPersistence<D> {
 | 
			
		||||
  Future<Option<FlowyError>> save(D data);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class CellDataPersistence implements _GridCellDataPersistence<String> {
 | 
			
		||||
class CellDataPersistence implements IGridCellDataPersistence<String> {
 | 
			
		||||
  final GridCell gridCell;
 | 
			
		||||
 | 
			
		||||
  CellDataPersistence({
 | 
			
		||||
@ -35,7 +35,7 @@ class CalendarData with _$CalendarData {
 | 
			
		||||
  const factory CalendarData({required DateTime date, String? time}) = _CalendarData;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class DateCellDataPersistence implements _GridCellDataPersistence<CalendarData> {
 | 
			
		||||
class DateCellDataPersistence implements IGridCellDataPersistence<CalendarData> {
 | 
			
		||||
  final GridCell gridCell;
 | 
			
		||||
  DateCellDataPersistence({
 | 
			
		||||
    required this.gridCell,
 | 
			
		||||
 | 
			
		||||
@ -0,0 +1,56 @@
 | 
			
		||||
import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pb.dart';
 | 
			
		||||
import 'package:flutter/foundation.dart';
 | 
			
		||||
 | 
			
		||||
import 'cell_service.dart';
 | 
			
		||||
 | 
			
		||||
abstract class GridFieldChangedNotifier {
 | 
			
		||||
  void onFieldChanged(void Function(Field) callback);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class GridCellFieldNotifier {
 | 
			
		||||
  /// fieldId: {objectId: callback}
 | 
			
		||||
  final Map<String, Map<String, List<VoidCallback>>> _fieldListenerByFieldId = {};
 | 
			
		||||
 | 
			
		||||
  GridCellFieldNotifier({required GridFieldChangedNotifier notifier}) {
 | 
			
		||||
    notifier.onFieldChanged(
 | 
			
		||||
      (field) {
 | 
			
		||||
        final map = _fieldListenerByFieldId[field.id];
 | 
			
		||||
        if (map != null) {
 | 
			
		||||
          for (final callbacks in map.values) {
 | 
			
		||||
            for (final callback in callbacks) {
 | 
			
		||||
              callback();
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  void addFieldListener(GridCellCacheKey cacheKey, VoidCallback onFieldChanged) {
 | 
			
		||||
    var map = _fieldListenerByFieldId[cacheKey.fieldId];
 | 
			
		||||
    if (map == null) {
 | 
			
		||||
      _fieldListenerByFieldId[cacheKey.fieldId] = {};
 | 
			
		||||
      map = _fieldListenerByFieldId[cacheKey.fieldId];
 | 
			
		||||
      map![cacheKey.rowId] = [onFieldChanged];
 | 
			
		||||
    } else {
 | 
			
		||||
      var objects = map[cacheKey.rowId];
 | 
			
		||||
      if (objects == null) {
 | 
			
		||||
        map[cacheKey.rowId] = [onFieldChanged];
 | 
			
		||||
      } else {
 | 
			
		||||
        objects.add(onFieldChanged);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  void removeFieldListener(GridCellCacheKey cacheKey, VoidCallback fn) {
 | 
			
		||||
    var callbacks = _fieldListenerByFieldId[cacheKey.fieldId]?[cacheKey.rowId];
 | 
			
		||||
    final index = callbacks?.indexWhere((callback) => callback == fn);
 | 
			
		||||
    if (index != null && index != -1) {
 | 
			
		||||
      callbacks?.removeAt(index);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  Future<void> dispose() async {
 | 
			
		||||
    _fieldListenerByFieldId.clear();
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@ -14,7 +14,6 @@ import 'package:flowy_sdk/protobuf/flowy-grid/url_type_option.pb.dart';
 | 
			
		||||
import 'package:flutter/foundation.dart';
 | 
			
		||||
import 'package:freezed_annotation/freezed_annotation.dart';
 | 
			
		||||
import 'package:app_flowy/workspace/application/grid/cell/cell_listener.dart';
 | 
			
		||||
import 'package:app_flowy/workspace/application/grid/cell/select_option_service.dart';
 | 
			
		||||
import 'package:app_flowy/workspace/application/grid/field/field_service.dart';
 | 
			
		||||
import 'dart:convert' show utf8;
 | 
			
		||||
part 'cell_service.freezed.dart';
 | 
			
		||||
 | 
			
		||||
@ -6,15 +6,19 @@ typedef GridDateCellContext = _GridCellContext<DateCellData, CalendarData>;
 | 
			
		||||
typedef GridURLCellContext = _GridCellContext<URLCellData, String>;
 | 
			
		||||
 | 
			
		||||
class GridCellContextBuilder {
 | 
			
		||||
  final GridCellCacheService _cellCache;
 | 
			
		||||
  final GridCell _gridCell;
 | 
			
		||||
  GridCellContextBuilder({
 | 
			
		||||
    required GridCellCacheService cellCache,
 | 
			
		||||
    required GridCell gridCell,
 | 
			
		||||
  })  : _cellCache = cellCache,
 | 
			
		||||
  final GridCellsCache _cellCache;
 | 
			
		||||
  final GridFieldCache _fieldCache;
 | 
			
		||||
 | 
			
		||||
  GridCellContextBuilder(
 | 
			
		||||
      {required GridCell gridCell, required GridCellsCache cellCache, required GridFieldCache fieldCache})
 | 
			
		||||
      : _cellCache = cellCache,
 | 
			
		||||
        _fieldCache = fieldCache,
 | 
			
		||||
        _gridCell = gridCell;
 | 
			
		||||
 | 
			
		||||
  _GridCellContext build() {
 | 
			
		||||
    final cellFieldNotifier = GridCellFieldNotifier(notifier: _GridFieldChangedNotifierImpl(_fieldCache));
 | 
			
		||||
 | 
			
		||||
    switch (_gridCell.field.fieldType) {
 | 
			
		||||
      case FieldType.Checkbox:
 | 
			
		||||
        final cellDataLoader = GridCellDataLoader(
 | 
			
		||||
@ -25,6 +29,7 @@ class GridCellContextBuilder {
 | 
			
		||||
          gridCell: _gridCell,
 | 
			
		||||
          cellCache: _cellCache,
 | 
			
		||||
          cellDataLoader: cellDataLoader,
 | 
			
		||||
          cellFieldNotifier: cellFieldNotifier,
 | 
			
		||||
          cellDataPersistence: CellDataPersistence(gridCell: _gridCell),
 | 
			
		||||
        );
 | 
			
		||||
      case FieldType.DateTime:
 | 
			
		||||
@ -38,18 +43,20 @@ class GridCellContextBuilder {
 | 
			
		||||
          gridCell: _gridCell,
 | 
			
		||||
          cellCache: _cellCache,
 | 
			
		||||
          cellDataLoader: cellDataLoader,
 | 
			
		||||
          cellFieldNotifier: cellFieldNotifier,
 | 
			
		||||
          cellDataPersistence: DateCellDataPersistence(gridCell: _gridCell),
 | 
			
		||||
        );
 | 
			
		||||
      case FieldType.Number:
 | 
			
		||||
        final cellDataLoader = GridCellDataLoader(
 | 
			
		||||
          gridCell: _gridCell,
 | 
			
		||||
          parser: StringCellDataParser(),
 | 
			
		||||
          config: const GridCellDataConfig(reloadOnCellChanged: true, reloadOnFieldChanged: true),
 | 
			
		||||
          config: const GridCellDataConfig(reloadOnFieldChanged: true),
 | 
			
		||||
        );
 | 
			
		||||
        return GridCellContext(
 | 
			
		||||
          gridCell: _gridCell,
 | 
			
		||||
          cellCache: _cellCache,
 | 
			
		||||
          cellDataLoader: cellDataLoader,
 | 
			
		||||
          cellFieldNotifier: cellFieldNotifier,
 | 
			
		||||
          cellDataPersistence: CellDataPersistence(gridCell: _gridCell),
 | 
			
		||||
        );
 | 
			
		||||
      case FieldType.RichText:
 | 
			
		||||
@ -61,6 +68,7 @@ class GridCellContextBuilder {
 | 
			
		||||
          gridCell: _gridCell,
 | 
			
		||||
          cellCache: _cellCache,
 | 
			
		||||
          cellDataLoader: cellDataLoader,
 | 
			
		||||
          cellFieldNotifier: cellFieldNotifier,
 | 
			
		||||
          cellDataPersistence: CellDataPersistence(gridCell: _gridCell),
 | 
			
		||||
        );
 | 
			
		||||
      case FieldType.MultiSelect:
 | 
			
		||||
@ -75,6 +83,7 @@ class GridCellContextBuilder {
 | 
			
		||||
          gridCell: _gridCell,
 | 
			
		||||
          cellCache: _cellCache,
 | 
			
		||||
          cellDataLoader: cellDataLoader,
 | 
			
		||||
          cellFieldNotifier: cellFieldNotifier,
 | 
			
		||||
          cellDataPersistence: CellDataPersistence(gridCell: _gridCell),
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
@ -87,6 +96,7 @@ class GridCellContextBuilder {
 | 
			
		||||
          gridCell: _gridCell,
 | 
			
		||||
          cellCache: _cellCache,
 | 
			
		||||
          cellDataLoader: cellDataLoader,
 | 
			
		||||
          cellFieldNotifier: cellFieldNotifier,
 | 
			
		||||
          cellDataPersistence: CellDataPersistence(gridCell: _gridCell),
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
@ -99,14 +109,17 @@ class GridCellContextBuilder {
 | 
			
		||||
// ignore: must_be_immutable
 | 
			
		||||
class _GridCellContext<T, D> extends Equatable {
 | 
			
		||||
  final GridCell gridCell;
 | 
			
		||||
  final GridCellCacheService cellCache;
 | 
			
		||||
  final _GridCellCacheKey _cacheKey;
 | 
			
		||||
  final IGridCellDataLoader<T> cellDataLoader;
 | 
			
		||||
  final _GridCellDataPersistence<D> cellDataPersistence;
 | 
			
		||||
  final GridCellsCache _cellsCache;
 | 
			
		||||
  final GridCellCacheKey _cacheKey;
 | 
			
		||||
  final FieldService _fieldService;
 | 
			
		||||
  final GridCellFieldNotifier _cellFieldNotifier;
 | 
			
		||||
  // final GridCellFieldNotifier _fieldNotifier;
 | 
			
		||||
  final IGridCellDataLoader<T> _cellDataLoader;
 | 
			
		||||
  final IGridCellDataPersistence<D> _cellDataPersistence;
 | 
			
		||||
 | 
			
		||||
  late final CellListener _cellListener;
 | 
			
		||||
  late final ValueNotifier<T?>? _cellDataNotifier;
 | 
			
		||||
 | 
			
		||||
  bool isListening = false;
 | 
			
		||||
  VoidCallback? _onFieldChangedFn;
 | 
			
		||||
  Timer? _loadDataOperation;
 | 
			
		||||
@ -114,18 +127,25 @@ class _GridCellContext<T, D> extends Equatable {
 | 
			
		||||
 | 
			
		||||
  _GridCellContext({
 | 
			
		||||
    required this.gridCell,
 | 
			
		||||
    required this.cellCache,
 | 
			
		||||
    required this.cellDataLoader,
 | 
			
		||||
    required this.cellDataPersistence,
 | 
			
		||||
  })  : _fieldService = FieldService(gridId: gridCell.gridId, fieldId: gridCell.field.id),
 | 
			
		||||
        _cacheKey = _GridCellCacheKey(rowId: gridCell.rowId, fieldId: gridCell.field.id);
 | 
			
		||||
    required GridCellsCache cellCache,
 | 
			
		||||
    required GridCellFieldNotifier cellFieldNotifier,
 | 
			
		||||
    required IGridCellDataLoader<T> cellDataLoader,
 | 
			
		||||
    required IGridCellDataPersistence<D> cellDataPersistence,
 | 
			
		||||
    // required GridFieldChangedNotifier notifierDelegate,
 | 
			
		||||
  })  : _cellsCache = cellCache,
 | 
			
		||||
        _cellDataLoader = cellDataLoader,
 | 
			
		||||
        _cellDataPersistence = cellDataPersistence,
 | 
			
		||||
        _cellFieldNotifier = cellFieldNotifier,
 | 
			
		||||
        _fieldService = FieldService(gridId: gridCell.gridId, fieldId: gridCell.field.id),
 | 
			
		||||
        _cacheKey = GridCellCacheKey(rowId: gridCell.rowId, fieldId: gridCell.field.id);
 | 
			
		||||
 | 
			
		||||
  _GridCellContext<T, D> clone() {
 | 
			
		||||
    return _GridCellContext(
 | 
			
		||||
        gridCell: gridCell,
 | 
			
		||||
        cellDataLoader: cellDataLoader,
 | 
			
		||||
        cellCache: cellCache,
 | 
			
		||||
        cellDataPersistence: cellDataPersistence);
 | 
			
		||||
        cellDataLoader: _cellDataLoader,
 | 
			
		||||
        cellCache: _cellsCache,
 | 
			
		||||
        cellFieldNotifier: _cellFieldNotifier,
 | 
			
		||||
        cellDataPersistence: _cellDataPersistence);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  String get gridId => gridCell.gridId;
 | 
			
		||||
@ -145,10 +165,18 @@ class _GridCellContext<T, D> extends Equatable {
 | 
			
		||||
      Log.error("Already started. It seems like you should call clone first");
 | 
			
		||||
      return null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    isListening = true;
 | 
			
		||||
    _cellDataNotifier = ValueNotifier(cellCache.get(_cacheKey));
 | 
			
		||||
 | 
			
		||||
    /// The cell data will be changed by two reasons:
 | 
			
		||||
    /// 1. User edit the cell
 | 
			
		||||
    /// 2. User edit the field
 | 
			
		||||
    ///   For example: The number cell reload the cell data that carries the format
 | 
			
		||||
    ///   user input: 12
 | 
			
		||||
    ///   cell display: $12
 | 
			
		||||
    _cellDataNotifier = ValueNotifier(_cellsCache.get(_cacheKey));
 | 
			
		||||
    _cellListener = CellListener(rowId: gridCell.rowId, fieldId: gridCell.field.id);
 | 
			
		||||
 | 
			
		||||
    /// Listen on user edit event and load the new cell data if needed.
 | 
			
		||||
    _cellListener.start(onCellChanged: (result) {
 | 
			
		||||
      result.fold(
 | 
			
		||||
        (_) => _loadData(),
 | 
			
		||||
@ -156,21 +184,14 @@ class _GridCellContext<T, D> extends Equatable {
 | 
			
		||||
      );
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    if (cellDataLoader.config.reloadOnFieldChanged) {
 | 
			
		||||
      _onFieldChangedFn = () {
 | 
			
		||||
        _loadData();
 | 
			
		||||
      };
 | 
			
		||||
      cellCache.addFieldListener(_cacheKey, _onFieldChangedFn!);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    onCellChangedFn() {
 | 
			
		||||
      onCellChanged(_cellDataNotifier?.value);
 | 
			
		||||
 | 
			
		||||
      if (cellDataLoader.config.reloadOnCellChanged) {
 | 
			
		||||
        _loadData();
 | 
			
		||||
      }
 | 
			
		||||
    /// Listen on the field event and load the cell data if needed.
 | 
			
		||||
    if (_cellDataLoader.config.reloadOnFieldChanged) {
 | 
			
		||||
      _onFieldChangedFn = () => _loadData();
 | 
			
		||||
      _cellFieldNotifier.addFieldListener(_cacheKey, _onFieldChangedFn!);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Notify the listener, the cell data was changed.
 | 
			
		||||
    onCellChangedFn() => onCellChanged(_cellDataNotifier?.value);
 | 
			
		||||
    _cellDataNotifier?.addListener(onCellChangedFn);
 | 
			
		||||
    return onCellChangedFn;
 | 
			
		||||
  }
 | 
			
		||||
@ -180,7 +201,7 @@ class _GridCellContext<T, D> extends Equatable {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  T? getCellData({bool loadIfNoCache = true}) {
 | 
			
		||||
    final data = cellCache.get(_cacheKey);
 | 
			
		||||
    final data = _cellsCache.get(_cacheKey);
 | 
			
		||||
    if (data == null && loadIfNoCache) {
 | 
			
		||||
      _loadData();
 | 
			
		||||
    }
 | 
			
		||||
@ -195,13 +216,13 @@ class _GridCellContext<T, D> extends Equatable {
 | 
			
		||||
    if (deduplicate) {
 | 
			
		||||
      _loadDataOperation?.cancel();
 | 
			
		||||
      _loadDataOperation = Timer(const Duration(milliseconds: 300), () async {
 | 
			
		||||
        final result = await cellDataPersistence.save(data);
 | 
			
		||||
        final result = await _cellDataPersistence.save(data);
 | 
			
		||||
        if (resultCallback != null) {
 | 
			
		||||
          resultCallback(result);
 | 
			
		||||
        }
 | 
			
		||||
      });
 | 
			
		||||
    } else {
 | 
			
		||||
      final result = await cellDataPersistence.save(data);
 | 
			
		||||
      final result = await _cellDataPersistence.save(data);
 | 
			
		||||
      if (resultCallback != null) {
 | 
			
		||||
        resultCallback(result);
 | 
			
		||||
      }
 | 
			
		||||
@ -211,9 +232,9 @@ class _GridCellContext<T, D> extends Equatable {
 | 
			
		||||
  void _loadData() {
 | 
			
		||||
    _loadDataOperation?.cancel();
 | 
			
		||||
    _loadDataOperation = Timer(const Duration(milliseconds: 10), () {
 | 
			
		||||
      cellDataLoader.loadData().then((data) {
 | 
			
		||||
      _cellDataLoader.loadData().then((data) {
 | 
			
		||||
        _cellDataNotifier?.value = data;
 | 
			
		||||
        cellCache.insert(_GridCellCacheObject(key: _cacheKey, object: data));
 | 
			
		||||
        _cellsCache.insert(_GridCellCacheObject(key: _cacheKey, object: data));
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
@ -224,11 +245,36 @@ class _GridCellContext<T, D> extends Equatable {
 | 
			
		||||
    _saveDataOperation?.cancel();
 | 
			
		||||
 | 
			
		||||
    if (_onFieldChangedFn != null) {
 | 
			
		||||
      cellCache.removeFieldListener(_cacheKey, _onFieldChangedFn!);
 | 
			
		||||
      _cellFieldNotifier.removeFieldListener(_cacheKey, _onFieldChangedFn!);
 | 
			
		||||
      _onFieldChangedFn = null;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  List<Object> get props => [cellCache.get(_cacheKey) ?? "", cellId];
 | 
			
		||||
  List<Object> get props => [_cellsCache.get(_cacheKey) ?? "", cellId];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class _GridFieldChangedNotifierImpl extends GridFieldChangedNotifier {
 | 
			
		||||
  final GridFieldCache _cache;
 | 
			
		||||
  FieldChangesetCallback? _onChangesetFn;
 | 
			
		||||
 | 
			
		||||
  _GridFieldChangedNotifierImpl(GridFieldCache cache) : _cache = cache;
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  void dispose() {
 | 
			
		||||
    if (_onChangesetFn != null) {
 | 
			
		||||
      _cache.removeListener(onChangsetListener: _onChangesetFn!);
 | 
			
		||||
      _onChangesetFn = null;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  void onFieldChanged(void Function(Field p1) callback) {
 | 
			
		||||
    _onChangesetFn = (GridFieldChangeset changeset) {
 | 
			
		||||
      for (final updatedField in changeset.updatedFields) {
 | 
			
		||||
        callback(updatedField);
 | 
			
		||||
      }
 | 
			
		||||
    };
 | 
			
		||||
    _cache.addListener(onChangeset: _onChangesetFn);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -68,7 +68,7 @@ class GridBloc extends Bloc<GridEvent, GridState> {
 | 
			
		||||
    return super.close();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  GridRowCacheService? getRowCache(String blockId, String rowId) {
 | 
			
		||||
  GridRowsCache? getRowCache(String blockId, String rowId) {
 | 
			
		||||
    final GridBlockCacheService? blockCache = _blocks[blockId];
 | 
			
		||||
    return blockCache?.rowCache;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@ -202,7 +202,7 @@ class GridRowCacheDelegateImpl extends GridRowCacheDelegate {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  void onFieldUpdated(void Function(Field) callback) {
 | 
			
		||||
  void onFieldChanged(void Function(Field) callback) {
 | 
			
		||||
    _onChangesetFn = (GridFieldChangeset changeset) {
 | 
			
		||||
      for (final updatedField in changeset.updatedFields) {
 | 
			
		||||
        callback(updatedField);
 | 
			
		||||
 | 
			
		||||
@ -11,12 +11,12 @@ part 'row_bloc.freezed.dart';
 | 
			
		||||
 | 
			
		||||
class RowBloc extends Bloc<RowEvent, RowState> {
 | 
			
		||||
  final RowService _rowService;
 | 
			
		||||
  final GridRowCacheService _rowCache;
 | 
			
		||||
  final GridRowsCache _rowCache;
 | 
			
		||||
  void Function()? _rowListenFn;
 | 
			
		||||
 | 
			
		||||
  RowBloc({
 | 
			
		||||
    required GridRow rowData,
 | 
			
		||||
    required GridRowCacheService rowCache,
 | 
			
		||||
    required GridRowsCache rowCache,
 | 
			
		||||
  })  : _rowService = RowService(
 | 
			
		||||
          gridId: rowData.gridId,
 | 
			
		||||
          blockId: rowData.blockId,
 | 
			
		||||
 | 
			
		||||
@ -8,12 +8,12 @@ part 'row_detail_bloc.freezed.dart';
 | 
			
		||||
 | 
			
		||||
class RowDetailBloc extends Bloc<RowDetailEvent, RowDetailState> {
 | 
			
		||||
  final GridRow rowData;
 | 
			
		||||
  final GridRowCacheService _rowCache;
 | 
			
		||||
  final GridRowsCache _rowCache;
 | 
			
		||||
  void Function()? _rowListenFn;
 | 
			
		||||
 | 
			
		||||
  RowDetailBloc({
 | 
			
		||||
    required this.rowData,
 | 
			
		||||
    required GridRowCacheService rowCache,
 | 
			
		||||
    required GridRowsCache rowCache,
 | 
			
		||||
  })  : _rowCache = rowCache,
 | 
			
		||||
        super(RowDetailState.initial()) {
 | 
			
		||||
    on<RowDetailEvent>(
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,4 @@
 | 
			
		||||
import 'dart:collection';
 | 
			
		||||
 | 
			
		||||
import 'package:app_flowy/workspace/application/grid/cell/cell_service/cell_service.dart';
 | 
			
		||||
import 'package:dartz/dartz.dart';
 | 
			
		||||
import 'package:flowy_sdk/dispatch/dispatch.dart';
 | 
			
		||||
@ -15,34 +14,36 @@ part 'row_service.freezed.dart';
 | 
			
		||||
 | 
			
		||||
typedef RowUpdateCallback = void Function();
 | 
			
		||||
 | 
			
		||||
abstract class GridRowCacheDelegate with GridCellCacheDelegate {
 | 
			
		||||
abstract class GridRowCacheDelegate {
 | 
			
		||||
  UnmodifiableListView<Field> get fields;
 | 
			
		||||
  void onFieldsChanged(void Function() callback);
 | 
			
		||||
  void onFieldsChanged(VoidCallback callback);
 | 
			
		||||
  void onFieldChanged(void Function(Field) callback);
 | 
			
		||||
  void dispose();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class GridRowCacheService {
 | 
			
		||||
class GridRowsCache {
 | 
			
		||||
  final String gridId;
 | 
			
		||||
  final GridBlock block;
 | 
			
		||||
  final _Notifier _notifier;
 | 
			
		||||
  List<GridRow> _rows = [];
 | 
			
		||||
  final HashMap<String, Row> _rowByRowId;
 | 
			
		||||
  final GridRowCacheDelegate _delegate;
 | 
			
		||||
  final GridCellCacheService _cellCache;
 | 
			
		||||
  final GridCellsCache _cellCache;
 | 
			
		||||
 | 
			
		||||
  List<GridRow> get rows => _rows;
 | 
			
		||||
  GridCellCacheService get cellCache => _cellCache;
 | 
			
		||||
  GridCellsCache get cellCache => _cellCache;
 | 
			
		||||
 | 
			
		||||
  GridRowCacheService({
 | 
			
		||||
  GridRowsCache({
 | 
			
		||||
    required this.gridId,
 | 
			
		||||
    required this.block,
 | 
			
		||||
    required GridRowCacheDelegate delegate,
 | 
			
		||||
  })  : _cellCache = GridCellCacheService(gridId: gridId, delegate: delegate),
 | 
			
		||||
  })  : _cellCache = GridCellsCache(gridId: gridId),
 | 
			
		||||
        _rowByRowId = HashMap(),
 | 
			
		||||
        _notifier = _Notifier(),
 | 
			
		||||
        _delegate = delegate {
 | 
			
		||||
    //
 | 
			
		||||
    delegate.onFieldsChanged(() => _notifier.receive(const GridRowChangeReason.fieldDidChange()));
 | 
			
		||||
    delegate.onFieldChanged((field) => _cellCache.remove(field.id));
 | 
			
		||||
    _rows = block.rowInfos.map((rowInfo) => buildGridRow(rowInfo.rowId, rowInfo.height.toDouble())).toList();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,5 @@
 | 
			
		||||
import 'package:app_flowy/workspace/application/grid/cell/cell_service/cell_service.dart';
 | 
			
		||||
import 'package:app_flowy/workspace/application/grid/grid_service.dart';
 | 
			
		||||
import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pb.dart';
 | 
			
		||||
import 'package:flutter/services.dart';
 | 
			
		||||
import 'package:flutter/widgets.dart';
 | 
			
		||||
@ -12,10 +13,56 @@ import 'select_option_cell/select_option_cell.dart';
 | 
			
		||||
import 'text_cell.dart';
 | 
			
		||||
import 'url_cell/url_cell.dart';
 | 
			
		||||
 | 
			
		||||
GridCellWidget buildGridCellWidget(GridCell gridCell, GridCellCacheService cellCache, {GridCellStyle? style}) {
 | 
			
		||||
class GridCellBuilder {
 | 
			
		||||
  final GridCellsCache cellCache;
 | 
			
		||||
  final GridFieldCache fieldCache;
 | 
			
		||||
  GridCellBuilder({
 | 
			
		||||
    required this.cellCache,
 | 
			
		||||
    required this.fieldCache,
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  GridCellWidget build(GridCell cell, {GridCellStyle? style}) {
 | 
			
		||||
    final key = ValueKey(gridCell.cellId());
 | 
			
		||||
 | 
			
		||||
    final cellContextBuilder = GridCellContextBuilder(
 | 
			
		||||
      gridCell: gridCell,
 | 
			
		||||
      cellCache: cellCache,
 | 
			
		||||
      fieldCache: fieldCache,
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    switch (gridCell.field.fieldType) {
 | 
			
		||||
      case FieldType.Checkbox:
 | 
			
		||||
        return CheckboxCell(cellContextBuilder: cellContextBuilder, key: key);
 | 
			
		||||
      case FieldType.DateTime:
 | 
			
		||||
        return DateCell(cellContextBuilder: cellContextBuilder, key: key, style: style);
 | 
			
		||||
      case FieldType.SingleSelect:
 | 
			
		||||
        return SingleSelectCell(cellContextBuilder: cellContextBuilder, style: style, key: key);
 | 
			
		||||
      case FieldType.MultiSelect:
 | 
			
		||||
        return MultiSelectCell(cellContextBuilder: cellContextBuilder, style: style, key: key);
 | 
			
		||||
      case FieldType.Number:
 | 
			
		||||
        return NumberCell(cellContextBuilder: cellContextBuilder, key: key);
 | 
			
		||||
      case FieldType.RichText:
 | 
			
		||||
        return GridTextCell(cellContextBuilder: cellContextBuilder, style: style, key: key);
 | 
			
		||||
      case FieldType.URL:
 | 
			
		||||
        return GridURLCell(cellContextBuilder: cellContextBuilder, style: style, key: key);
 | 
			
		||||
    }
 | 
			
		||||
    throw UnimplementedError;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
GridCellWidget buildGridCellWidget(
 | 
			
		||||
  GridCell gridCell, {
 | 
			
		||||
  required GridCellsCache cellCache,
 | 
			
		||||
  required GridFieldCache fieldCache,
 | 
			
		||||
  GridCellStyle? style,
 | 
			
		||||
}) {
 | 
			
		||||
  final key = ValueKey(gridCell.cellId());
 | 
			
		||||
 | 
			
		||||
  final cellContextBuilder = GridCellContextBuilder(gridCell: gridCell, cellCache: cellCache);
 | 
			
		||||
  final cellContextBuilder = GridCellContextBuilder(
 | 
			
		||||
    gridCell: gridCell,
 | 
			
		||||
    cellCache: cellCache,
 | 
			
		||||
    fieldCache: fieldCache,
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
  switch (gridCell.field.fieldType) {
 | 
			
		||||
    case FieldType.Checkbox:
 | 
			
		||||
 | 
			
		||||
@ -10,19 +10,25 @@ import 'package:flutter/foundation.dart';
 | 
			
		||||
import 'package:flutter/material.dart';
 | 
			
		||||
import 'package:flutter_bloc/flutter_bloc.dart';
 | 
			
		||||
import 'package:provider/provider.dart';
 | 
			
		||||
import 'row_action_sheet.dart';
 | 
			
		||||
 | 
			
		||||
import 'row_action_sheet.dart';
 | 
			
		||||
import 'row_detail.dart';
 | 
			
		||||
 | 
			
		||||
class GridRowWidget extends StatefulWidget {
 | 
			
		||||
  final GridRow rowData;
 | 
			
		||||
  final GridRowCacheService rowCache;
 | 
			
		||||
  final GridRowsCache rowCache;
 | 
			
		||||
  final GridCellBuilder cellBuilder;
 | 
			
		||||
 | 
			
		||||
  const GridRowWidget({
 | 
			
		||||
  GridRowWidget({
 | 
			
		||||
    required this.rowData,
 | 
			
		||||
    required this.rowCache,
 | 
			
		||||
    required GridFieldCache fieldCache,
 | 
			
		||||
    Key? key,
 | 
			
		||||
  }) : super(key: key);
 | 
			
		||||
  })  : cellBuilder = GridCellBuilder(
 | 
			
		||||
          cellCache: rowCache.cellCache,
 | 
			
		||||
          fieldCache: fieldCache,
 | 
			
		||||
        ),
 | 
			
		||||
        super(key: key);
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  State<GridRowWidget> createState() => _GridRowWidgetState();
 | 
			
		||||
@ -52,7 +58,11 @@ class _GridRowWidgetState extends State<GridRowWidget> {
 | 
			
		||||
            return Row(
 | 
			
		||||
              children: [
 | 
			
		||||
                const _RowLeading(),
 | 
			
		||||
                Expanded(child: _RowCells(cellCache: widget.rowCache.cellCache, onExpand: () => _expandRow(context))),
 | 
			
		||||
                Expanded(
 | 
			
		||||
                    child: _RowCells(
 | 
			
		||||
                  builder: widget.cellBuilder,
 | 
			
		||||
                  onExpand: () => _expandRow(context),
 | 
			
		||||
                )),
 | 
			
		||||
                const _RowTrailing(),
 | 
			
		||||
              ],
 | 
			
		||||
            );
 | 
			
		||||
@ -72,6 +82,7 @@ class _GridRowWidgetState extends State<GridRowWidget> {
 | 
			
		||||
    final page = RowDetailPage(
 | 
			
		||||
      rowData: widget.rowData,
 | 
			
		||||
      rowCache: widget.rowCache,
 | 
			
		||||
      cellBuilder: widget.cellBuilder,
 | 
			
		||||
    );
 | 
			
		||||
    page.show(context);
 | 
			
		||||
  }
 | 
			
		||||
@ -146,9 +157,13 @@ class _DeleteRowButton extends StatelessWidget {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class _RowCells extends StatelessWidget {
 | 
			
		||||
  final GridCellCacheService cellCache;
 | 
			
		||||
  final VoidCallback onExpand;
 | 
			
		||||
  const _RowCells({required this.cellCache, required this.onExpand, Key? key}) : super(key: key);
 | 
			
		||||
  final GridCellBuilder builder;
 | 
			
		||||
  const _RowCells({
 | 
			
		||||
    required this.builder,
 | 
			
		||||
    required this.onExpand,
 | 
			
		||||
    Key? key,
 | 
			
		||||
  }) : super(key: key);
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  Widget build(BuildContext context) {
 | 
			
		||||
@ -169,8 +184,7 @@ class _RowCells extends StatelessWidget {
 | 
			
		||||
  List<Widget> _makeCells(BuildContext context, GridCellMap gridCellMap) {
 | 
			
		||||
    return gridCellMap.values.map(
 | 
			
		||||
      (gridCell) {
 | 
			
		||||
        final GridCellWidget child = buildGridCellWidget(gridCell, cellCache);
 | 
			
		||||
 | 
			
		||||
        final GridCellWidget child = builder.build(gridCell);
 | 
			
		||||
        accessoryBuilder(GridCellAccessoryBuildContext buildContext) {
 | 
			
		||||
          final builder = child.accessoryBuilder;
 | 
			
		||||
          List<GridCellAccessory> accessories = [];
 | 
			
		||||
 | 
			
		||||
@ -22,11 +22,13 @@ import 'package:flutter_bloc/flutter_bloc.dart';
 | 
			
		||||
 | 
			
		||||
class RowDetailPage extends StatefulWidget with FlowyOverlayDelegate {
 | 
			
		||||
  final GridRow rowData;
 | 
			
		||||
  final GridRowCacheService rowCache;
 | 
			
		||||
  final GridRowsCache rowCache;
 | 
			
		||||
  final GridCellBuilder cellBuilder;
 | 
			
		||||
 | 
			
		||||
  const RowDetailPage({
 | 
			
		||||
    required this.rowData,
 | 
			
		||||
    required this.rowCache,
 | 
			
		||||
    required this.cellBuilder,
 | 
			
		||||
    Key? key,
 | 
			
		||||
  }) : super(key: key);
 | 
			
		||||
 | 
			
		||||
@ -74,7 +76,7 @@ class _RowDetailPageState extends State<RowDetailPage> {
 | 
			
		||||
                children: const [Spacer(), _CloseButton()],
 | 
			
		||||
              ),
 | 
			
		||||
            ),
 | 
			
		||||
            Expanded(child: _PropertyList(cellCache: widget.rowCache.cellCache)),
 | 
			
		||||
            Expanded(child: _PropertyList(cellBuilder: widget.cellBuilder)),
 | 
			
		||||
          ],
 | 
			
		||||
        ),
 | 
			
		||||
      ),
 | 
			
		||||
@ -98,10 +100,10 @@ class _CloseButton extends StatelessWidget {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class _PropertyList extends StatelessWidget {
 | 
			
		||||
  final GridCellCacheService cellCache;
 | 
			
		||||
  final GridCellBuilder cellBuilder;
 | 
			
		||||
  final ScrollController _scrollController;
 | 
			
		||||
  _PropertyList({
 | 
			
		||||
    required this.cellCache,
 | 
			
		||||
    required this.cellBuilder,
 | 
			
		||||
    Key? key,
 | 
			
		||||
  })  : _scrollController = ScrollController(),
 | 
			
		||||
        super(key: key);
 | 
			
		||||
@ -121,7 +123,7 @@ class _PropertyList extends StatelessWidget {
 | 
			
		||||
            itemBuilder: (BuildContext context, int index) {
 | 
			
		||||
              return _RowDetailCell(
 | 
			
		||||
                gridCell: state.gridCells[index],
 | 
			
		||||
                cellCache: cellCache,
 | 
			
		||||
                cellBuilder: cellBuilder,
 | 
			
		||||
              );
 | 
			
		||||
            },
 | 
			
		||||
            separatorBuilder: (BuildContext context, int index) {
 | 
			
		||||
@ -136,10 +138,10 @@ class _PropertyList extends StatelessWidget {
 | 
			
		||||
 | 
			
		||||
class _RowDetailCell extends StatelessWidget {
 | 
			
		||||
  final GridCell gridCell;
 | 
			
		||||
  final GridCellCacheService cellCache;
 | 
			
		||||
  final GridCellBuilder cellBuilder;
 | 
			
		||||
  const _RowDetailCell({
 | 
			
		||||
    required this.gridCell,
 | 
			
		||||
    required this.cellCache,
 | 
			
		||||
    required this.cellBuilder,
 | 
			
		||||
    Key? key,
 | 
			
		||||
  }) : super(key: key);
 | 
			
		||||
 | 
			
		||||
@ -147,7 +149,7 @@ class _RowDetailCell extends StatelessWidget {
 | 
			
		||||
  Widget build(BuildContext context) {
 | 
			
		||||
    final theme = context.watch<AppTheme>();
 | 
			
		||||
    final style = _customCellStyle(theme, gridCell.field.fieldType);
 | 
			
		||||
    final cell = buildGridCellWidget(gridCell, cellCache, style: style);
 | 
			
		||||
    final cell = cellBuilder.build(gridCell, style: style);
 | 
			
		||||
 | 
			
		||||
    final gesture = GestureDetector(
 | 
			
		||||
      behavior: HitTestBehavior.translucent,
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user