chore: cache row data

This commit is contained in:
appflowy 2022-04-16 20:20:00 +08:00
parent 792f8b95aa
commit 3cc7c8e6de
17 changed files with 247 additions and 225 deletions

View File

@ -150,13 +150,6 @@ void _resolveGridDeps(GetIt getIt) {
(view, _) => GridBloc(view: view), (view, _) => GridBloc(view: view),
); );
getIt.registerFactoryParam<RowBloc, RowData, GridFieldCache>(
(data, fieldCache) => RowBloc(
rowData: data,
fieldCache: fieldCache,
),
);
getIt.registerFactoryParam<GridHeaderBloc, String, GridFieldCache>( getIt.registerFactoryParam<GridHeaderBloc, String, GridFieldCache>(
(gridId, fieldCache) => GridHeaderBloc( (gridId, fieldCache) => GridHeaderBloc(
gridId: gridId, gridId: gridId,

View File

@ -58,12 +58,11 @@ class CheckboxCellBloc extends Bloc<CheckboxCellEvent, CheckboxCellState> {
fieldId: state.cellData.field.id, fieldId: state.cellData.field.id,
rowId: state.cellData.rowId, rowId: state.cellData.rowId,
); );
if (isClosed) {
return;
}
result.fold( result.fold(
(cell) { (cell) => add(CheckboxCellEvent.didReceiveCellUpdate(cell)),
if (!isClosed) {
add(CheckboxCellEvent.didReceiveCellUpdate(cell));
}
},
(err) => Log.error(err), (err) => Log.error(err),
); );
} }

View File

@ -57,19 +57,15 @@ class DateCellBloc extends Bloc<DateCellEvent, DateCellState> {
(notificationData) => _loadCellData(), (notificationData) => _loadCellData(),
(err) => Log.error(err), (err) => Log.error(err),
); );
}); }, listenWhen: () => !isClosed);
_cellListener.start(); _cellListener.start();
_fieldListener.updateFieldNotifier?.addPublishListener((result) { _fieldListener.updateFieldNotifier?.addPublishListener((result) {
result.fold( result.fold(
(field) { (field) => add(DateCellEvent.didReceiveFieldUpdate(field)),
if (!isClosed) {
add(DateCellEvent.didReceiveFieldUpdate(field));
}
},
(err) => Log.error(err), (err) => Log.error(err),
); );
}); }, listenWhen: () => !isClosed);
_fieldListener.start(); _fieldListener.start();
} }
@ -79,12 +75,11 @@ class DateCellBloc extends Bloc<DateCellEvent, DateCellState> {
fieldId: state.cellData.field.id, fieldId: state.cellData.field.id,
rowId: state.cellData.rowId, rowId: state.cellData.rowId,
); );
if (isClosed) {
return;
}
result.fold( result.fold(
(cell) { (cell) => add(DateCellEvent.didReceiveCellUpdate(cell)),
if (!isClosed) {
add(DateCellEvent.didReceiveCellUpdate(cell));
}
},
(err) => Log.error(err), (err) => Log.error(err),
); );
} }

View File

@ -84,12 +84,12 @@ class NumberCellBloc extends Bloc<NumberCellEvent, NumberCellState> {
fieldId: state.cellData.field.id, fieldId: state.cellData.field.id,
rowId: state.cellData.rowId, rowId: state.cellData.rowId,
); );
if (isClosed) {
return;
}
result.fold( result.fold(
(cell) { (cell) => add(NumberCellEvent.didReceiveCellUpdate(cell)),
if (!isClosed) {
add(NumberCellEvent.didReceiveCellUpdate(cell));
}
},
(err) => Log.error(err), (err) => Log.error(err),
); );
} }

View File

@ -49,16 +49,15 @@ class SelectionCellBloc extends Bloc<SelectionCellEvent, SelectionCellState> {
fieldId: state.cellData.field.id, fieldId: state.cellData.field.id,
rowId: state.cellData.rowId, rowId: state.cellData.rowId,
); );
if (isClosed) {
return;
}
result.fold( result.fold(
(selectOptionContext) { (selectOptionContext) => add(SelectionCellEvent.didReceiveOptions(
if (!isClosed) { selectOptionContext.options,
add(SelectionCellEvent.didReceiveOptions( selectOptionContext.selectOptions,
selectOptionContext.options, )),
selectOptionContext.selectOptions,
));
}
},
(err) => Log.error(err), (err) => Log.error(err),
); );
} }

View File

@ -117,16 +117,15 @@ class SelectOptionEditorBloc extends Bloc<SelectOptionEditorEvent, SelectOptionE
fieldId: state.field.id, fieldId: state.field.id,
rowId: state.rowId, rowId: state.rowId,
); );
if (isClosed) {
return;
}
result.fold( result.fold(
(selectOptionContext) { (selectOptionContext) => add(SelectOptionEditorEvent.didReceiveOptions(
if (!isClosed) { selectOptionContext.options,
add(SelectOptionEditorEvent.didReceiveOptions( selectOptionContext.selectOptions,
selectOptionContext.options, )),
selectOptionContext.selectOptions,
));
}
},
(err) => Log.error(err), (err) => Log.error(err),
); );
}, },
@ -144,14 +143,10 @@ class SelectOptionEditorBloc extends Bloc<SelectOptionEditorEvent, SelectOptionE
_fieldListener.updateFieldNotifier?.addPublishListener((result) { _fieldListener.updateFieldNotifier?.addPublishListener((result) {
result.fold( result.fold(
(field) { (field) => add(SelectOptionEditorEvent.didReceiveFieldUpdate(field)),
if (!isClosed) {
add(SelectOptionEditorEvent.didReceiveFieldUpdate(field));
}
},
(err) => Log.error(err), (err) => Log.error(err),
); );
}); }, listenWhen: () => !isClosed);
_fieldListener.start(); _fieldListener.start();
} }
} }

View File

@ -47,14 +47,10 @@ class FieldCellBloc extends Bloc<FieldCellEvent, FieldCellState> {
void _startListening() { void _startListening() {
_fieldListener.updateFieldNotifier?.addPublishListener((result) { _fieldListener.updateFieldNotifier?.addPublishListener((result) {
result.fold( result.fold(
(field) { (field) => add(FieldCellEvent.didReceiveFieldUpdate(field)),
if (!isClosed) {
add(FieldCellEvent.didReceiveFieldUpdate(field));
}
},
(err) => Log.error(err), (err) => Log.error(err),
); );
}); }, listenWhen: () => !isClosed);
_fieldListener.start(); _fieldListener.start();
} }
} }

View File

@ -18,14 +18,14 @@ class GridBloc extends Bloc<GridEvent, GridState> {
final GridListener _gridListener; final GridListener _gridListener;
final GridFieldsListener _fieldListener; final GridFieldsListener _fieldListener;
final GridFieldCache fieldCache; final GridFieldCache fieldCache;
final GridRowCache _rowCache; final GridRowCache rowCache;
GridBloc({required View view}) GridBloc({required View view})
: _fieldListener = GridFieldsListener(gridId: view.id), : _fieldListener = GridFieldsListener(gridId: view.id),
_gridService = GridService(gridId: view.id), _gridService = GridService(gridId: view.id),
_gridListener = GridListener(gridId: view.id), _gridListener = GridListener(gridId: view.id),
fieldCache = GridFieldCache(), fieldCache = GridFieldCache(),
_rowCache = GridRowCache(gridId: view.id), rowCache = GridRowCache(gridId: view.id),
super(GridState.initial(view.id)) { super(GridState.initial(view.id)) {
on<GridEvent>( on<GridEvent>(
(event, emit) async { (event, emit) async {
@ -41,7 +41,7 @@ class GridBloc extends Bloc<GridEvent, GridState> {
emit(state.copyWith(rows: value.rows, listState: value.listState)); emit(state.copyWith(rows: value.rows, listState: value.listState));
}, },
didReceiveFieldUpdate: (_DidReceiveFieldUpdate value) { didReceiveFieldUpdate: (_DidReceiveFieldUpdate value) {
emit(state.copyWith(rows: _rowCache.rows, fields: value.fields)); emit(state.copyWith(rows: rowCache.rows, fields: value.fields));
}, },
); );
}, },
@ -62,7 +62,7 @@ class GridBloc extends Bloc<GridEvent, GridState> {
result.fold( result.fold(
(changeset) { (changeset) {
fieldCache.applyChangeset(changeset); fieldCache.applyChangeset(changeset);
_rowCache.updateFields(fieldCache.unmodifiableFields); rowCache.updateFields(fieldCache.unmodifiableFields);
add(GridEvent.didReceiveFieldUpdate(fieldCache.clonedFields)); add(GridEvent.didReceiveFieldUpdate(fieldCache.clonedFields));
}, },
(err) => Log.error(err), (err) => Log.error(err),
@ -74,15 +74,15 @@ class GridBloc extends Bloc<GridEvent, GridState> {
result.fold( result.fold(
(changesets) { (changesets) {
for (final changeset in changesets) { for (final changeset in changesets) {
_rowCache rowCache
.deleteRows(changeset.deletedRows) .deleteRows(changeset.deletedRows)
.foldRight(null, (listState, _) => add(GridEvent.didReceiveRowUpdate(_rowCache.rows, listState))); .foldRight(null, (listState, _) => add(GridEvent.didReceiveRowUpdate(rowCache.rows, listState)));
_rowCache rowCache
.insertRows(changeset.insertedRows) .insertRows(changeset.insertedRows)
.foldRight(null, (listState, _) => add(GridEvent.didReceiveRowUpdate(_rowCache.rows, listState))); .foldRight(null, (listState, _) => add(GridEvent.didReceiveRowUpdate(rowCache.rows, listState)));
_rowCache.updateRows(changeset.updatedRows); rowCache.updateRows(changeset.updatedRows);
} }
}, },
(err) => Log.error(err), (err) => Log.error(err),
@ -107,12 +107,12 @@ class GridBloc extends Bloc<GridEvent, GridState> {
() => result.fold( () => result.fold(
(fields) { (fields) {
fieldCache.clonedFields = fields.items; fieldCache.clonedFields = fields.items;
_rowCache.updateWithBlock(grid.blockOrders, fieldCache.unmodifiableFields); rowCache.updateWithBlock(grid.blockOrders, fieldCache.unmodifiableFields);
emit(state.copyWith( emit(state.copyWith(
grid: Some(grid), grid: Some(grid),
fields: fieldCache.clonedFields, fields: fieldCache.clonedFields,
rows: _rowCache.rows, rows: rowCache.rows,
loadingState: GridLoadingState.finish(left(unit)), loadingState: GridLoadingState.finish(left(unit)),
)); ));
}, },
@ -126,7 +126,7 @@ class GridBloc extends Bloc<GridEvent, GridState> {
class GridEvent with _$GridEvent { class GridEvent with _$GridEvent {
const factory GridEvent.initial() = InitialGrid; const factory GridEvent.initial() = InitialGrid;
const factory GridEvent.createRow() = _CreateRow; const factory GridEvent.createRow() = _CreateRow;
const factory GridEvent.didReceiveRowUpdate(List<RowData> rows, GridListState listState) = _DidReceiveRowUpdate; const factory GridEvent.didReceiveRowUpdate(List<GridRow> rows, GridListState listState) = _DidReceiveRowUpdate;
const factory GridEvent.didReceiveFieldUpdate(List<Field> fields) = _DidReceiveFieldUpdate; const factory GridEvent.didReceiveFieldUpdate(List<Field> fields) = _DidReceiveFieldUpdate;
} }
@ -136,7 +136,7 @@ class GridState with _$GridState {
required String gridId, required String gridId,
required Option<Grid> grid, required Option<Grid> grid,
required List<Field> fields, required List<Field> fields,
required List<RowData> rows, required List<GridRow> rows,
required GridLoadingState loadingState, required GridLoadingState loadingState,
required GridListState listState, required GridListState listState,
}) = _GridState; }) = _GridState;

View File

@ -36,11 +36,11 @@ class GridHeaderBloc extends Bloc<GridHeaderEvent, GridHeaderState> {
} }
Future<void> _startListening() async { Future<void> _startListening() async {
fieldCache.addListener(() {}, onChanged: (fields) { fieldCache.addListener(
if (!isClosed) { () {},
add(GridHeaderEvent.didReceiveFieldUpdate(fields)); onChanged: (fields) => add(GridHeaderEvent.didReceiveFieldUpdate(fields)),
} listenWhen: () => !isClosed,
}); );
} }
@override @override

View File

@ -5,9 +5,6 @@ import 'package:flowy_sdk/protobuf/flowy-folder-data-model/view.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:app_flowy/workspace/application/grid/row/row_service.dart';
part 'grid_service.freezed.dart';
class GridService { class GridService {
final String gridId; final String gridId;
@ -74,11 +71,16 @@ class GridFieldCache {
_fieldNotifier.addListener(() => onFieldChanged(clonedFields)); _fieldNotifier.addListener(() => onFieldChanged(clonedFields));
} }
void addListener(VoidCallback listener, {void Function(List<Field>)? onChanged}) { void addListener(VoidCallback listener, {void Function(List<Field>)? onChanged, bool Function()? listenWhen}) {
_fieldNotifier.addListener(() { _fieldNotifier.addListener(() {
if (onChanged != null) { if (onChanged != null) {
onChanged(clonedFields); onChanged(clonedFields);
} }
if (listenWhen != null && listenWhen() == false) {
return;
}
listener(); listener();
}); });
} }
@ -130,98 +132,3 @@ class GridFieldCache {
_fieldNotifier.dispose(); _fieldNotifier.dispose();
} }
} }
class GridRowCache {
final String gridId;
UnmodifiableListView<Field> _fields = UnmodifiableListView([]);
List<RowData> _rows = [];
GridRowCache({required this.gridId});
List<RowData> get rows => [..._rows];
void updateWithBlock(List<GridBlockOrder> blocks, UnmodifiableListView<Field> fields) {
_fields = fields;
_rows = blocks.expand((block) => block.rowOrders).map((rowOrder) {
return RowData.fromBlockRow(gridId, rowOrder, _fields);
}).toList();
}
void updateFields(UnmodifiableListView<Field> fields) {
if (fields.isEmpty) {
return;
}
_fields = fields;
_rows = _rows.map((row) => row.copyWith(fields: fields)).toList();
}
Option<GridListState> deleteRows(List<RowOrder> deletedRows) {
if (deletedRows.isEmpty) {
return none();
}
final List<RowData> newRows = [];
final DeletedIndex deletedIndex = [];
final Map<String, RowOrder> deletedRowMap = {for (var rowOrder in deletedRows) rowOrder.rowId: rowOrder};
_rows.asMap().forEach((index, value) {
if (deletedRowMap[value.rowId] == null) {
newRows.add(value);
} else {
deletedIndex.add(Tuple2(index, value));
}
});
_rows = newRows;
return Some(GridListState.delete(deletedIndex));
}
Option<GridListState> insertRows(List<IndexRowOrder> createdRows) {
if (createdRows.isEmpty) {
return none();
}
InsertedIndexs insertIndexs = [];
for (final newRow in createdRows) {
if (newRow.hasIndex()) {
insertIndexs.add(Tuple2(newRow.index, newRow.rowOrder.rowId));
_rows.insert(newRow.index, _toRowData(newRow.rowOrder));
} else {
insertIndexs.add(Tuple2(newRow.index, newRow.rowOrder.rowId));
_rows.add(_toRowData(newRow.rowOrder));
}
}
return Some(GridListState.insert(insertIndexs));
}
void updateRows(List<RowOrder> updatedRows) {
if (updatedRows.isEmpty) {
return;
}
final List<int> updatedIndexs = [];
for (final updatedRow in updatedRows) {
final index = _rows.indexWhere((row) => row.rowId == updatedRow.rowId);
if (index != -1) {
_rows.removeAt(index);
_rows.insert(index, _toRowData(updatedRow));
updatedIndexs.add(index);
}
}
}
RowData _toRowData(RowOrder rowOrder) {
return RowData.fromBlockRow(gridId, rowOrder, _fields);
}
}
typedef InsertedIndexs = List<Tuple2<int, String>>;
typedef DeletedIndex = List<Tuple2<int, RowData>>;
@freezed
class GridListState with _$GridListState {
const factory GridListState.insert(InsertedIndexs items) = _Insert;
const factory GridListState.delete(DeletedIndex items) = _Delete;
const factory GridListState.initial() = InitialListState;
}

View File

@ -11,7 +11,7 @@ part 'row_action_sheet_bloc.freezed.dart';
class RowActionSheetBloc extends Bloc<RowActionSheetEvent, RowActionSheetState> { class RowActionSheetBloc extends Bloc<RowActionSheetEvent, RowActionSheetState> {
final RowService _rowService; final RowService _rowService;
RowActionSheetBloc({required RowData rowData}) RowActionSheetBloc({required GridRow rowData})
: _rowService = RowService(gridId: rowData.gridId, rowId: rowData.rowId), : _rowService = RowService(gridId: rowData.gridId, rowId: rowData.rowId),
super(RowActionSheetState.initial(rowData)) { super(RowActionSheetState.initial(rowData)) {
on<RowActionSheetEvent>( on<RowActionSheetEvent>(
@ -49,10 +49,10 @@ class RowActionSheetEvent with _$RowActionSheetEvent {
@freezed @freezed
class RowActionSheetState with _$RowActionSheetState { class RowActionSheetState with _$RowActionSheetState {
const factory RowActionSheetState({ const factory RowActionSheetState({
required RowData rowData, required GridRow rowData,
}) = _RowActionSheetState; }) = _RowActionSheetState;
factory RowActionSheetState.initial(RowData rowData) => RowActionSheetState( factory RowActionSheetState.initial(GridRow rowData) => RowActionSheetState(
rowData: rowData, rowData: rowData,
); );
} }

View File

@ -18,11 +18,16 @@ class RowBloc extends Bloc<RowEvent, RowState> {
final RowService _rowService; final RowService _rowService;
final RowListener _rowlistener; final RowListener _rowlistener;
final GridFieldCache _fieldCache; final GridFieldCache _fieldCache;
final GridRowCache _rowCache;
RowBloc({required RowData rowData, required GridFieldCache fieldCache}) RowBloc({
: _rowService = RowService(gridId: rowData.gridId, rowId: rowData.rowId), required GridRow rowData,
_fieldCache = fieldCache, required GridFieldCache fieldCache,
required GridRowCache rowCache,
}) : _rowService = RowService(gridId: rowData.gridId, rowId: rowData.rowId),
_rowlistener = RowListener(rowId: rowData.rowId), _rowlistener = RowListener(rowId: rowData.rowId),
_fieldCache = fieldCache,
_rowCache = rowCache,
super(RowState.initial(rowData)) { super(RowState.initial(rowData)) {
on<RowEvent>( on<RowEvent>(
(event, emit) async { (event, emit) async {
@ -76,37 +81,30 @@ class RowBloc extends Bloc<RowEvent, RowState> {
} }
Future<void> _startListening() async { Future<void> _startListening() async {
_rowlistener.updateRowNotifier?.addPublishListener((result) { _rowlistener.updateRowNotifier?.addPublishListener(
result.fold( (result) {
(row) { result.fold(
if (!isClosed) { (row) => add(RowEvent.didUpdateRow(row)),
add(RowEvent.didUpdateRow(row)); (err) => Log.error(err),
} );
}, },
(err) => Log.error(err), listenWhen: () => !isClosed,
); );
});
_fieldCache.addListener(() { _fieldCache.addListener(
if (!isClosed) { () => add(const RowEvent.fieldsDidUpdate()),
add(const RowEvent.fieldsDidUpdate()); listenWhen: () => !isClosed,
} );
});
_rowlistener.start(); _rowlistener.start();
} }
Future<void> _loadRow(Emitter<RowState> emit) async { Future<void> _loadRow(Emitter<RowState> emit) async {
_rowService.getRow().then((result) { final data = await _rowCache.getRowData(state.rowData.rowId);
return result.fold( if (isClosed) {
(row) { return;
if (!isClosed) { }
add(RowEvent.didLoadRow(row)); data.foldRight(null, (data, _) => add(RowEvent.didLoadRow(data)));
}
},
(err) => Log.error(err),
);
});
} }
CellDataMap _makeCellDatas(Row row, List<Field> fields) { CellDataMap _makeCellDatas(Row row, List<Field> fields) {
@ -137,12 +135,12 @@ class RowEvent with _$RowEvent {
@freezed @freezed
class RowState with _$RowState { class RowState with _$RowState {
const factory RowState({ const factory RowState({
required RowData rowData, required GridRow rowData,
required Future<Option<Row>> row, required Future<Option<Row>> row,
required Option<CellDataMap> cellDataMap, required Option<CellDataMap> cellDataMap,
}) = _RowState; }) = _RowState;
factory RowState.initial(RowData rowData) => RowState( factory RowState.initial(GridRow rowData) => RowState(
rowData: rowData, rowData: rowData,
row: Future(() => none()), row: Future(() => none()),
cellDataMap: none(), cellDataMap: none(),

View File

@ -1,5 +1,8 @@
import 'dart:collection';
import 'package:dartz/dartz.dart'; import 'package:dartz/dartz.dart';
import 'package:flowy_sdk/dispatch/dispatch.dart'; import 'package:flowy_sdk/dispatch/dispatch.dart';
import 'package:flowy_sdk/log.dart';
import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-grid/row_entities.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-grid/row_entities.pb.dart';
@ -57,6 +60,115 @@ class RowService {
} }
} }
class GridRowCache {
final String gridId;
UnmodifiableListView<Field> _fields = UnmodifiableListView([]);
HashMap<String, Row> rowDataMap = HashMap();
List<GridRow> _rows = [];
GridRowCache({required this.gridId});
List<GridRow> get rows => [..._rows];
Future<Option<Row>> getRowData(String rowId) async {
final Row? data = rowDataMap[rowId];
if (data != null) {
return Future(() => Some(data));
}
final payload = RowIdentifierPayload.create()
..gridId = gridId
..rowId = rowId;
final result = await GridEventGetRow(payload).send();
return Future(() {
return result.fold(
(data) {
data.freeze();
rowDataMap[data.id] = data;
return Some(data);
},
(err) {
Log.error(err);
return none();
},
);
});
}
void updateWithBlock(List<GridBlockOrder> blocks, UnmodifiableListView<Field> fields) {
_fields = fields;
_rows = blocks.expand((block) => block.rowOrders).map((rowOrder) {
return GridRow.fromBlockRow(gridId, rowOrder, _fields);
}).toList();
}
void updateFields(UnmodifiableListView<Field> fields) {
if (fields.isEmpty) {
return;
}
_fields = fields;
_rows = _rows.map((row) => row.copyWith(fields: fields)).toList();
}
Option<GridListState> deleteRows(List<RowOrder> deletedRows) {
if (deletedRows.isEmpty) {
return none();
}
final List<GridRow> newRows = [];
final DeletedIndex deletedIndex = [];
final Map<String, RowOrder> deletedRowMap = {for (var rowOrder in deletedRows) rowOrder.rowId: rowOrder};
_rows.asMap().forEach((index, value) {
if (deletedRowMap[value.rowId] == null) {
newRows.add(value);
} else {
deletedIndex.add(Tuple2(index, value));
}
});
_rows = newRows;
return Some(GridListState.delete(deletedIndex));
}
Option<GridListState> insertRows(List<IndexRowOrder> createdRows) {
if (createdRows.isEmpty) {
return none();
}
InsertedIndexs insertIndexs = [];
for (final createdRow in createdRows) {
final gridRow = GridRow.fromBlockRow(gridId, createdRow.rowOrder, _fields);
insertIndexs.add(Tuple2(createdRow.index, gridRow.rowId));
_rows.insert(createdRow.index, gridRow);
}
return Some(GridListState.insert(insertIndexs));
}
void updateRows(List<RowOrder> updatedRows) {
if (updatedRows.isEmpty) {
return;
}
final List<int> updatedIndexs = [];
for (final updatedRow in updatedRows) {
final index = _rows.indexWhere((row) => row.rowId == updatedRow.rowId);
if (index != -1) {
_rows.removeAt(index);
_rows.insert(index, _toRowData(updatedRow));
updatedIndexs.add(index);
}
}
}
GridRow _toRowData(RowOrder rowOrder) {
return GridRow.fromBlockRow(gridId, rowOrder, _fields);
}
}
@freezed @freezed
class CellData with _$CellData { class CellData with _$CellData {
const factory CellData({ const factory CellData({
@ -68,20 +180,32 @@ class CellData with _$CellData {
} }
@freezed @freezed
class RowData with _$RowData { class GridRow with _$GridRow {
const factory RowData({ const factory GridRow({
required String gridId, required String gridId,
required String rowId, required String rowId,
required List<Field> fields, required List<Field> fields,
required double height, required double height,
}) = _RowData; required Future<Option<Row>> data,
}) = _GridRow;
factory RowData.fromBlockRow(String gridId, RowOrder row, List<Field> fields) { factory GridRow.fromBlockRow(String gridId, RowOrder row, List<Field> fields) {
return RowData( return GridRow(
gridId: gridId, gridId: gridId,
rowId: row.rowId,
fields: fields, fields: fields,
rowId: row.rowId,
data: Future(() => none()),
height: row.height.toDouble(), height: row.height.toDouble(),
); );
} }
} }
typedef InsertedIndexs = List<Tuple2<int, String>>;
typedef DeletedIndex = List<Tuple2<int, GridRow>>;
@freezed
class GridListState with _$GridListState {
const factory GridListState.insert(InsertedIndexs items) = _Insert;
const factory GridListState.delete(DeletedIndex items) = _Delete;
const factory GridListState.initial() = InitialListState;
}

View File

@ -1,5 +1,6 @@
import 'package:app_flowy/startup/startup.dart'; import 'package:app_flowy/startup/startup.dart';
import 'package:app_flowy/workspace/application/grid/grid_bloc.dart'; import 'package:app_flowy/workspace/application/grid/grid_bloc.dart';
import 'package:app_flowy/workspace/application/grid/row/row_bloc.dart';
import 'package:app_flowy/workspace/application/grid/row/row_service.dart'; import 'package:app_flowy/workspace/application/grid/row/row_service.dart';
import 'package:flowy_infra_ui/style_widget/scrolling/styled_list.dart'; import 'package:flowy_infra_ui/style_widget/scrolling/styled_list.dart';
import 'package:flowy_infra_ui/style_widget/scrolling/styled_scroll_bar.dart'; import 'package:flowy_infra_ui/style_widget/scrolling/styled_scroll_bar.dart';
@ -221,14 +222,19 @@ class _GridRowsState extends State<_GridRows> {
); );
} }
Widget _renderRow(BuildContext context, RowData rowData, Animation<double> animation) { Widget _renderRow(BuildContext context, GridRow rowData, Animation<double> animation) {
final fieldCache = context.read<GridBloc>().fieldCache; final bloc = context.read<GridBloc>();
final fieldCache = bloc.fieldCache;
final rowCache = bloc.rowCache;
return SizeTransition( return SizeTransition(
sizeFactor: animation, sizeFactor: animation,
child: GridRowWidget( child: GridRowWidget(
data: rowData, blocBuilder: () => RowBloc(
fieldCache: fieldCache, rowData: rowData,
fieldCache: fieldCache,
rowCache: rowCache,
),
key: ValueKey(rowData.rowId), key: ValueKey(rowData.rowId),
), ),
); );

View File

@ -12,9 +12,12 @@ import 'package:provider/provider.dart';
import 'row_action_sheet.dart'; import 'row_action_sheet.dart';
class GridRowWidget extends StatefulWidget { class GridRowWidget extends StatefulWidget {
final RowData data; final RowBloc Function() blocBuilder;
final GridFieldCache fieldCache;
const GridRowWidget({required this.data, required this.fieldCache, Key? key}) : super(key: key); const GridRowWidget({
required this.blocBuilder,
Key? key,
}) : super(key: key);
@override @override
State<GridRowWidget> createState() => _GridRowWidgetState(); State<GridRowWidget> createState() => _GridRowWidgetState();
@ -26,7 +29,8 @@ class _GridRowWidgetState extends State<GridRowWidget> {
@override @override
void initState() { void initState() {
_rowBloc = getIt<RowBloc>(param1: widget.data, param2: widget.fieldCache)..add(const RowEvent.initial()); _rowBloc = widget.blocBuilder();
_rowBloc.add(const RowEvent.initial());
_rowStateNotifier = _RegionStateNotifier(); _rowStateNotifier = _RegionStateNotifier();
super.initState(); super.initState();
} }

View File

@ -14,7 +14,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
class GridRowActionSheet extends StatelessWidget { class GridRowActionSheet extends StatelessWidget {
final RowData rowData; final GridRow rowData;
const GridRowActionSheet({required this.rowData, Key? key}) : super(key: key); const GridRowActionSheet({required this.rowData, Key? key}) : super(key: key);
@override @override

View File

@ -31,12 +31,18 @@ class PublishNotifier<T> extends ChangeNotifier {
T? get currentValue => _value; T? get currentValue => _value;
void addPublishListener(void Function(T) callback) { void addPublishListener(void Function(T) callback, {bool Function()? listenWhen}) {
super.addListener( super.addListener(
() { () {
if (_value != null) { if (_value == null) {
callback(_value!); return;
} }
if (listenWhen != null && listenWhen() == false) {
return;
}
callback(_value!);
}, },
); );
} }