|
@@ -6,12 +6,12 @@ typedef GridDateCellController = IGridCellController<DateCellData, CalendarData>
|
|
typedef GridURLCellController = IGridCellController<URLCellData, String>;
|
|
typedef GridURLCellController = IGridCellController<URLCellData, String>;
|
|
|
|
|
|
class GridCellControllerBuilder {
|
|
class GridCellControllerBuilder {
|
|
- final GridCell _gridCell;
|
|
|
|
|
|
+ final GridCellIdentifier _gridCell;
|
|
final GridCellsCache _cellCache;
|
|
final GridCellsCache _cellCache;
|
|
final GridFieldCache _fieldCache;
|
|
final GridFieldCache _fieldCache;
|
|
|
|
|
|
GridCellControllerBuilder(
|
|
GridCellControllerBuilder(
|
|
- {required GridCell gridCell, required GridCellsCache cellCache, required GridFieldCache fieldCache})
|
|
|
|
|
|
+ {required GridCellIdentifier gridCell, required GridCellsCache cellCache, required GridFieldCache fieldCache})
|
|
: _cellCache = cellCache,
|
|
: _cellCache = cellCache,
|
|
_fieldCache = fieldCache,
|
|
_fieldCache = fieldCache,
|
|
_gridCell = gridCell;
|
|
_gridCell = gridCell;
|
|
@@ -29,34 +29,33 @@ class GridCellControllerBuilder {
|
|
gridCell: _gridCell,
|
|
gridCell: _gridCell,
|
|
cellCache: _cellCache,
|
|
cellCache: _cellCache,
|
|
cellDataLoader: cellDataLoader,
|
|
cellDataLoader: cellDataLoader,
|
|
- cellFieldNotifier: cellFieldNotifier,
|
|
|
|
|
|
+ fieldNotifier: cellFieldNotifier,
|
|
cellDataPersistence: CellDataPersistence(gridCell: _gridCell),
|
|
cellDataPersistence: CellDataPersistence(gridCell: _gridCell),
|
|
);
|
|
);
|
|
case FieldType.DateTime:
|
|
case FieldType.DateTime:
|
|
final cellDataLoader = GridCellDataLoader(
|
|
final cellDataLoader = GridCellDataLoader(
|
|
gridCell: _gridCell,
|
|
gridCell: _gridCell,
|
|
parser: DateCellDataParser(),
|
|
parser: DateCellDataParser(),
|
|
- config: const GridCellDataConfig(reloadOnFieldChanged: true),
|
|
|
|
|
|
+ reloadOnFieldChanged: true,
|
|
);
|
|
);
|
|
|
|
|
|
return GridDateCellController(
|
|
return GridDateCellController(
|
|
gridCell: _gridCell,
|
|
gridCell: _gridCell,
|
|
cellCache: _cellCache,
|
|
cellCache: _cellCache,
|
|
cellDataLoader: cellDataLoader,
|
|
cellDataLoader: cellDataLoader,
|
|
- cellFieldNotifier: cellFieldNotifier,
|
|
|
|
|
|
+ fieldNotifier: cellFieldNotifier,
|
|
cellDataPersistence: DateCellDataPersistence(gridCell: _gridCell),
|
|
cellDataPersistence: DateCellDataPersistence(gridCell: _gridCell),
|
|
);
|
|
);
|
|
case FieldType.Number:
|
|
case FieldType.Number:
|
|
final cellDataLoader = GridCellDataLoader(
|
|
final cellDataLoader = GridCellDataLoader(
|
|
gridCell: _gridCell,
|
|
gridCell: _gridCell,
|
|
parser: StringCellDataParser(),
|
|
parser: StringCellDataParser(),
|
|
- config: const GridCellDataConfig(reloadOnFieldChanged: true),
|
|
|
|
);
|
|
);
|
|
return GridCellController(
|
|
return GridCellController(
|
|
gridCell: _gridCell,
|
|
gridCell: _gridCell,
|
|
cellCache: _cellCache,
|
|
cellCache: _cellCache,
|
|
cellDataLoader: cellDataLoader,
|
|
cellDataLoader: cellDataLoader,
|
|
- cellFieldNotifier: cellFieldNotifier,
|
|
|
|
|
|
+ fieldNotifier: cellFieldNotifier,
|
|
cellDataPersistence: CellDataPersistence(gridCell: _gridCell),
|
|
cellDataPersistence: CellDataPersistence(gridCell: _gridCell),
|
|
);
|
|
);
|
|
case FieldType.RichText:
|
|
case FieldType.RichText:
|
|
@@ -68,7 +67,7 @@ class GridCellControllerBuilder {
|
|
gridCell: _gridCell,
|
|
gridCell: _gridCell,
|
|
cellCache: _cellCache,
|
|
cellCache: _cellCache,
|
|
cellDataLoader: cellDataLoader,
|
|
cellDataLoader: cellDataLoader,
|
|
- cellFieldNotifier: cellFieldNotifier,
|
|
|
|
|
|
+ fieldNotifier: cellFieldNotifier,
|
|
cellDataPersistence: CellDataPersistence(gridCell: _gridCell),
|
|
cellDataPersistence: CellDataPersistence(gridCell: _gridCell),
|
|
);
|
|
);
|
|
case FieldType.MultiSelect:
|
|
case FieldType.MultiSelect:
|
|
@@ -76,14 +75,14 @@ class GridCellControllerBuilder {
|
|
final cellDataLoader = GridCellDataLoader(
|
|
final cellDataLoader = GridCellDataLoader(
|
|
gridCell: _gridCell,
|
|
gridCell: _gridCell,
|
|
parser: SelectOptionCellDataParser(),
|
|
parser: SelectOptionCellDataParser(),
|
|
- config: const GridCellDataConfig(reloadOnFieldChanged: true),
|
|
|
|
|
|
+ reloadOnFieldChanged: true,
|
|
);
|
|
);
|
|
|
|
|
|
return GridSelectOptionCellController(
|
|
return GridSelectOptionCellController(
|
|
gridCell: _gridCell,
|
|
gridCell: _gridCell,
|
|
cellCache: _cellCache,
|
|
cellCache: _cellCache,
|
|
cellDataLoader: cellDataLoader,
|
|
cellDataLoader: cellDataLoader,
|
|
- cellFieldNotifier: cellFieldNotifier,
|
|
|
|
|
|
+ fieldNotifier: cellFieldNotifier,
|
|
cellDataPersistence: CellDataPersistence(gridCell: _gridCell),
|
|
cellDataPersistence: CellDataPersistence(gridCell: _gridCell),
|
|
);
|
|
);
|
|
|
|
|
|
@@ -96,7 +95,7 @@ class GridCellControllerBuilder {
|
|
gridCell: _gridCell,
|
|
gridCell: _gridCell,
|
|
cellCache: _cellCache,
|
|
cellCache: _cellCache,
|
|
cellDataLoader: cellDataLoader,
|
|
cellDataLoader: cellDataLoader,
|
|
- cellFieldNotifier: cellFieldNotifier,
|
|
|
|
|
|
+ fieldNotifier: cellFieldNotifier,
|
|
cellDataPersistence: CellDataPersistence(gridCell: _gridCell),
|
|
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
|
|
// ignore: must_be_immutable
|
|
class IGridCellController<T, D> extends Equatable {
|
|
class IGridCellController<T, D> extends Equatable {
|
|
- final GridCell gridCell;
|
|
|
|
|
|
+ final GridCellIdentifier gridCell;
|
|
final GridCellsCache _cellsCache;
|
|
final GridCellsCache _cellsCache;
|
|
- final GridCellId _cacheKey;
|
|
|
|
|
|
+ final GridCellCacheKey _cacheKey;
|
|
final FieldService _fieldService;
|
|
final FieldService _fieldService;
|
|
- final GridCellFieldNotifier _cellFieldNotifier;
|
|
|
|
- // final GridCellFieldNotifier _fieldNotifier;
|
|
|
|
- final IGridCellDataLoader<T> _cellDataLoader;
|
|
|
|
|
|
+ final GridCellFieldNotifier _fieldNotifier;
|
|
|
|
+ final GridCellDataLoader<T> _cellDataLoader;
|
|
final IGridCellDataPersistence<D> _cellDataPersistence;
|
|
final IGridCellDataPersistence<D> _cellDataPersistence;
|
|
|
|
|
|
late final CellListener _cellListener;
|
|
late final CellListener _cellListener;
|
|
@@ -124,28 +127,27 @@ class IGridCellController<T, D> extends Equatable {
|
|
VoidCallback? _onFieldChangedFn;
|
|
VoidCallback? _onFieldChangedFn;
|
|
Timer? _loadDataOperation;
|
|
Timer? _loadDataOperation;
|
|
Timer? _saveDataOperation;
|
|
Timer? _saveDataOperation;
|
|
- bool isDispose = false;
|
|
|
|
|
|
+ bool _isDispose = false;
|
|
|
|
|
|
IGridCellController({
|
|
IGridCellController({
|
|
required this.gridCell,
|
|
required this.gridCell,
|
|
required GridCellsCache cellCache,
|
|
required GridCellsCache cellCache,
|
|
- required GridCellFieldNotifier cellFieldNotifier,
|
|
|
|
- required IGridCellDataLoader<T> cellDataLoader,
|
|
|
|
|
|
+ required GridCellFieldNotifier fieldNotifier,
|
|
|
|
+ required GridCellDataLoader<T> cellDataLoader,
|
|
required IGridCellDataPersistence<D> cellDataPersistence,
|
|
required IGridCellDataPersistence<D> cellDataPersistence,
|
|
- // required GridFieldChangedNotifier notifierDelegate,
|
|
|
|
}) : _cellsCache = cellCache,
|
|
}) : _cellsCache = cellCache,
|
|
_cellDataLoader = cellDataLoader,
|
|
_cellDataLoader = cellDataLoader,
|
|
_cellDataPersistence = cellDataPersistence,
|
|
_cellDataPersistence = cellDataPersistence,
|
|
- _cellFieldNotifier = cellFieldNotifier,
|
|
|
|
|
|
+ _fieldNotifier = fieldNotifier,
|
|
_fieldService = FieldService(gridId: gridCell.gridId, fieldId: gridCell.field.id),
|
|
_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() {
|
|
IGridCellController<T, D> clone() {
|
|
return IGridCellController(
|
|
return IGridCellController(
|
|
gridCell: gridCell,
|
|
gridCell: gridCell,
|
|
cellDataLoader: _cellDataLoader,
|
|
cellDataLoader: _cellDataLoader,
|
|
cellCache: _cellsCache,
|
|
cellCache: _cellsCache,
|
|
- cellFieldNotifier: _cellFieldNotifier,
|
|
|
|
|
|
+ fieldNotifier: _fieldNotifier,
|
|
cellDataPersistence: _cellDataPersistence);
|
|
cellDataPersistence: _cellDataPersistence);
|
|
}
|
|
}
|
|
|
|
|
|
@@ -191,16 +193,18 @@ class IGridCellController<T, D> extends Equatable {
|
|
onCellFieldChanged();
|
|
onCellFieldChanged();
|
|
}
|
|
}
|
|
|
|
|
|
- if (_cellDataLoader.config.reloadOnFieldChanged) {
|
|
|
|
|
|
+ if (_cellDataLoader.reloadOnFieldChanged) {
|
|
_loadData();
|
|
_loadData();
|
|
}
|
|
}
|
|
};
|
|
};
|
|
|
|
|
|
- _cellFieldNotifier.addFieldListener(_cacheKey, _onFieldChangedFn!);
|
|
|
|
|
|
+ _fieldNotifier.register(_cacheKey, _onFieldChangedFn!);
|
|
|
|
|
|
/// Notify the listener, the cell data was changed.
|
|
/// Notify the listener, the cell data was changed.
|
|
onCellChangedFn() => onCellChanged(_cellDataNotifier?.value);
|
|
onCellChangedFn() => onCellChanged(_cellDataNotifier?.value);
|
|
_cellDataNotifier?.addListener(onCellChangedFn);
|
|
_cellDataNotifier?.addListener(onCellChangedFn);
|
|
|
|
+
|
|
|
|
+ // Return the function pointer that can be used when calling removeListener.
|
|
return onCellChangedFn;
|
|
return onCellChangedFn;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -208,22 +212,38 @@ class IGridCellController<T, D> extends Equatable {
|
|
_cellDataNotifier?.removeListener(fn);
|
|
_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);
|
|
final data = _cellsCache.get(_cacheKey);
|
|
- if (data == null && loadIfNoCache) {
|
|
|
|
|
|
+ if (data == null && loadIfNotExist) {
|
|
_loadData();
|
|
_loadData();
|
|
}
|
|
}
|
|
return data;
|
|
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 {
|
|
void saveCellData(D data, {bool deduplicate = false, void Function(Option<FlowyError>)? resultCallback}) async {
|
|
if (deduplicate) {
|
|
if (deduplicate) {
|
|
_loadDataOperation?.cancel();
|
|
_loadDataOperation?.cancel();
|
|
- _loadDataOperation = Timer(const Duration(milliseconds: 300), () async {
|
|
|
|
|
|
+
|
|
|
|
+ _saveDataOperation?.cancel();
|
|
|
|
+ _saveDataOperation = Timer(const Duration(milliseconds: 300), () async {
|
|
final result = await _cellDataPersistence.save(data);
|
|
final result = await _cellDataPersistence.save(data);
|
|
if (resultCallback != null) {
|
|
if (resultCallback != null) {
|
|
resultCallback(result);
|
|
resultCallback(result);
|
|
@@ -238,28 +258,30 @@ class IGridCellController<T, D> extends Equatable {
|
|
}
|
|
}
|
|
|
|
|
|
void _loadData() {
|
|
void _loadData() {
|
|
|
|
+ _saveDataOperation?.cancel();
|
|
|
|
+
|
|
_loadDataOperation?.cancel();
|
|
_loadDataOperation?.cancel();
|
|
_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(_GridCellCacheItem(key: _cacheKey, object: data));
|
|
|
|
|
|
+ _cellsCache.insert(_GridCellCacheValue(key: _cacheKey, object: data));
|
|
});
|
|
});
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
|
|
void dispose() {
|
|
void dispose() {
|
|
- if (isDispose) {
|
|
|
|
|
|
+ if (_isDispose) {
|
|
Log.error("$this should only dispose once");
|
|
Log.error("$this should only dispose once");
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
- isDispose = true;
|
|
|
|
|
|
+ _isDispose = true;
|
|
_cellListener.stop();
|
|
_cellListener.stop();
|
|
_loadDataOperation?.cancel();
|
|
_loadDataOperation?.cancel();
|
|
_saveDataOperation?.cancel();
|
|
_saveDataOperation?.cancel();
|
|
_cellDataNotifier = null;
|
|
_cellDataNotifier = null;
|
|
|
|
|
|
if (_onFieldChangedFn != null) {
|
|
if (_onFieldChangedFn != null) {
|
|
- _cellFieldNotifier.removeFieldListener(_cacheKey, _onFieldChangedFn!);
|
|
|
|
|
|
+ _fieldNotifier.unregister(_cacheKey, _onFieldChangedFn!);
|
|
_onFieldChangedFn = null;
|
|
_onFieldChangedFn = null;
|
|
}
|
|
}
|
|
}
|
|
}
|