chore: renmae property & add documentation

This commit is contained in:
appflowy
2022-07-16 15:38:38 +08:00
parent a73987456e
commit 29f2d863ff
24 changed files with 190 additions and 189 deletions

View File

@ -6,21 +6,22 @@ import 'package:flowy_sdk/protobuf/flowy-grid/block_entities.pb.dart';
import 'block_listener.dart'; import 'block_listener.dart';
/// Read https://appflowy.gitbook.io/docs/essential-documentation/contribute-to-appflowy/architecture/frontend/grid for more information
class GridBlockCache { class GridBlockCache {
final String gridId; final String gridId;
final GridBlock block; final GridBlock block;
late GridRowsCache _rowCache; late GridRowCache _rowCache;
late GridBlockListener _listener; late GridBlockListener _listener;
List<GridRow> get rows => _rowCache.rows; List<GridRow> get rows => _rowCache.rows;
GridRowsCache get rowCache => _rowCache; GridRowCache get rowCache => _rowCache;
GridBlockCache({ GridBlockCache({
required this.gridId, required this.gridId,
required this.block, required this.block,
required GridFieldCache fieldCache, required GridFieldCache fieldCache,
}) { }) {
_rowCache = GridRowsCache( _rowCache = GridRowCache(
gridId: gridId, gridId: gridId,
block: block, block: block,
notifier: GridRowCacheFieldNotifierImpl(fieldCache), notifier: GridRowCacheFieldNotifierImpl(fieldCache),

View File

@ -2,11 +2,9 @@ part of 'cell_service.dart';
typedef GridCellMap = LinkedHashMap<String, GridCellIdentifier>; typedef GridCellMap = LinkedHashMap<String, GridCellIdentifier>;
class _GridCellCacheValue { class GridCell {
GridCellCacheKey key;
dynamic object; dynamic object;
_GridCellCacheValue({ GridCell({
required this.key,
required this.object, required this.object,
}); });
} }
@ -22,14 +20,16 @@ class GridCellCacheKey {
}); });
} }
/// GridCellsCache is used to cache cell data of each Grid. /// GridCellCache is used to cache cell data of each block.
/// We use GridCellCacheKey to index the cell in the cache. /// We use GridCellCacheKey to index the cell in the cache.
class GridCellsCache { /// Read https://appflowy.gitbook.io/docs/essential-documentation/contribute-to-appflowy/architecture/frontend/grid
/// for more information
class GridCellCache {
final String gridId; final String gridId;
/// fieldId: {cacheKey: cacheData} /// fieldId: {cacheKey: GridCell}
final Map<String, Map<String, dynamic>> _cellDataByFieldId = {}; final Map<String, Map<String, dynamic>> _cellDataByFieldId = {};
GridCellsCache({ GridCellCache({
required this.gridId, required this.gridId,
}); });
@ -37,14 +37,14 @@ class GridCellsCache {
_cellDataByFieldId.remove(fieldId); _cellDataByFieldId.remove(fieldId);
} }
void insert<T extends _GridCellCacheValue>(T value) { void insert<T extends GridCell>(GridCellCacheKey key, T value) {
var map = _cellDataByFieldId[value.key.fieldId]; var map = _cellDataByFieldId[key.fieldId];
if (map == null) { if (map == null) {
_cellDataByFieldId[value.key.fieldId] = {}; _cellDataByFieldId[key.fieldId] = {};
map = _cellDataByFieldId[value.key.fieldId]; map = _cellDataByFieldId[key.fieldId];
} }
map![value.key.rowId] = value.object; map![key.rowId] = value.object;
} }
T? get<T>(GridCellCacheKey key) { T? get<T>(GridCellCacheKey key) {

View File

@ -11,22 +11,18 @@ abstract class ICellDataParser<T> {
class GridCellDataLoader<T> { class GridCellDataLoader<T> {
final CellService service = CellService(); final CellService service = CellService();
final GridCellIdentifier gridCell; final GridCellIdentifier cellId;
final ICellDataParser<T> parser; final ICellDataParser<T> parser;
final bool reloadOnFieldChanged; final bool reloadOnFieldChanged;
GridCellDataLoader({ GridCellDataLoader({
required this.gridCell, required this.cellId,
required this.parser, required this.parser,
this.reloadOnFieldChanged = false, this.reloadOnFieldChanged = false,
}); });
Future<T?> loadData() { Future<T?> loadData() {
final fut = service.getCell( final fut = service.getCell(cellId: cellId);
gridId: gridCell.gridId,
fieldId: gridCell.field.id,
rowId: gridCell.rowId,
);
return fut.then( return fut.then(
(result) => result.fold((Cell cell) { (result) => result.fold((Cell cell) {
try { try {

View File

@ -7,21 +7,16 @@ abstract class IGridCellDataPersistence<D> {
} }
class CellDataPersistence implements IGridCellDataPersistence<String> { class CellDataPersistence implements IGridCellDataPersistence<String> {
final GridCellIdentifier gridCell; final GridCellIdentifier cellId;
CellDataPersistence({ CellDataPersistence({
required this.gridCell, required this.cellId,
}); });
final CellService _cellService = CellService(); final CellService _cellService = CellService();
@override @override
Future<Option<FlowyError>> save(String data) async { Future<Option<FlowyError>> save(String data) async {
final fut = _cellService.updateCell( final fut = _cellService.updateCell(cellId: cellId, data: data);
gridId: gridCell.gridId,
fieldId: gridCell.field.id,
rowId: gridCell.rowId,
data: data,
);
return fut.then((result) { return fut.then((result) {
return result.fold( return result.fold(
@ -38,14 +33,14 @@ class CalendarData with _$CalendarData {
} }
class DateCellDataPersistence implements IGridCellDataPersistence<CalendarData> { class DateCellDataPersistence implements IGridCellDataPersistence<CalendarData> {
final GridCellIdentifier gridCell; final GridCellIdentifier cellId;
DateCellDataPersistence({ DateCellDataPersistence({
required this.gridCell, required this.cellId,
}); });
@override @override
Future<Option<FlowyError>> save(CalendarData data) { Future<Option<FlowyError>> save(CalendarData data) {
var payload = DateChangesetPayload.create()..cellIdentifier = _cellIdentifier(gridCell); var payload = DateChangesetPayload.create()..cellIdentifier = _makeCellIdPayload(cellId);
final date = (data.date.millisecondsSinceEpoch ~/ 1000).toString(); final date = (data.date.millisecondsSinceEpoch ~/ 1000).toString();
payload.date = date; payload.date = date;
@ -63,9 +58,9 @@ class DateCellDataPersistence implements IGridCellDataPersistence<CalendarData>
} }
} }
CellIdentifierPayload _cellIdentifier(GridCellIdentifier gridCell) { CellIdentifierPayload _makeCellIdPayload(GridCellIdentifier cellId) {
return CellIdentifierPayload.create() return CellIdentifierPayload.create()
..gridId = gridCell.gridId ..gridId = cellId.gridId
..fieldId = gridCell.field.id ..fieldId = cellId.fieldId
..rowId = gridCell.rowId; ..rowId = cellId.rowId;
} }

View File

@ -23,7 +23,7 @@ import 'cell_field_notifier.dart';
part 'cell_service.freezed.dart'; part 'cell_service.freezed.dart';
part 'cell_data_loader.dart'; part 'cell_data_loader.dart';
part 'context_builder.dart'; part 'context_builder.dart';
part 'cache.dart'; part 'cell_cache.dart';
part 'cell_data_persistence.dart'; part 'cell_data_persistence.dart';
// key: rowId // key: rowId
@ -32,28 +32,24 @@ class CellService {
CellService(); CellService();
Future<Either<void, FlowyError>> updateCell({ Future<Either<void, FlowyError>> updateCell({
required String gridId, required GridCellIdentifier cellId,
required String fieldId,
required String rowId,
required String data, required String data,
}) { }) {
final payload = CellChangeset.create() final payload = CellChangeset.create()
..gridId = gridId ..gridId = cellId.gridId
..fieldId = fieldId ..fieldId = cellId.fieldId
..rowId = rowId ..rowId = cellId.rowId
..content = data; ..content = data;
return GridEventUpdateCell(payload).send(); return GridEventUpdateCell(payload).send();
} }
Future<Either<Cell, FlowyError>> getCell({ Future<Either<Cell, FlowyError>> getCell({
required String gridId, required GridCellIdentifier cellId,
required String fieldId,
required String rowId,
}) { }) {
final payload = CellIdentifierPayload.create() final payload = CellIdentifierPayload.create()
..gridId = gridId ..gridId = cellId.gridId
..fieldId = fieldId ..fieldId = cellId.fieldId
..rowId = rowId; ..rowId = cellId.rowId;
return GridEventGetCell(payload).send(); return GridEventGetCell(payload).send();
} }
} }
@ -71,7 +67,11 @@ class GridCellIdentifier with _$GridCellIdentifier {
// ignore: unused_element // ignore: unused_element
const GridCellIdentifier._(); const GridCellIdentifier._();
String get fieldId => field.id;
FieldType get fieldType => field.fieldType;
ValueKey key() { ValueKey key() {
return ValueKey(rowId + field.id + "${field.fieldType}"); return ValueKey(rowId + fieldId + "${field.fieldType}");
} }
} }

View File

@ -6,97 +6,99 @@ typedef GridDateCellController = IGridCellController<DateCellData, CalendarData>
typedef GridURLCellController = IGridCellController<URLCellData, String>; typedef GridURLCellController = IGridCellController<URLCellData, String>;
class GridCellControllerBuilder { class GridCellControllerBuilder {
final GridCellIdentifier _gridCell; final GridCellIdentifier _cellId;
final GridCellsCache _cellCache; final GridCellCache _cellCache;
final GridFieldCache _fieldCache; final GridFieldCache _fieldCache;
GridCellControllerBuilder( GridCellControllerBuilder({
{required GridCellIdentifier gridCell, required GridCellsCache cellCache, required GridFieldCache fieldCache}) required GridCellIdentifier cellId,
: _cellCache = cellCache, required GridCellCache cellCache,
required GridFieldCache fieldCache,
}) : _cellCache = cellCache,
_fieldCache = fieldCache, _fieldCache = fieldCache,
_gridCell = gridCell; _cellId = cellId;
IGridCellController build() { IGridCellController build() {
final cellFieldNotifier = GridCellFieldNotifier(notifier: _GridFieldChangedNotifierImpl(_fieldCache)); final cellFieldNotifier = GridCellFieldNotifier(notifier: _GridFieldChangedNotifierImpl(_fieldCache));
switch (_gridCell.field.fieldType) { switch (_cellId.fieldType) {
case FieldType.Checkbox: case FieldType.Checkbox:
final cellDataLoader = GridCellDataLoader( final cellDataLoader = GridCellDataLoader(
gridCell: _gridCell, cellId: _cellId,
parser: StringCellDataParser(), parser: StringCellDataParser(),
); );
return GridCellController( return GridCellController(
gridCell: _gridCell, cellId: _cellId,
cellCache: _cellCache, cellCache: _cellCache,
cellDataLoader: cellDataLoader, cellDataLoader: cellDataLoader,
fieldNotifier: cellFieldNotifier, fieldNotifier: cellFieldNotifier,
cellDataPersistence: CellDataPersistence(gridCell: _gridCell), cellDataPersistence: CellDataPersistence(cellId: _cellId),
); );
case FieldType.DateTime: case FieldType.DateTime:
final cellDataLoader = GridCellDataLoader( final cellDataLoader = GridCellDataLoader(
gridCell: _gridCell, cellId: _cellId,
parser: DateCellDataParser(), parser: DateCellDataParser(),
reloadOnFieldChanged: true, reloadOnFieldChanged: true,
); );
return GridDateCellController( return GridDateCellController(
gridCell: _gridCell, cellId: _cellId,
cellCache: _cellCache, cellCache: _cellCache,
cellDataLoader: cellDataLoader, cellDataLoader: cellDataLoader,
fieldNotifier: cellFieldNotifier, fieldNotifier: cellFieldNotifier,
cellDataPersistence: DateCellDataPersistence(gridCell: _gridCell), cellDataPersistence: DateCellDataPersistence(cellId: _cellId),
); );
case FieldType.Number: case FieldType.Number:
final cellDataLoader = GridCellDataLoader( final cellDataLoader = GridCellDataLoader(
gridCell: _gridCell, cellId: _cellId,
parser: StringCellDataParser(), parser: StringCellDataParser(),
); );
return GridCellController( return GridCellController(
gridCell: _gridCell, cellId: _cellId,
cellCache: _cellCache, cellCache: _cellCache,
cellDataLoader: cellDataLoader, cellDataLoader: cellDataLoader,
fieldNotifier: cellFieldNotifier, fieldNotifier: cellFieldNotifier,
cellDataPersistence: CellDataPersistence(gridCell: _gridCell), cellDataPersistence: CellDataPersistence(cellId: _cellId),
); );
case FieldType.RichText: case FieldType.RichText:
final cellDataLoader = GridCellDataLoader( final cellDataLoader = GridCellDataLoader(
gridCell: _gridCell, cellId: _cellId,
parser: StringCellDataParser(), parser: StringCellDataParser(),
); );
return GridCellController( return GridCellController(
gridCell: _gridCell, cellId: _cellId,
cellCache: _cellCache, cellCache: _cellCache,
cellDataLoader: cellDataLoader, cellDataLoader: cellDataLoader,
fieldNotifier: cellFieldNotifier, fieldNotifier: cellFieldNotifier,
cellDataPersistence: CellDataPersistence(gridCell: _gridCell), cellDataPersistence: CellDataPersistence(cellId: _cellId),
); );
case FieldType.MultiSelect: case FieldType.MultiSelect:
case FieldType.SingleSelect: case FieldType.SingleSelect:
final cellDataLoader = GridCellDataLoader( final cellDataLoader = GridCellDataLoader(
gridCell: _gridCell, cellId: _cellId,
parser: SelectOptionCellDataParser(), parser: SelectOptionCellDataParser(),
reloadOnFieldChanged: true, reloadOnFieldChanged: true,
); );
return GridSelectOptionCellController( return GridSelectOptionCellController(
gridCell: _gridCell, cellId: _cellId,
cellCache: _cellCache, cellCache: _cellCache,
cellDataLoader: cellDataLoader, cellDataLoader: cellDataLoader,
fieldNotifier: cellFieldNotifier, fieldNotifier: cellFieldNotifier,
cellDataPersistence: CellDataPersistence(gridCell: _gridCell), cellDataPersistence: CellDataPersistence(cellId: _cellId),
); );
case FieldType.URL: case FieldType.URL:
final cellDataLoader = GridCellDataLoader( final cellDataLoader = GridCellDataLoader(
gridCell: _gridCell, cellId: _cellId,
parser: URLCellDataParser(), parser: URLCellDataParser(),
); );
return GridURLCellController( return GridURLCellController(
gridCell: _gridCell, cellId: _cellId,
cellCache: _cellCache, cellCache: _cellCache,
cellDataLoader: cellDataLoader, cellDataLoader: cellDataLoader,
fieldNotifier: cellFieldNotifier, fieldNotifier: cellFieldNotifier,
cellDataPersistence: CellDataPersistence(gridCell: _gridCell), cellDataPersistence: CellDataPersistence(cellId: _cellId),
); );
} }
throw UnimplementedError; throw UnimplementedError;
@ -112,8 +114,8 @@ class GridCellControllerBuilder {
/// ///
// ignore: must_be_immutable // ignore: must_be_immutable
class IGridCellController<T, D> extends Equatable { class IGridCellController<T, D> extends Equatable {
final GridCellIdentifier gridCell; final GridCellIdentifier cellId;
final GridCellsCache _cellsCache; final GridCellCache _cellsCache;
final GridCellCacheKey _cacheKey; final GridCellCacheKey _cacheKey;
final FieldService _fieldService; final FieldService _fieldService;
final GridCellFieldNotifier _fieldNotifier; final GridCellFieldNotifier _fieldNotifier;
@ -130,8 +132,8 @@ class IGridCellController<T, D> extends Equatable {
bool _isDispose = false; bool _isDispose = false;
IGridCellController({ IGridCellController({
required this.gridCell, required this.cellId,
required GridCellsCache cellCache, required GridCellCache cellCache,
required GridCellFieldNotifier fieldNotifier, required GridCellFieldNotifier fieldNotifier,
required GridCellDataLoader<T> cellDataLoader, required GridCellDataLoader<T> cellDataLoader,
required IGridCellDataPersistence<D> cellDataPersistence, required IGridCellDataPersistence<D> cellDataPersistence,
@ -139,29 +141,27 @@ class IGridCellController<T, D> extends Equatable {
_cellDataLoader = cellDataLoader, _cellDataLoader = cellDataLoader,
_cellDataPersistence = cellDataPersistence, _cellDataPersistence = cellDataPersistence,
_fieldNotifier = fieldNotifier, _fieldNotifier = fieldNotifier,
_fieldService = FieldService(gridId: gridCell.gridId, fieldId: gridCell.field.id), _fieldService = FieldService(gridId: cellId.gridId, fieldId: cellId.field.id),
_cacheKey = GridCellCacheKey(rowId: gridCell.rowId, fieldId: gridCell.field.id); _cacheKey = GridCellCacheKey(rowId: cellId.rowId, fieldId: cellId.field.id);
IGridCellController<T, D> clone() { IGridCellController<T, D> clone() {
return IGridCellController( return IGridCellController(
gridCell: gridCell, cellId: cellId,
cellDataLoader: _cellDataLoader, cellDataLoader: _cellDataLoader,
cellCache: _cellsCache, cellCache: _cellsCache,
fieldNotifier: _fieldNotifier, fieldNotifier: _fieldNotifier,
cellDataPersistence: _cellDataPersistence); cellDataPersistence: _cellDataPersistence);
} }
String get gridId => gridCell.gridId; String get gridId => cellId.gridId;
String get rowId => gridCell.rowId; String get rowId => cellId.rowId;
String get cellId => gridCell.rowId + gridCell.field.id; String get fieldId => cellId.field.id;
String get fieldId => gridCell.field.id; Field get field => cellId.field;
Field get field => gridCell.field; FieldType get fieldType => cellId.field.fieldType;
FieldType get fieldType => gridCell.field.fieldType;
VoidCallback? startListening({required void Function(T?) onCellChanged, VoidCallback? onCellFieldChanged}) { VoidCallback? startListening({required void Function(T?) onCellChanged, VoidCallback? onCellFieldChanged}) {
if (isListening) { if (isListening) {
@ -177,7 +177,7 @@ class IGridCellController<T, D> extends Equatable {
/// user input: 12 /// user input: 12
/// cell display: $12 /// cell display: $12
_cellDataNotifier = ValueNotifier(_cellsCache.get(_cacheKey)); _cellDataNotifier = ValueNotifier(_cellsCache.get(_cacheKey));
_cellListener = CellListener(rowId: gridCell.rowId, fieldId: gridCell.field.id); _cellListener = CellListener(rowId: cellId.rowId, fieldId: cellId.field.id);
/// 1.Listen on user edit event and load the new cell data if needed. /// 1.Listen on user edit event and load the new cell data if needed.
_cellListener.start(onCellChanged: (result) { _cellListener.start(onCellChanged: (result) {
@ -264,7 +264,7 @@ class IGridCellController<T, D> extends Equatable {
_loadDataOperation = Timer(const Duration(milliseconds: 10), () { _loadDataOperation = Timer(const Duration(milliseconds: 10), () {
_cellDataLoader.loadData().then((data) { _cellDataLoader.loadData().then((data) {
_cellDataNotifier?.value = data; _cellDataNotifier?.value = data;
_cellsCache.insert(_GridCellCacheValue(key: _cacheKey, object: data)); _cellsCache.insert(_cacheKey, GridCell(object: data));
}); });
}); });
} }
@ -287,7 +287,7 @@ class IGridCellController<T, D> extends Equatable {
} }
@override @override
List<Object> get props => [_cellsCache.get(_cacheKey) ?? "", cellId]; List<Object> get props => [_cellsCache.get(_cacheKey) ?? "", cellId.rowId + cellId.field.id];
} }
class _GridFieldChangedNotifierImpl extends GridFieldChangedNotifier { class _GridFieldChangedNotifierImpl extends GridFieldChangedNotifier {

View File

@ -17,7 +17,7 @@ class SelectOptionCellEditorBloc extends Bloc<SelectOptionEditorEvent, SelectOpt
SelectOptionCellEditorBloc({ SelectOptionCellEditorBloc({
required this.cellController, required this.cellController,
}) : _selectOptionService = SelectOptionService(gridCell: cellController.gridCell), }) : _selectOptionService = SelectOptionService(cellId: cellController.cellId),
super(SelectOptionEditorState.initial(cellController)) { super(SelectOptionEditorState.initial(cellController)) {
on<SelectOptionEditorEvent>( on<SelectOptionEditorEvent>(
(event, emit) async { (event, emit) async {

View File

@ -7,12 +7,12 @@ import 'package:flowy_sdk/protobuf/flowy-grid/select_option.pb.dart';
import 'cell_service/cell_service.dart'; import 'cell_service/cell_service.dart';
class SelectOptionService { class SelectOptionService {
final GridCellIdentifier gridCell; final GridCellIdentifier cellId;
SelectOptionService({required this.gridCell}); SelectOptionService({required this.cellId});
String get gridId => gridCell.gridId; String get gridId => cellId.gridId;
String get fieldId => gridCell.field.id; String get fieldId => cellId.field.id;
String get rowId => gridCell.rowId; String get rowId => cellId.rowId;
Future<Either<Unit, FlowyError>> create({required String name}) { Future<Either<Unit, FlowyError>> create({required String name}) {
return TypeOptionService(gridId: gridId, fieldId: fieldId).newOption(name: name).then( return TypeOptionService(gridId: gridId, fieldId: fieldId).newOption(name: name).then(

View File

@ -9,7 +9,7 @@ class FieldEditorBloc extends Bloc<FieldEditorEvent, FieldEditorState> {
FieldEditorBloc({ FieldEditorBloc({
required String gridId, required String gridId,
required String fieldName, required String fieldName,
required IFieldContextLoader fieldContextLoader, required IFieldTypeOptionLoader fieldContextLoader,
}) : super(FieldEditorState.initial(gridId, fieldName, fieldContextLoader)) { }) : super(FieldEditorState.initial(gridId, fieldName, fieldContextLoader)) {
on<FieldEditorEvent>( on<FieldEditorEvent>(
(event, emit) async { (event, emit) async {
@ -53,7 +53,7 @@ class FieldEditorState with _$FieldEditorState {
required Option<GridFieldContext> fieldContext, required Option<GridFieldContext> fieldContext,
}) = _FieldEditorState; }) = _FieldEditorState;
factory FieldEditorState.initial(String gridId, String fieldName, IFieldContextLoader loader) => FieldEditorState( factory FieldEditorState.initial(String gridId, String fieldName, IFieldTypeOptionLoader loader) => FieldEditorState(
gridId: gridId, gridId: gridId,
fieldContext: none(), fieldContext: none(),
errorText: '', errorText: '',

View File

@ -141,7 +141,7 @@ class GridFieldCellContext with _$GridFieldCellContext {
}) = _GridFieldCellContext; }) = _GridFieldCellContext;
} }
abstract class IFieldContextLoader { abstract class IFieldTypeOptionLoader {
String get gridId; String get gridId;
Future<Either<FieldTypeOptionData, FlowyError>> load(); Future<Either<FieldTypeOptionData, FlowyError>> load();
@ -155,10 +155,10 @@ abstract class IFieldContextLoader {
} }
} }
class NewFieldContextLoader extends IFieldContextLoader { class NewFieldTypeOptionLoader extends IFieldTypeOptionLoader {
@override @override
final String gridId; final String gridId;
NewFieldContextLoader({ NewFieldTypeOptionLoader({
required this.gridId, required this.gridId,
}); });
@ -172,12 +172,12 @@ class NewFieldContextLoader extends IFieldContextLoader {
} }
} }
class FieldContextLoader extends IFieldContextLoader { class FieldTypeOptionLoader extends IFieldTypeOptionLoader {
@override @override
final String gridId; final String gridId;
final Field field; final Field field;
FieldContextLoader({ FieldTypeOptionLoader({
required this.gridId, required this.gridId,
required this.field, required this.field,
}); });
@ -195,14 +195,14 @@ class FieldContextLoader extends IFieldContextLoader {
class GridFieldContext { class GridFieldContext {
final String gridId; final String gridId;
final IFieldContextLoader _loader; final IFieldTypeOptionLoader _loader;
late FieldTypeOptionData _data; late FieldTypeOptionData _data;
ValueNotifier<Field>? _fieldNotifier; ValueNotifier<Field>? _fieldNotifier;
GridFieldContext({ GridFieldContext({
required this.gridId, required this.gridId,
required IFieldContextLoader loader, required IFieldTypeOptionLoader loader,
}) : _loader = loader; }) : _loader = loader;
Future<Either<Unit, FlowyError>> loadData() async { Future<Either<Unit, FlowyError>> loadData() async {

View File

@ -7,7 +7,7 @@ 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 'block/block_service.dart'; import 'block/block_cache.dart';
import 'grid_service.dart'; import 'grid_service.dart';
import 'row/row_service.dart'; import 'row/row_service.dart';
import 'dart:collection'; import 'dart:collection';
@ -68,7 +68,7 @@ class GridBloc extends Bloc<GridEvent, GridState> {
return super.close(); return super.close();
} }
GridRowsCache? getRowCache(String blockId, String rowId) { GridRowCache? getRowCache(String blockId, String rowId) {
final GridBlockCache? blockCache = _blocks[blockId]; final GridBlockCache? blockCache = _blocks[blockId];
return blockCache?.rowCache; return blockCache?.rowCache;
} }

View File

@ -61,13 +61,12 @@ typedef FieldsCallback = void Function(List<Field>);
class GridFieldCache { class GridFieldCache {
final String gridId; final String gridId;
late final GridFieldsListener _fieldListener; final GridFieldsListener _fieldListener;
FieldsNotifier? _fieldNotifier = FieldsNotifier(); FieldsNotifier? _fieldNotifier = FieldsNotifier();
final Map<FieldsCallback, VoidCallback> _fieldsCallbackMap = {}; final Map<FieldsCallback, VoidCallback> _fieldsCallbackMap = {};
final Map<FieldChangesetCallback, FieldChangesetCallback> _changesetCallbackMap = {}; final Map<FieldChangesetCallback, FieldChangesetCallback> _changesetCallbackMap = {};
GridFieldCache({required this.gridId}) { GridFieldCache({required this.gridId}) : _fieldListener = GridFieldsListener(gridId: gridId) {
_fieldListener = GridFieldsListener(gridId: gridId);
_fieldListener.start(onFieldsChanged: (result) { _fieldListener.start(onFieldsChanged: (result) {
result.fold( result.fold(
(changeset) { (changeset) {

View File

@ -15,7 +15,7 @@ class RowActionSheetBloc extends Bloc<RowActionSheetEvent, RowActionSheetState>
: _rowService = RowService( : _rowService = RowService(
gridId: rowData.gridId, gridId: rowData.gridId,
blockId: rowData.blockId, blockId: rowData.blockId,
rowId: rowData.rowId, rowId: rowData.id,
), ),
super(RowActionSheetState.initial(rowData)) { super(RowActionSheetState.initial(rowData)) {
on<RowActionSheetEvent>( on<RowActionSheetEvent>(

View File

@ -11,19 +11,19 @@ part 'row_bloc.freezed.dart';
class RowBloc extends Bloc<RowEvent, RowState> { class RowBloc extends Bloc<RowEvent, RowState> {
final RowService _rowService; final RowService _rowService;
final GridRowsCache _rowCache; final GridRowCache _rowCache;
void Function()? _rowListenFn; void Function()? _rowListenFn;
RowBloc({ RowBloc({
required GridRow rowData, required GridRow rowData,
required GridRowsCache rowCache, required GridRowCache rowCache,
}) : _rowService = RowService( }) : _rowService = RowService(
gridId: rowData.gridId, gridId: rowData.gridId,
blockId: rowData.blockId, blockId: rowData.blockId,
rowId: rowData.rowId, rowId: rowData.id,
), ),
_rowCache = rowCache, _rowCache = rowCache,
super(RowState.initial(rowData, rowCache.loadGridCells(rowData.rowId))) { super(RowState.initial(rowData, rowCache.loadGridCells(rowData.id))) {
on<RowEvent>( on<RowEvent>(
(event, emit) async { (event, emit) async {
await event.map( await event.map(
@ -58,7 +58,7 @@ class RowBloc extends Bloc<RowEvent, RowState> {
Future<void> _startListening() async { Future<void> _startListening() async {
_rowListenFn = _rowCache.addListener( _rowListenFn = _rowCache.addListener(
rowId: state.rowData.rowId, rowId: state.rowData.id,
onCellUpdated: (cellDatas, reason) => add(RowEvent.didReceiveCellDatas(cellDatas, reason)), onCellUpdated: (cellDatas, reason) => add(RowEvent.didReceiveCellDatas(cellDatas, reason)),
listenWhen: () => !isClosed, listenWhen: () => !isClosed,
); );

View File

@ -8,12 +8,12 @@ part 'row_detail_bloc.freezed.dart';
class RowDetailBloc extends Bloc<RowDetailEvent, RowDetailState> { class RowDetailBloc extends Bloc<RowDetailEvent, RowDetailState> {
final GridRow rowData; final GridRow rowData;
final GridRowsCache _rowCache; final GridRowCache _rowCache;
void Function()? _rowListenFn; void Function()? _rowListenFn;
RowDetailBloc({ RowDetailBloc({
required this.rowData, required this.rowData,
required GridRowsCache rowCache, required GridRowCache rowCache,
}) : _rowCache = rowCache, }) : _rowCache = rowCache,
super(RowDetailState.initial()) { super(RowDetailState.initial()) {
on<RowDetailEvent>( on<RowDetailEvent>(
@ -41,14 +41,14 @@ class RowDetailBloc extends Bloc<RowDetailEvent, RowDetailState> {
Future<void> _startListening() async { Future<void> _startListening() async {
_rowListenFn = _rowCache.addListener( _rowListenFn = _rowCache.addListener(
rowId: rowData.rowId, rowId: rowData.id,
onCellUpdated: (cellDatas, reason) => add(RowDetailEvent.didReceiveCellDatas(cellDatas.values.toList())), onCellUpdated: (cellDatas, reason) => add(RowDetailEvent.didReceiveCellDatas(cellDatas.values.toList())),
listenWhen: () => !isClosed, listenWhen: () => !isClosed,
); );
} }
Future<void> _loadCellData() async { Future<void> _loadCellData() async {
final cellDataMap = _rowCache.loadGridCells(rowData.rowId); final cellDataMap = _rowCache.loadGridCells(rowData.id);
if (!isClosed) { if (!isClosed) {
add(RowDetailEvent.didReceiveCellDatas(cellDataMap.values.toList())); add(RowDetailEvent.didReceiveCellDatas(cellDataMap.values.toList()));
} }

View File

@ -21,35 +21,46 @@ abstract class GridRowCacheFieldNotifier {
void dispose(); void dispose();
} }
class GridRowsCache { /// Cache the rows in memory
/// Insert / delete / update row
///
/// Read https://appflowy.gitbook.io/docs/essential-documentation/contribute-to-appflowy/architecture/frontend/grid for more information.
class GridRowCache {
final String gridId; final String gridId;
final GridBlock block; final GridBlock block;
final _Notifier _notifier;
/// _rows containers the current block's rows
/// Use List to reverse the order of the GridRow.
List<GridRow> _rows = []; List<GridRow> _rows = [];
/// Use Map for faster access the raw row data.
final HashMap<String, Row> _rowByRowId; final HashMap<String, Row> _rowByRowId;
final GridCellCache _cellCache;
final GridRowCacheFieldNotifier _fieldNotifier; final GridRowCacheFieldNotifier _fieldNotifier;
final GridCellsCache _cellCache; final _GridRowChangesetNotifier _rowChangeReasonNotifier;
List<GridRow> get rows => _rows; UnmodifiableListView<GridRow> get rows => UnmodifiableListView(_rows);
GridCellsCache get cellCache => _cellCache; GridCellCache get cellCache => _cellCache;
GridRowsCache({ GridRowCache({
required this.gridId, required this.gridId,
required this.block, required this.block,
required GridRowCacheFieldNotifier notifier, required GridRowCacheFieldNotifier notifier,
}) : _cellCache = GridCellsCache(gridId: gridId), }) : _cellCache = GridCellCache(gridId: gridId),
_rowByRowId = HashMap(), _rowByRowId = HashMap(),
_notifier = _Notifier(), _rowChangeReasonNotifier = _GridRowChangesetNotifier(),
_fieldNotifier = notifier { _fieldNotifier = notifier {
// //
notifier.onFieldsChanged(() => _notifier.receive(const GridRowChangeReason.fieldDidChange())); notifier.onFieldsChanged(() => _rowChangeReasonNotifier.receive(const GridRowChangeReason.fieldDidChange()));
notifier.onFieldChanged((field) => _cellCache.remove(field.id)); notifier.onFieldChanged((field) => _cellCache.remove(field.id));
_rows = block.rowInfos.map((rowInfo) => buildGridRow(rowInfo.rowId, rowInfo.height.toDouble())).toList(); _rows = block.rowInfos.map((rowInfo) => buildGridRow(rowInfo.rowId, rowInfo.height.toDouble())).toList();
} }
Future<void> dispose() async { Future<void> dispose() async {
_fieldNotifier.dispose(); _fieldNotifier.dispose();
_notifier.dispose(); _rowChangeReasonNotifier.dispose();
await _cellCache.dispose(); await _cellCache.dispose();
} }
@ -73,14 +84,15 @@ class GridRowsCache {
final Map<String, String> deletedRowByRowId = {for (var rowId in deletedRows) rowId: rowId}; final Map<String, String> deletedRowByRowId = {for (var rowId in deletedRows) rowId: rowId};
_rows.asMap().forEach((index, row) { _rows.asMap().forEach((index, row) {
if (deletedRowByRowId[row.rowId] == null) { if (deletedRowByRowId[row.id] == null) {
newRows.add(row); newRows.add(row);
} else { } else {
_rowByRowId.remove(row.id);
deletedIndex.add(DeletedIndex(index: index, row: row)); deletedIndex.add(DeletedIndex(index: index, row: row));
} }
}); });
_rows = newRows; _rows = newRows;
_notifier.receive(GridRowChangeReason.delete(deletedIndex)); _rowChangeReasonNotifier.receive(GridRowChangeReason.delete(deletedIndex));
} }
void _insertRows(List<InsertedRow> insertRows) { void _insertRows(List<InsertedRow> insertRows) {
@ -89,17 +101,16 @@ class GridRowsCache {
} }
InsertedIndexs insertIndexs = []; InsertedIndexs insertIndexs = [];
final List<GridRow> newRows = _rows;
for (final insertRow in insertRows) { for (final insertRow in insertRows) {
final insertIndex = InsertedIndex( final insertIndex = InsertedIndex(
index: insertRow.index, index: insertRow.index,
rowId: insertRow.rowId, rowId: insertRow.rowId,
); );
insertIndexs.add(insertIndex); insertIndexs.add(insertIndex);
newRows.insert(insertRow.index, (buildGridRow(insertRow.rowId, insertRow.height.toDouble()))); _rows.insert(insertRow.index, (buildGridRow(insertRow.rowId, insertRow.height.toDouble())));
} }
_notifier.receive(GridRowChangeReason.insert(insertIndexs)); _rowChangeReasonNotifier.receive(GridRowChangeReason.insert(insertIndexs));
} }
void _updateRows(List<UpdatedRow> updatedRows) { void _updateRows(List<UpdatedRow> updatedRows) {
@ -108,20 +119,19 @@ class GridRowsCache {
} }
final UpdatedIndexs updatedIndexs = UpdatedIndexs(); final UpdatedIndexs updatedIndexs = UpdatedIndexs();
final List<GridRow> newRows = _rows;
for (final updatedRow in updatedRows) { for (final updatedRow in updatedRows) {
final rowId = updatedRow.rowId; final rowId = updatedRow.rowId;
final index = newRows.indexWhere((row) => row.rowId == rowId); final index = _rows.indexWhere((row) => row.id == rowId);
if (index != -1) { if (index != -1) {
_rowByRowId[rowId] = updatedRow.row; _rowByRowId[rowId] = updatedRow.row;
newRows.removeAt(index); _rows.removeAt(index);
newRows.insert(index, buildGridRow(rowId, updatedRow.row.height.toDouble())); _rows.insert(index, buildGridRow(rowId, updatedRow.row.height.toDouble()));
updatedIndexs[rowId] = UpdatedIndex(index: index, rowId: rowId); updatedIndexs[rowId] = UpdatedIndex(index: index, rowId: rowId);
} }
} }
_notifier.receive(GridRowChangeReason.update(updatedIndexs)); _rowChangeReasonNotifier.receive(GridRowChangeReason.update(updatedIndexs));
} }
void _hideRows(List<String> hideRows) {} void _hideRows(List<String> hideRows) {}
@ -131,8 +141,8 @@ class GridRowsCache {
void onRowsChanged( void onRowsChanged(
void Function(GridRowChangeReason) onRowChanged, void Function(GridRowChangeReason) onRowChanged,
) { ) {
_notifier.addListener(() { _rowChangeReasonNotifier.addListener(() {
onRowChanged(_notifier._reason); onRowChanged(_rowChangeReasonNotifier.reason);
}); });
} }
@ -151,12 +161,12 @@ class GridRowsCache {
final row = _rowByRowId[rowId]; final row = _rowByRowId[rowId];
if (row != null) { if (row != null) {
final GridCellMap cellDataMap = _makeGridCells(rowId, row); final GridCellMap cellDataMap = _makeGridCells(rowId, row);
onCellUpdated(cellDataMap, _notifier._reason); onCellUpdated(cellDataMap, _rowChangeReasonNotifier.reason);
} }
} }
} }
_notifier._reason.whenOrNull( _rowChangeReasonNotifier.reason.whenOrNull(
update: (indexs) { update: (indexs) {
if (indexs[rowId] != null) notifyUpdate(); if (indexs[rowId] != null) notifyUpdate();
}, },
@ -164,12 +174,12 @@ class GridRowsCache {
); );
} }
_notifier.addListener(listenrHandler); _rowChangeReasonNotifier.addListener(listenrHandler);
return listenrHandler; return listenrHandler;
} }
void removeRowListener(VoidCallback callback) { void removeRowListener(VoidCallback callback) {
_notifier.removeListener(callback); _rowChangeReasonNotifier.removeListener(callback);
} }
GridCellMap loadGridCells(String rowId) { GridCellMap loadGridCells(String rowId) {
@ -215,19 +225,19 @@ class GridRowsCache {
updatedRow.freeze(); updatedRow.freeze();
_rowByRowId[updatedRow.id] = updatedRow; _rowByRowId[updatedRow.id] = updatedRow;
final index = _rows.indexWhere((gridRow) => gridRow.rowId == updatedRow.id); final index = _rows.indexWhere((gridRow) => gridRow.id == updatedRow.id);
if (index != -1) { if (index != -1) {
// update the corresponding row in _rows if they are not the same // update the corresponding row in _rows if they are not the same
if (_rows[index].data != updatedRow) { if (_rows[index].rawRow != updatedRow) {
final row = _rows.removeAt(index).copyWith(data: updatedRow); final row = _rows.removeAt(index).copyWith(rawRow: updatedRow);
_rows.insert(index, row); _rows.insert(index, row);
// Calculate the update index // Calculate the update index
final UpdatedIndexs updatedIndexs = UpdatedIndexs(); final UpdatedIndexs updatedIndexs = UpdatedIndexs();
updatedIndexs[row.rowId] = UpdatedIndex(index: index, rowId: row.rowId); updatedIndexs[row.id] = UpdatedIndex(index: index, rowId: row.id);
// //
_notifier.receive(GridRowChangeReason.update(updatedIndexs)); _rowChangeReasonNotifier.receive(GridRowChangeReason.update(updatedIndexs));
} }
} }
} }
@ -237,19 +247,19 @@ class GridRowsCache {
gridId: gridId, gridId: gridId,
blockId: block.id, blockId: block.id,
fields: _fieldNotifier.fields, fields: _fieldNotifier.fields,
rowId: rowId, id: rowId,
height: rowHeight, height: rowHeight,
); );
} }
} }
class _Notifier extends ChangeNotifier { class _GridRowChangesetNotifier extends ChangeNotifier {
GridRowChangeReason _reason = const InitialListState(); GridRowChangeReason reason = const InitialListState();
_Notifier(); _GridRowChangesetNotifier();
void receive(GridRowChangeReason reason) { void receive(GridRowChangeReason newReason) {
_reason = reason; reason = newReason;
reason.map( reason.map(
insert: (_) => notifyListeners(), insert: (_) => notifyListeners(),
delete: (_) => notifyListeners(), delete: (_) => notifyListeners(),
@ -319,10 +329,10 @@ class GridRow with _$GridRow {
const factory GridRow({ const factory GridRow({
required String gridId, required String gridId,
required String blockId, required String blockId,
required String rowId, required String id,
required UnmodifiableListView<Field> fields, required UnmodifiableListView<Field> fields,
required double height, required double height,
Row? data, Row? rawRow,
}) = _GridRow; }) = _GridRow;
} }

View File

@ -227,7 +227,7 @@ class _GridRowsState extends State<_GridRows> {
GridRow rowData, GridRow rowData,
Animation<double> animation, Animation<double> animation,
) { ) {
final rowCache = context.read<GridBloc>().getRowCache(rowData.blockId, rowData.rowId); final rowCache = context.read<GridBloc>().getRowCache(rowData.blockId, rowData.id);
final fieldCache = context.read<GridBloc>().fieldCache; final fieldCache = context.read<GridBloc>().fieldCache;
if (rowCache != null) { if (rowCache != null) {
return SizeTransition( return SizeTransition(
@ -236,7 +236,7 @@ class _GridRowsState extends State<_GridRows> {
rowData: rowData, rowData: rowData,
rowCache: rowCache, rowCache: rowCache,
fieldCache: fieldCache, fieldCache: fieldCache,
key: ValueKey(rowData.rowId), key: ValueKey(rowData.id),
), ),
); );
} else { } else {

View File

@ -14,7 +14,7 @@ import 'text_cell.dart';
import 'url_cell/url_cell.dart'; import 'url_cell/url_cell.dart';
class GridCellBuilder { class GridCellBuilder {
final GridCellsCache cellCache; final GridCellCache cellCache;
final GridFieldCache fieldCache; final GridFieldCache fieldCache;
GridCellBuilder({ GridCellBuilder({
required this.cellCache, required this.cellCache,
@ -23,12 +23,12 @@ class GridCellBuilder {
GridCellWidget build(GridCellIdentifier cell, {GridCellStyle? style}) { GridCellWidget build(GridCellIdentifier cell, {GridCellStyle? style}) {
final cellControllerBuilder = GridCellControllerBuilder( final cellControllerBuilder = GridCellControllerBuilder(
gridCell: cell, cellId: cell,
cellCache: cellCache, cellCache: cellCache,
fieldCache: fieldCache, fieldCache: fieldCache,
); );
final key = cell.key(); final key = cell.key();
switch (cell.field.fieldType) { switch (cell.fieldType) {
case FieldType.Checkbox: case FieldType.Checkbox:
return CheckboxCell(cellControllerBuilder: cellControllerBuilder, key: key); return CheckboxCell(cellControllerBuilder: cellControllerBuilder, key: key);
case FieldType.DateTime: case FieldType.DateTime:

View File

@ -65,7 +65,7 @@ class GridFieldCell extends StatelessWidget {
FieldEditor( FieldEditor(
gridId: state.gridId, gridId: state.gridId,
fieldName: field.name, fieldName: field.name,
contextLoader: FieldContextLoader( contextLoader: FieldTypeOptionLoader(
gridId: state.gridId, gridId: state.gridId,
field: field, field: field,
), ),

View File

@ -14,7 +14,7 @@ class FieldEditor extends StatelessWidget with FlowyOverlayDelegate {
final String gridId; final String gridId;
final String fieldName; final String fieldName;
final IFieldContextLoader contextLoader; final IFieldTypeOptionLoader contextLoader;
const FieldEditor({ const FieldEditor({
required this.gridId, required this.gridId,
required this.fieldName, required this.fieldName,

View File

@ -151,7 +151,7 @@ class CreateFieldButton extends StatelessWidget {
onTap: () => FieldEditor( onTap: () => FieldEditor(
gridId: gridId, gridId: gridId,
fieldName: "", fieldName: "",
contextLoader: NewFieldContextLoader(gridId: gridId), contextLoader: NewFieldTypeOptionLoader(gridId: gridId),
).show(context), ).show(context),
leftIcon: svgWidget("home/add"), leftIcon: svgWidget("home/add"),
); );

View File

@ -16,7 +16,7 @@ import 'row_detail.dart';
class GridRowWidget extends StatefulWidget { class GridRowWidget extends StatefulWidget {
final GridRow rowData; final GridRow rowData;
final GridRowsCache rowCache; final GridRowCache rowCache;
final GridCellBuilder cellBuilder; final GridCellBuilder cellBuilder;
GridRowWidget({ GridRowWidget({
@ -183,12 +183,12 @@ class _RowCells extends StatelessWidget {
List<Widget> _makeCells(BuildContext context, GridCellMap gridCellMap) { List<Widget> _makeCells(BuildContext context, GridCellMap gridCellMap) {
return gridCellMap.values.map( return gridCellMap.values.map(
(gridCell) { (cellId) {
final GridCellWidget child = builder.build(gridCell); final GridCellWidget child = builder.build(cellId);
accessoryBuilder(GridCellAccessoryBuildContext buildContext) { accessoryBuilder(GridCellAccessoryBuildContext buildContext) {
final builder = child.accessoryBuilder; final builder = child.accessoryBuilder;
List<GridCellAccessory> accessories = []; List<GridCellAccessory> accessories = [];
if (gridCell.field.isPrimary) { if (cellId.field.isPrimary) {
accessories.add(PrimaryCellAccessory( accessories.add(PrimaryCellAccessory(
onTapCallback: onExpand, onTapCallback: onExpand,
isCellEditing: buildContext.isCellEditing, isCellEditing: buildContext.isCellEditing,
@ -202,7 +202,7 @@ class _RowCells extends StatelessWidget {
} }
return CellContainer( return CellContainer(
width: gridCell.field.width.toDouble(), width: cellId.field.width.toDouble(),
child: child, child: child,
rowStateNotifier: Provider.of<RegionStateNotifier>(context, listen: false), rowStateNotifier: Provider.of<RegionStateNotifier>(context, listen: false),
accessoryBuilder: accessoryBuilder, accessoryBuilder: accessoryBuilder,

View File

@ -22,7 +22,7 @@ import 'package:flutter_bloc/flutter_bloc.dart';
class RowDetailPage extends StatefulWidget with FlowyOverlayDelegate { class RowDetailPage extends StatefulWidget with FlowyOverlayDelegate {
final GridRow rowData; final GridRow rowData;
final GridRowsCache rowCache; final GridRowCache rowCache;
final GridCellBuilder cellBuilder; final GridCellBuilder cellBuilder;
const RowDetailPage({ const RowDetailPage({
@ -122,7 +122,7 @@ class _PropertyList extends StatelessWidget {
itemCount: state.gridCells.length, itemCount: state.gridCells.length,
itemBuilder: (BuildContext context, int index) { itemBuilder: (BuildContext context, int index) {
return _RowDetailCell( return _RowDetailCell(
gridCell: state.gridCells[index], cellId: state.gridCells[index],
cellBuilder: cellBuilder, cellBuilder: cellBuilder,
); );
}, },
@ -137,10 +137,10 @@ class _PropertyList extends StatelessWidget {
} }
class _RowDetailCell extends StatelessWidget { class _RowDetailCell extends StatelessWidget {
final GridCellIdentifier gridCell; final GridCellIdentifier cellId;
final GridCellBuilder cellBuilder; final GridCellBuilder cellBuilder;
const _RowDetailCell({ const _RowDetailCell({
required this.gridCell, required this.cellId,
required this.cellBuilder, required this.cellBuilder,
Key? key, Key? key,
}) : super(key: key); }) : super(key: key);
@ -148,8 +148,8 @@ class _RowDetailCell extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final theme = context.watch<AppTheme>(); final theme = context.watch<AppTheme>();
final style = _customCellStyle(theme, gridCell.field.fieldType); final style = _customCellStyle(theme, cellId.fieldType);
final cell = cellBuilder.build(gridCell, style: style); final cell = cellBuilder.build(cellId, style: style);
final gesture = GestureDetector( final gesture = GestureDetector(
behavior: HitTestBehavior.translucent, behavior: HitTestBehavior.translucent,
@ -169,7 +169,7 @@ class _RowDetailCell extends StatelessWidget {
children: [ children: [
SizedBox( SizedBox(
width: 150, width: 150,
child: FieldCellButton(field: gridCell.field, onTap: () => _showFieldEditor(context)), child: FieldCellButton(field: cellId.field, onTap: () => _showFieldEditor(context)),
), ),
const HSpace(10), const HSpace(10),
Expanded(child: gesture), Expanded(child: gesture),
@ -181,11 +181,11 @@ class _RowDetailCell extends StatelessWidget {
void _showFieldEditor(BuildContext context) { void _showFieldEditor(BuildContext context) {
FieldEditor( FieldEditor(
gridId: gridCell.gridId, gridId: cellId.gridId,
fieldName: gridCell.field.name, fieldName: cellId.field.name,
contextLoader: FieldContextLoader( contextLoader: FieldTypeOptionLoader(
gridId: gridCell.gridId, gridId: cellId.gridId,
field: gridCell.field, field: cellId.field,
), ),
).show(context); ).show(context);
} }

View File

@ -116,7 +116,7 @@ class _GridPropertyCell extends StatelessWidget {
FieldEditor( FieldEditor(
gridId: gridId, gridId: gridId,
fieldName: field.name, fieldName: field.name,
contextLoader: FieldContextLoader(gridId: gridId, field: field), contextLoader: FieldTypeOptionLoader(gridId: gridId, field: field),
).show(context, anchorDirection: AnchorDirection.bottomRight); ).show(context, anchorDirection: AnchorDirection.bottomRight);
}, },
); );