mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
chore: renmae property & add documentation
This commit is contained in:
@ -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),
|
@ -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) {
|
@ -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 {
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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 {
|
||||||
|
@ -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 {
|
||||||
|
@ -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(
|
||||||
|
@ -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: '',
|
||||||
|
@ -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 {
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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) {
|
||||||
|
@ -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>(
|
||||||
|
@ -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,
|
||||||
);
|
);
|
||||||
|
@ -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()));
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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 {
|
||||||
|
@ -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:
|
||||||
|
@ -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,
|
||||||
),
|
),
|
||||||
|
@ -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,
|
||||||
|
@ -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"),
|
||||||
);
|
);
|
||||||
|
@ -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,
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
Reference in New Issue
Block a user