chore: add documentation

This commit is contained in:
appflowy 2022-07-16 11:53:39 +08:00
parent e01a0cf8a5
commit a73987456e
29 changed files with 161 additions and 144 deletions

View File

@ -6,7 +6,7 @@ import 'package:flowy_sdk/protobuf/flowy-grid/block_entities.pb.dart';
import 'block_listener.dart';
class GridBlockCacheService {
class GridBlockCache {
final String gridId;
final GridBlock block;
late GridRowsCache _rowCache;
@ -15,7 +15,7 @@ class GridBlockCacheService {
List<GridRow> get rows => _rowCache.rows;
GridRowsCache get rowCache => _rowCache;
GridBlockCacheService({
GridBlockCache({
required this.gridId,
required this.block,
required GridFieldCache fieldCache,
@ -23,7 +23,7 @@ class GridBlockCacheService {
_rowCache = GridRowsCache(
gridId: gridId,
block: block,
delegate: GridRowCacheDelegateImpl(fieldCache),
notifier: GridRowCacheFieldNotifierImpl(fieldCache),
);
_listener = GridBlockListener(blockId: block.id);

View File

@ -1,25 +1,29 @@
part of 'cell_service.dart';
typedef GridCellMap = LinkedHashMap<String, GridCell>;
typedef GridCellMap = LinkedHashMap<String, GridCellIdentifier>;
class _GridCellCacheItem {
GridCellId key;
class _GridCellCacheValue {
GridCellCacheKey key;
dynamic object;
_GridCellCacheItem({
_GridCellCacheValue({
required this.key,
required this.object,
});
}
class GridCellId {
/// Use to index the cell in the grid.
/// We use [fieldId + rowId] to identify the cell.
class GridCellCacheKey {
final String fieldId;
final String rowId;
GridCellId({
GridCellCacheKey({
required this.fieldId,
required this.rowId,
});
}
/// GridCellsCache is used to cache cell data of each Grid.
/// We use GridCellCacheKey to index the cell in the cache.
class GridCellsCache {
final String gridId;
@ -33,29 +37,28 @@ class GridCellsCache {
_cellDataByFieldId.remove(fieldId);
}
void insert<T extends _GridCellCacheItem>(T item) {
var map = _cellDataByFieldId[item.key.fieldId];
void insert<T extends _GridCellCacheValue>(T value) {
var map = _cellDataByFieldId[value.key.fieldId];
if (map == null) {
_cellDataByFieldId[item.key.fieldId] = {};
map = _cellDataByFieldId[item.key.fieldId];
_cellDataByFieldId[value.key.fieldId] = {};
map = _cellDataByFieldId[value.key.fieldId];
}
map![item.key.rowId] = item.object;
map![value.key.rowId] = value.object;
}
T? get<T>(GridCellId key) {
T? get<T>(GridCellCacheKey key) {
final map = _cellDataByFieldId[key.fieldId];
if (map == null) {
return null;
} else {
final object = map[key.rowId];
if (object is T) {
return object;
final value = map[key.rowId];
if (value is T) {
return value;
} else {
if (object != null) {
Log.error("Cache data type does not match the cache data type");
if (value != null) {
Log.error("Expected value type: $T, but receive $value");
}
return null;
}
}

View File

@ -5,40 +5,22 @@ abstract class IGridCellDataConfig {
bool get reloadOnFieldChanged;
}
class GridCellDataConfig implements IGridCellDataConfig {
@override
final bool reloadOnFieldChanged;
const GridCellDataConfig({
this.reloadOnFieldChanged = false,
});
}
abstract class IGridCellDataLoader<T> {
Future<T?> loadData();
IGridCellDataConfig get config;
}
abstract class ICellDataParser<T> {
T? parserData(List<int> data);
}
class GridCellDataLoader<T> extends IGridCellDataLoader<T> {
class GridCellDataLoader<T> {
final CellService service = CellService();
final GridCell gridCell;
final GridCellIdentifier gridCell;
final ICellDataParser<T> parser;
@override
final IGridCellDataConfig config;
final bool reloadOnFieldChanged;
GridCellDataLoader({
required this.gridCell,
required this.parser,
this.config = const GridCellDataConfig(),
this.reloadOnFieldChanged = false,
});
@override
Future<T?> loadData() {
final fut = service.getCell(
gridId: gridCell.gridId,

View File

@ -1,11 +1,13 @@
part of 'cell_service.dart';
/// Save the cell data to disk
/// You can extend this class to do custom operations. For example, the DateCellDataPersistence.
abstract class IGridCellDataPersistence<D> {
Future<Option<FlowyError>> save(D data);
}
class CellDataPersistence implements IGridCellDataPersistence<String> {
final GridCell gridCell;
final GridCellIdentifier gridCell;
CellDataPersistence({
required this.gridCell,
@ -36,7 +38,7 @@ class CalendarData with _$CalendarData {
}
class DateCellDataPersistence implements IGridCellDataPersistence<CalendarData> {
final GridCell gridCell;
final GridCellIdentifier gridCell;
DateCellDataPersistence({
required this.gridCell,
});
@ -61,7 +63,7 @@ class DateCellDataPersistence implements IGridCellDataPersistence<CalendarData>
}
}
CellIdentifierPayload _cellIdentifier(GridCell gridCell) {
CellIdentifierPayload _cellIdentifier(GridCellIdentifier gridCell) {
return CellIdentifierPayload.create()
..gridId = gridCell.gridId
..fieldId = gridCell.field.id

View File

@ -8,6 +8,8 @@ abstract class GridFieldChangedNotifier {
void dispose();
}
/// Grid's cell helper wrapper that enables each cell will get notified when the corresponding field was changed.
/// You Register an onFieldChanged callback to listen to the cell changes, and unregister if you don't want to listen.
class GridCellFieldNotifier {
/// fieldId: {objectId: callback}
final Map<String, Map<String, List<VoidCallback>>> _fieldListenerByFieldId = {};
@ -27,7 +29,8 @@ class GridCellFieldNotifier {
);
}
void addFieldListener(GridCellId cacheKey, VoidCallback onFieldChanged) {
///
void register(GridCellCacheKey cacheKey, VoidCallback onFieldChanged) {
var map = _fieldListenerByFieldId[cacheKey.fieldId];
if (map == null) {
_fieldListenerByFieldId[cacheKey.fieldId] = {};
@ -43,7 +46,7 @@ class GridCellFieldNotifier {
}
}
void removeFieldListener(GridCellId cacheKey, VoidCallback fn) {
void unregister(GridCellCacheKey cacheKey, VoidCallback fn) {
var callbacks = _fieldListenerByFieldId[cacheKey.fieldId]?[cacheKey.rowId];
final index = callbacks?.indexWhere((callback) => callback == fn);
if (index != null && index != -1) {

View File

@ -18,6 +18,7 @@ import 'package:app_flowy/workspace/application/grid/cell/cell_listener.dart';
import 'package:app_flowy/workspace/application/grid/field/field_service.dart';
import 'dart:convert' show utf8;
import '../../field/type_option/type_option_service.dart';
import 'cell_field_notifier.dart';
part 'cell_service.freezed.dart';
part 'cell_data_loader.dart';
@ -57,18 +58,20 @@ class CellService {
}
}
/// Id of the cell
/// We can locate the cell by using gridId + rowId + field.id.
@freezed
class GridCell with _$GridCell {
const factory GridCell({
class GridCellIdentifier with _$GridCellIdentifier {
const factory GridCellIdentifier({
required String gridId,
required String rowId,
required Field field,
}) = _GridCell;
}) = _GridCellIdentifier;
// ignore: unused_element
const GridCell._();
const GridCellIdentifier._();
String cellId() {
return rowId + field.id + "${field.fieldType}";
ValueKey key() {
return ValueKey(rowId + field.id + "${field.fieldType}");
}
}

View File

@ -6,12 +6,12 @@ typedef GridDateCellController = IGridCellController<DateCellData, CalendarData>
typedef GridURLCellController = IGridCellController<URLCellData, String>;
class GridCellControllerBuilder {
final GridCell _gridCell;
final GridCellIdentifier _gridCell;
final GridCellsCache _cellCache;
final GridFieldCache _fieldCache;
GridCellControllerBuilder(
{required GridCell gridCell, required GridCellsCache cellCache, required GridFieldCache fieldCache})
{required GridCellIdentifier gridCell, required GridCellsCache cellCache, required GridFieldCache fieldCache})
: _cellCache = cellCache,
_fieldCache = fieldCache,
_gridCell = gridCell;
@ -29,34 +29,33 @@ class GridCellControllerBuilder {
gridCell: _gridCell,
cellCache: _cellCache,
cellDataLoader: cellDataLoader,
cellFieldNotifier: cellFieldNotifier,
fieldNotifier: cellFieldNotifier,
cellDataPersistence: CellDataPersistence(gridCell: _gridCell),
);
case FieldType.DateTime:
final cellDataLoader = GridCellDataLoader(
gridCell: _gridCell,
parser: DateCellDataParser(),
config: const GridCellDataConfig(reloadOnFieldChanged: true),
reloadOnFieldChanged: true,
);
return GridDateCellController(
gridCell: _gridCell,
cellCache: _cellCache,
cellDataLoader: cellDataLoader,
cellFieldNotifier: cellFieldNotifier,
fieldNotifier: cellFieldNotifier,
cellDataPersistence: DateCellDataPersistence(gridCell: _gridCell),
);
case FieldType.Number:
final cellDataLoader = GridCellDataLoader(
gridCell: _gridCell,
parser: StringCellDataParser(),
config: const GridCellDataConfig(reloadOnFieldChanged: true),
);
return GridCellController(
gridCell: _gridCell,
cellCache: _cellCache,
cellDataLoader: cellDataLoader,
cellFieldNotifier: cellFieldNotifier,
fieldNotifier: cellFieldNotifier,
cellDataPersistence: CellDataPersistence(gridCell: _gridCell),
);
case FieldType.RichText:
@ -68,7 +67,7 @@ class GridCellControllerBuilder {
gridCell: _gridCell,
cellCache: _cellCache,
cellDataLoader: cellDataLoader,
cellFieldNotifier: cellFieldNotifier,
fieldNotifier: cellFieldNotifier,
cellDataPersistence: CellDataPersistence(gridCell: _gridCell),
);
case FieldType.MultiSelect:
@ -76,14 +75,14 @@ class GridCellControllerBuilder {
final cellDataLoader = GridCellDataLoader(
gridCell: _gridCell,
parser: SelectOptionCellDataParser(),
config: const GridCellDataConfig(reloadOnFieldChanged: true),
reloadOnFieldChanged: true,
);
return GridSelectOptionCellController(
gridCell: _gridCell,
cellCache: _cellCache,
cellDataLoader: cellDataLoader,
cellFieldNotifier: cellFieldNotifier,
fieldNotifier: cellFieldNotifier,
cellDataPersistence: CellDataPersistence(gridCell: _gridCell),
);
@ -96,7 +95,7 @@ class GridCellControllerBuilder {
gridCell: _gridCell,
cellCache: _cellCache,
cellDataLoader: cellDataLoader,
cellFieldNotifier: cellFieldNotifier,
fieldNotifier: cellFieldNotifier,
cellDataPersistence: CellDataPersistence(gridCell: _gridCell),
);
}
@ -104,17 +103,21 @@ class GridCellControllerBuilder {
}
}
// T: the type of the CellData
// D: the type of the data that will be saved to disk
/// IGridCellController is used to manipulate the cell and receive notifications.
/// * Read/Write cell data
/// * Listen on field/cell notifications.
///
/// Generic T represents the type of the cell data.
/// Generic D represents the type of data that will be saved to the disk
///
// ignore: must_be_immutable
class IGridCellController<T, D> extends Equatable {
final GridCell gridCell;
final GridCellIdentifier gridCell;
final GridCellsCache _cellsCache;
final GridCellId _cacheKey;
final GridCellCacheKey _cacheKey;
final FieldService _fieldService;
final GridCellFieldNotifier _cellFieldNotifier;
// final GridCellFieldNotifier _fieldNotifier;
final IGridCellDataLoader<T> _cellDataLoader;
final GridCellFieldNotifier _fieldNotifier;
final GridCellDataLoader<T> _cellDataLoader;
final IGridCellDataPersistence<D> _cellDataPersistence;
late final CellListener _cellListener;
@ -124,28 +127,27 @@ class IGridCellController<T, D> extends Equatable {
VoidCallback? _onFieldChangedFn;
Timer? _loadDataOperation;
Timer? _saveDataOperation;
bool isDispose = false;
bool _isDispose = false;
IGridCellController({
required this.gridCell,
required GridCellsCache cellCache,
required GridCellFieldNotifier cellFieldNotifier,
required IGridCellDataLoader<T> cellDataLoader,
required GridCellFieldNotifier fieldNotifier,
required GridCellDataLoader<T> cellDataLoader,
required IGridCellDataPersistence<D> cellDataPersistence,
// required GridFieldChangedNotifier notifierDelegate,
}) : _cellsCache = cellCache,
_cellDataLoader = cellDataLoader,
_cellDataPersistence = cellDataPersistence,
_cellFieldNotifier = cellFieldNotifier,
_fieldNotifier = fieldNotifier,
_fieldService = FieldService(gridId: gridCell.gridId, fieldId: gridCell.field.id),
_cacheKey = GridCellId(rowId: gridCell.rowId, fieldId: gridCell.field.id);
_cacheKey = GridCellCacheKey(rowId: gridCell.rowId, fieldId: gridCell.field.id);
IGridCellController<T, D> clone() {
return IGridCellController(
gridCell: gridCell,
cellDataLoader: _cellDataLoader,
cellCache: _cellsCache,
cellFieldNotifier: _cellFieldNotifier,
fieldNotifier: _fieldNotifier,
cellDataPersistence: _cellDataPersistence);
}
@ -191,16 +193,18 @@ class IGridCellController<T, D> extends Equatable {
onCellFieldChanged();
}
if (_cellDataLoader.config.reloadOnFieldChanged) {
if (_cellDataLoader.reloadOnFieldChanged) {
_loadData();
}
};
_cellFieldNotifier.addFieldListener(_cacheKey, _onFieldChangedFn!);
_fieldNotifier.register(_cacheKey, _onFieldChangedFn!);
/// Notify the listener, the cell data was changed.
onCellChangedFn() => onCellChanged(_cellDataNotifier?.value);
_cellDataNotifier?.addListener(onCellChangedFn);
// Return the function pointer that can be used when calling removeListener.
return onCellChangedFn;
}
@ -208,22 +212,38 @@ class IGridCellController<T, D> extends Equatable {
_cellDataNotifier?.removeListener(fn);
}
T? getCellData({bool loadIfNoCache = true}) {
/// Return the cell data.
/// The cell data will be read from the Cache first, and load from disk if it does not exist.
/// You can set [loadIfNotExist] to false (default is true) to disable loading the cell data.
T? getCellData({bool loadIfNotExist = true}) {
final data = _cellsCache.get(_cacheKey);
if (data == null && loadIfNoCache) {
if (data == null && loadIfNotExist) {
_loadData();
}
return data;
}
Future<Either<FieldTypeOptionData, FlowyError>> getTypeOptionData() {
return _fieldService.getFieldTypeOptionData(fieldType: fieldType);
/// Return the FieldTypeOptionData that can be parsed into corresponding class using the [parser].
/// [PD] is the type that the parser return.
Future<Either<PD, FlowyError>> getFieldTypeOption<PD, P extends TypeOptionDataParser>(P parser) {
return _fieldService.getFieldTypeOptionData(fieldType: fieldType).then((result) {
return result.fold(
(data) => parser.fromBuffer(data.typeOptionData),
(err) => right(err),
);
});
}
/// Save the cell data to disk
/// You can set [dedeplicate] to true (default is false) to reduce the save operation.
/// It's useful when you call this method when user editing the [TextField].
/// The default debounce interval is 300 milliseconds.
void saveCellData(D data, {bool deduplicate = false, void Function(Option<FlowyError>)? resultCallback}) async {
if (deduplicate) {
_loadDataOperation?.cancel();
_loadDataOperation = Timer(const Duration(milliseconds: 300), () async {
_saveDataOperation?.cancel();
_saveDataOperation = Timer(const Duration(milliseconds: 300), () async {
final result = await _cellDataPersistence.save(data);
if (resultCallback != null) {
resultCallback(result);
@ -238,28 +258,30 @@ class IGridCellController<T, D> extends Equatable {
}
void _loadData() {
_saveDataOperation?.cancel();
_loadDataOperation?.cancel();
_loadDataOperation = Timer(const Duration(milliseconds: 10), () {
_cellDataLoader.loadData().then((data) {
_cellDataNotifier?.value = data;
_cellsCache.insert(_GridCellCacheItem(key: _cacheKey, object: data));
_cellsCache.insert(_GridCellCacheValue(key: _cacheKey, object: data));
});
});
}
void dispose() {
if (isDispose) {
if (_isDispose) {
Log.error("$this should only dispose once");
return;
}
isDispose = true;
_isDispose = true;
_cellListener.stop();
_loadDataOperation?.cancel();
_saveDataOperation?.cancel();
_cellDataNotifier = null;
if (_onFieldChangedFn != null) {
_cellFieldNotifier.removeFieldListener(_cacheKey, _onFieldChangedFn!);
_fieldNotifier.unregister(_cacheKey, _onFieldChangedFn!);
_onFieldChangedFn = null;
}
}

View File

@ -184,7 +184,7 @@ class SelectOptionEditorState with _$SelectOptionEditorState {
}) = _SelectOptionEditorState;
factory SelectOptionEditorState.initial(GridSelectOptionCellController context) {
final data = context.getCellData(loadIfNoCache: false);
final data = context.getCellData(loadIfNotExist: false);
return SelectOptionEditorState(
options: data?.options ?? [],
allOptions: data?.options ?? [],

View File

@ -7,7 +7,7 @@ import 'package:flowy_sdk/protobuf/flowy-grid/select_option.pb.dart';
import 'cell_service/cell_service.dart';
class SelectOptionService {
final GridCell gridCell;
final GridCellIdentifier gridCell;
SelectOptionService({required this.gridCell});
String get gridId => gridCell.gridId;

View File

@ -9,6 +9,10 @@ import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:protobuf/protobuf.dart';
part 'field_service.freezed.dart';
/// FieldService consists of lots of event functions. We define the events in the backend(Rust),
/// you can find the corresponding event implementation in event_map.rs of the corresponding crate.
///
/// You could check out the rust-lib/flowy-grid/event_map.rs for more information.
class FieldService {
final String gridId;
final String fieldId;

View File

@ -8,7 +8,7 @@ part 'date_bloc.freezed.dart';
typedef DateTypeOptionContext = TypeOptionWidgetContext<DateTypeOption>;
class DateTypeOptionDataParser extends TypeOptionWidgetDataParser<DateTypeOption> {
class DateTypeOptionDataParser extends TypeOptionDataParser<DateTypeOption> {
@override
DateTypeOption fromBuffer(List<int> buffer) {
return DateTypeOption.fromBuffer(buffer);

View File

@ -18,7 +18,7 @@ class MultiSelectTypeOptionContext extends TypeOptionWidgetContext<MultiSelectTy
gridId: fieldContext.gridId,
fieldId: fieldContext.field.id,
),
super(dataBuilder: dataBuilder, fieldContext: fieldContext);
super(dataParser: dataBuilder, fieldContext: fieldContext);
@override
List<SelectOption> Function(SelectOption) get deleteOption {
@ -71,7 +71,7 @@ class MultiSelectTypeOptionContext extends TypeOptionWidgetContext<MultiSelectTy
}
}
class MultiSelectTypeOptionWidgetDataParser extends TypeOptionWidgetDataParser<MultiSelectTypeOption> {
class MultiSelectTypeOptionWidgetDataParser extends TypeOptionDataParser<MultiSelectTypeOption> {
@override
MultiSelectTypeOption fromBuffer(List<int> buffer) {
return MultiSelectTypeOption.fromBuffer(buffer);

View File

@ -10,7 +10,7 @@ part 'number_bloc.freezed.dart';
typedef NumberTypeOptionContext = TypeOptionWidgetContext<NumberTypeOption>;
class NumberTypeOptionWidgetDataParser extends TypeOptionWidgetDataParser<NumberTypeOption> {
class NumberTypeOptionWidgetDataParser extends TypeOptionDataParser<NumberTypeOption> {
@override
NumberTypeOption fromBuffer(List<int> buffer) {
return NumberTypeOption.fromBuffer(buffer);

View File

@ -18,7 +18,7 @@ class SingleSelectTypeOptionContext extends TypeOptionWidgetContext<SingleSelect
gridId: fieldContext.gridId,
fieldId: fieldContext.field.id,
),
super(dataBuilder: dataBuilder, fieldContext: fieldContext);
super(dataParser: dataBuilder, fieldContext: fieldContext);
@override
List<SelectOption> Function(SelectOption) get deleteOption {
@ -71,7 +71,7 @@ class SingleSelectTypeOptionContext extends TypeOptionWidgetContext<SingleSelect
}
}
class SingleSelectTypeOptionWidgetDataParser extends TypeOptionWidgetDataParser<SingleSelectTypeOption> {
class SingleSelectTypeOptionWidgetDataParser extends TypeOptionDataParser<SingleSelectTypeOption> {
@override
SingleSelectTypeOption fromBuffer(List<int> buffer) {
return SingleSelectTypeOption.fromBuffer(buffer);

View File

@ -33,17 +33,17 @@ class TypeOptionService {
}
}
abstract class TypeOptionWidgetDataParser<T> {
abstract class TypeOptionDataParser<T> {
T fromBuffer(List<int> buffer);
}
class TypeOptionWidgetContext<T extends GeneratedMessage> {
T? _typeOptionObject;
final GridFieldContext _fieldContext;
final TypeOptionWidgetDataParser<T> dataBuilder;
final TypeOptionDataParser<T> dataParser;
TypeOptionWidgetContext({
required this.dataBuilder,
required this.dataParser,
required GridFieldContext fieldContext,
}) : _fieldContext = fieldContext;
@ -56,7 +56,7 @@ class TypeOptionWidgetContext<T extends GeneratedMessage> {
return _typeOptionObject!;
}
final T object = dataBuilder.fromBuffer(_fieldContext.typeOptionData);
final T object = dataParser.fromBuffer(_fieldContext.typeOptionData);
_typeOptionObject = object;
return object;
}
@ -77,7 +77,7 @@ class TypeOptionContext2<T> {
final Field field;
final FieldService _fieldService;
T? _data;
final TypeOptionWidgetDataParser dataBuilder;
final TypeOptionDataParser dataBuilder;
TypeOptionContext2({
required this.gridId,

View File

@ -20,7 +20,7 @@ class GridBloc extends Bloc<GridEvent, GridState> {
final GridFieldCache fieldCache;
// key: the block id
final LinkedHashMap<String, GridBlockCacheService> _blocks;
final LinkedHashMap<String, GridBlockCache> _blocks;
List<GridRow> get rows {
final List<GridRow> rows = [];
@ -69,7 +69,7 @@ class GridBloc extends Bloc<GridEvent, GridState> {
}
GridRowsCache? getRowCache(String blockId, String rowId) {
final GridBlockCacheService? blockCache = _blocks[blockId];
final GridBlockCache? blockCache = _blocks[blockId];
return blockCache?.rowCache;
}
@ -119,7 +119,7 @@ class GridBloc extends Bloc<GridEvent, GridState> {
return;
}
final cache = GridBlockCacheService(
final cache = GridBlockCache(
gridId: gridId,
block: block,
fieldCache: fieldCache,

View File

@ -186,11 +186,11 @@ class GridFieldCache {
}
}
class GridRowCacheDelegateImpl extends GridRowCacheDelegate {
class GridRowCacheFieldNotifierImpl extends GridRowCacheFieldNotifier {
final GridFieldCache _cache;
FieldChangesetCallback? _onChangesetFn;
FieldsCallback? _onFieldFn;
GridRowCacheDelegateImpl(GridFieldCache cache) : _cache = cache;
GridRowCacheFieldNotifierImpl(GridFieldCache cache) : _cache = cache;
@override
UnmodifiableListView<Field> get fields => _cache.unmodifiableFields;

View File

@ -58,13 +58,13 @@ class RowDetailBloc extends Bloc<RowDetailEvent, RowDetailState> {
@freezed
class RowDetailEvent with _$RowDetailEvent {
const factory RowDetailEvent.initial() = _Initial;
const factory RowDetailEvent.didReceiveCellDatas(List<GridCell> gridCells) = _DidReceiveCellDatas;
const factory RowDetailEvent.didReceiveCellDatas(List<GridCellIdentifier> gridCells) = _DidReceiveCellDatas;
}
@freezed
class RowDetailState with _$RowDetailState {
const factory RowDetailState({
required List<GridCell> gridCells,
required List<GridCellIdentifier> gridCells,
}) = _RowDetailState;
factory RowDetailState.initial() => RowDetailState(

View File

@ -14,7 +14,7 @@ part 'row_service.freezed.dart';
typedef RowUpdateCallback = void Function();
abstract class GridRowCacheDelegate {
abstract class GridRowCacheFieldNotifier {
UnmodifiableListView<Field> get fields;
void onFieldsChanged(VoidCallback callback);
void onFieldChanged(void Function(Field) callback);
@ -27,7 +27,7 @@ class GridRowsCache {
final _Notifier _notifier;
List<GridRow> _rows = [];
final HashMap<String, Row> _rowByRowId;
final GridRowCacheDelegate _delegate;
final GridRowCacheFieldNotifier _fieldNotifier;
final GridCellsCache _cellCache;
List<GridRow> get rows => _rows;
@ -36,19 +36,19 @@ class GridRowsCache {
GridRowsCache({
required this.gridId,
required this.block,
required GridRowCacheDelegate delegate,
required GridRowCacheFieldNotifier notifier,
}) : _cellCache = GridCellsCache(gridId: gridId),
_rowByRowId = HashMap(),
_notifier = _Notifier(),
_delegate = delegate {
_fieldNotifier = notifier {
//
delegate.onFieldsChanged(() => _notifier.receive(const GridRowChangeReason.fieldDidChange()));
delegate.onFieldChanged((field) => _cellCache.remove(field.id));
notifier.onFieldsChanged(() => _notifier.receive(const GridRowChangeReason.fieldDidChange()));
notifier.onFieldChanged((field) => _cellCache.remove(field.id));
_rows = block.rowInfos.map((rowInfo) => buildGridRow(rowInfo.rowId, rowInfo.height.toDouble())).toList();
}
Future<void> dispose() async {
_delegate.dispose();
_fieldNotifier.dispose();
_notifier.dispose();
await _cellCache.dispose();
}
@ -195,9 +195,9 @@ class GridRowsCache {
GridCellMap _makeGridCells(String rowId, Row? row) {
var cellDataMap = GridCellMap.new();
for (final field in _delegate.fields) {
for (final field in _fieldNotifier.fields) {
if (field.visibility) {
cellDataMap[field.id] = GridCell(
cellDataMap[field.id] = GridCellIdentifier(
rowId: rowId,
gridId: gridId,
field: field,
@ -236,7 +236,7 @@ class GridRowsCache {
return GridRow(
gridId: gridId,
blockId: block.id,
fields: _delegate.fields,
fields: _fieldNotifier.fields,
rowId: rowId,
height: rowHeight,
);

View File

@ -21,15 +21,13 @@ class GridCellBuilder {
required this.fieldCache,
});
GridCellWidget build(GridCell cell, {GridCellStyle? style}) {
final key = ValueKey(cell.cellId());
GridCellWidget build(GridCellIdentifier cell, {GridCellStyle? style}) {
final cellControllerBuilder = GridCellControllerBuilder(
gridCell: cell,
cellCache: cellCache,
fieldCache: fieldCache,
);
final key = cell.key();
switch (cell.field.fieldType) {
case FieldType.Checkbox:
return CheckboxCell(cellControllerBuilder: cellControllerBuilder, key: key);

View File

@ -80,7 +80,7 @@ class _DateCellState extends GridCellState<DateCell> {
final calendar = DateCellEditor(onDismissed: () => widget.onCellEditing.value = false);
calendar.show(
context,
cellContext: bloc.cellContext.clone(),
cellController: bloc.cellContext.clone(),
);
}

View File

@ -31,16 +31,16 @@ class DateCellEditor with FlowyOverlayDelegate {
Future<void> show(
BuildContext context, {
required GridDateCellController cellContext,
required GridDateCellController cellController,
}) async {
DateCellEditor.remove(context);
final result = await cellContext.getTypeOptionData();
final result = await cellController.getFieldTypeOption(DateTypeOptionDataParser());
result.fold(
(data) {
(dateTypeOption) {
final calendar = _CellCalendarWidget(
cellContext: cellContext,
dateTypeOption: DateTypeOption.fromBuffer(data.typeOptionData),
cellContext: cellController,
dateTypeOption: dateTypeOption,
);
FlowyOverlay.of(context).insertWithAnchor(

View File

@ -7,9 +7,9 @@ import 'dart:async';
import 'package:flutter_bloc/flutter_bloc.dart';
class URLCellEditor extends StatefulWidget with FlowyOverlayDelegate {
final GridURLCellController cellContext;
final GridURLCellController cellController;
final VoidCallback completed;
const URLCellEditor({required this.cellContext, required this.completed, Key? key}) : super(key: key);
const URLCellEditor({required this.cellController, required this.completed, Key? key}) : super(key: key);
@override
State<URLCellEditor> createState() => _URLCellEditorState();
@ -21,7 +21,7 @@ class URLCellEditor extends StatefulWidget with FlowyOverlayDelegate {
) {
FlowyOverlay.of(context).remove(identifier());
final editor = URLCellEditor(
cellContext: cellContext,
cellController: cellContext,
completed: completed,
);
@ -62,7 +62,7 @@ class _URLCellEditorState extends State<URLCellEditor> {
@override
void initState() {
_cellBloc = URLCellEditorBloc(cellContext: widget.cellContext);
_cellBloc = URLCellEditorBloc(cellContext: widget.cellController);
_cellBloc.add(const URLCellEditorEvent.initial());
_controller = TextEditingController(text: _cellBloc.state.content);

View File

@ -187,7 +187,7 @@ class _CopyURLAccessory extends StatelessWidget with GridCellAccessory {
@override
void onTap() {
final content = cellContext.getCellData(loadIfNoCache: false)?.content ?? "";
final content = cellContext.getCellData(loadIfNotExist: false)?.content ?? "";
Clipboard.setData(ClipboardData(text: content));
showMessageToast(LocaleKeys.grid_row_copyProperty.tr());
}

View File

@ -51,13 +51,13 @@ TypeOptionWidgetBuilder makeTypeOptionWidgetBuilder(
case FieldType.Checkbox:
final context = CheckboxTypeOptionContext(
fieldContext: fieldContext,
dataBuilder: CheckboxTypeOptionWidgetDataParser(),
dataParser: CheckboxTypeOptionWidgetDataParser(),
);
return CheckboxTypeOptionWidgetBuilder(context);
case FieldType.DateTime:
final context = DateTypeOptionContext(
fieldContext: fieldContext,
dataBuilder: DateTypeOptionDataParser(),
dataParser: DateTypeOptionDataParser(),
);
return DateTypeOptionWidgetBuilder(
context,
@ -84,7 +84,7 @@ TypeOptionWidgetBuilder makeTypeOptionWidgetBuilder(
case FieldType.Number:
final context = NumberTypeOptionContext(
fieldContext: fieldContext,
dataBuilder: NumberTypeOptionWidgetDataParser(),
dataParser: NumberTypeOptionWidgetDataParser(),
);
return NumberTypeOptionWidgetBuilder(
context,
@ -93,14 +93,14 @@ TypeOptionWidgetBuilder makeTypeOptionWidgetBuilder(
case FieldType.RichText:
final context = RichTextTypeOptionContext(
fieldContext: fieldContext,
dataBuilder: RichTextTypeOptionWidgetDataParser(),
dataParser: RichTextTypeOptionWidgetDataParser(),
);
return RichTextTypeOptionWidgetBuilder(context);
case FieldType.URL:
final context = URLTypeOptionContext(
fieldContext: fieldContext,
dataBuilder: URLTypeOptionWidgetDataParser(),
dataParser: URLTypeOptionWidgetDataParser(),
);
return URLTypeOptionWidgetBuilder(context);
}

View File

@ -5,7 +5,7 @@ import 'builder.dart';
typedef CheckboxTypeOptionContext = TypeOptionWidgetContext<CheckboxTypeOption>;
class CheckboxTypeOptionWidgetDataParser extends TypeOptionWidgetDataParser<CheckboxTypeOption> {
class CheckboxTypeOptionWidgetDataParser extends TypeOptionDataParser<CheckboxTypeOption> {
@override
CheckboxTypeOption fromBuffer(List<int> buffer) {
return CheckboxTypeOption.fromBuffer(buffer);

View File

@ -5,7 +5,7 @@ import 'builder.dart';
typedef RichTextTypeOptionContext = TypeOptionWidgetContext<RichTextTypeOption>;
class RichTextTypeOptionWidgetDataParser extends TypeOptionWidgetDataParser<RichTextTypeOption> {
class RichTextTypeOptionWidgetDataParser extends TypeOptionDataParser<RichTextTypeOption> {
@override
RichTextTypeOption fromBuffer(List<int> buffer) {
return RichTextTypeOption.fromBuffer(buffer);

View File

@ -5,7 +5,7 @@ import 'builder.dart';
typedef URLTypeOptionContext = TypeOptionWidgetContext<URLTypeOption>;
class URLTypeOptionWidgetDataParser extends TypeOptionWidgetDataParser<URLTypeOption> {
class URLTypeOptionWidgetDataParser extends TypeOptionDataParser<URLTypeOption> {
@override
URLTypeOption fromBuffer(List<int> buffer) {
return URLTypeOption.fromBuffer(buffer);

View File

@ -137,7 +137,7 @@ class _PropertyList extends StatelessWidget {
}
class _RowDetailCell extends StatelessWidget {
final GridCell gridCell;
final GridCellIdentifier gridCell;
final GridCellBuilder cellBuilder;
const _RowDetailCell({
required this.gridCell,