mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
chore: replace SliverList with SliverAnimatedList
This commit is contained in:
parent
6af78641d2
commit
31b2ace48f
@ -59,7 +59,11 @@ class CheckboxCellBloc extends Bloc<CheckboxCellEvent, CheckboxCellState> {
|
||||
rowId: state.cellData.rowId,
|
||||
);
|
||||
result.fold(
|
||||
(cell) => add(CheckboxCellEvent.didReceiveCellUpdate(cell)),
|
||||
(cell) {
|
||||
if (!isClosed) {
|
||||
add(CheckboxCellEvent.didReceiveCellUpdate(cell));
|
||||
}
|
||||
},
|
||||
(err) => Log.error(err),
|
||||
);
|
||||
}
|
||||
|
@ -72,7 +72,11 @@ class DateCellBloc extends Bloc<DateCellEvent, DateCellState> {
|
||||
rowId: state.cellData.rowId,
|
||||
);
|
||||
result.fold(
|
||||
(cell) => add(DateCellEvent.didReceiveCellUpdate(cell)),
|
||||
(cell) {
|
||||
if (!isClosed) {
|
||||
add(DateCellEvent.didReceiveCellUpdate(cell));
|
||||
}
|
||||
},
|
||||
(err) => Log.error(err),
|
||||
);
|
||||
}
|
||||
|
@ -59,21 +59,29 @@ class NumberCellBloc extends Bloc<NumberCellEvent, NumberCellState> {
|
||||
_listener.updateCellNotifier.addPublishListener((result) {
|
||||
result.fold(
|
||||
(notificationData) async {
|
||||
final result = await _service.getCell(
|
||||
gridId: state.cellData.gridId,
|
||||
fieldId: state.cellData.field.id,
|
||||
rowId: state.cellData.rowId,
|
||||
);
|
||||
result.fold(
|
||||
(cell) => add(NumberCellEvent.didReceiveCellUpdate(cell)),
|
||||
(err) => Log.error(err),
|
||||
);
|
||||
await _getCellData();
|
||||
},
|
||||
(err) => Log.error(err),
|
||||
);
|
||||
});
|
||||
_listener.start();
|
||||
}
|
||||
|
||||
Future<void> _getCellData() async {
|
||||
final result = await _service.getCell(
|
||||
gridId: state.cellData.gridId,
|
||||
fieldId: state.cellData.field.id,
|
||||
rowId: state.cellData.rowId,
|
||||
);
|
||||
result.fold(
|
||||
(cell) {
|
||||
if (!isClosed) {
|
||||
add(NumberCellEvent.didReceiveCellUpdate(cell));
|
||||
}
|
||||
},
|
||||
(err) => Log.error(err),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@freezed
|
||||
|
@ -51,10 +51,14 @@ class SelectionCellBloc extends Bloc<SelectionCellEvent, SelectionCellState> {
|
||||
);
|
||||
|
||||
result.fold(
|
||||
(selectOptionContext) => add(SelectionCellEvent.didReceiveOptions(
|
||||
selectOptionContext.options,
|
||||
selectOptionContext.selectOptions,
|
||||
)),
|
||||
(selectOptionContext) {
|
||||
if (!isClosed) {
|
||||
add(SelectionCellEvent.didReceiveOptions(
|
||||
selectOptionContext.options,
|
||||
selectOptionContext.selectOptions,
|
||||
));
|
||||
}
|
||||
},
|
||||
(err) => Log.error(err),
|
||||
);
|
||||
}
|
||||
|
@ -9,6 +9,7 @@ import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'field/grid_listenr.dart';
|
||||
import 'grid_listener.dart';
|
||||
import 'grid_service.dart';
|
||||
import 'row/row_service.dart';
|
||||
|
||||
part 'grid_bloc.freezed.dart';
|
||||
|
||||
@ -32,12 +33,16 @@ class GridBloc extends Bloc<GridEvent, GridState> {
|
||||
createRow: (_CreateRow value) {
|
||||
_gridService.createRow();
|
||||
},
|
||||
updateDesc: (_Desc value) {},
|
||||
didReceiveRowUpdate: (_DidReceiveRowUpdate value) {
|
||||
emit(state.copyWith(rows: value.rows));
|
||||
emit(state.copyWith(rows: value.rows, listState: value.listState));
|
||||
},
|
||||
didReceiveFieldUpdate: (_DidReceiveFieldUpdate value) {
|
||||
emit(state.copyWith(fields: value.fields));
|
||||
final rows = state.rows.map((row) => row.copyWith(fields: value.fields)).toList();
|
||||
emit(state.copyWith(
|
||||
rows: rows,
|
||||
fields: value.fields,
|
||||
listState: const GridListState.reload(),
|
||||
));
|
||||
},
|
||||
);
|
||||
},
|
||||
@ -103,7 +108,7 @@ class GridBloc extends Bloc<GridEvent, GridState> {
|
||||
emit(state.copyWith(
|
||||
grid: Some(grid),
|
||||
fields: fields.items,
|
||||
rows: _buildRows(grid.blockOrders),
|
||||
rows: _buildRows(grid.blockOrders, fields.items),
|
||||
loadingState: GridLoadingState.finish(left(unit)),
|
||||
));
|
||||
},
|
||||
@ -113,49 +118,65 @@ class GridBloc extends Bloc<GridEvent, GridState> {
|
||||
}
|
||||
|
||||
void _deleteRows(List<RowOrder> deletedRows) {
|
||||
final List<RowOrder> rows = List.from(state.rows);
|
||||
rows.retainWhere(
|
||||
(row) => deletedRows.where((deletedRow) => deletedRow.rowId == row.rowId).isEmpty,
|
||||
);
|
||||
final List<RowData> rows = [];
|
||||
final List<Tuple2<int, RowData>> deletedIndex = [];
|
||||
final Map<String, RowOrder> deletedRowMap = {for (var rowOrder in deletedRows) rowOrder.rowId: rowOrder};
|
||||
state.rows.asMap().forEach((index, value) {
|
||||
if (deletedRowMap[value.rowId] == null) {
|
||||
rows.add(value);
|
||||
} else {
|
||||
deletedIndex.add(Tuple2(index, value));
|
||||
}
|
||||
});
|
||||
|
||||
add(GridEvent.didReceiveRowUpdate(rows));
|
||||
add(GridEvent.didReceiveRowUpdate(rows, GridListState.delete(deletedIndex)));
|
||||
}
|
||||
|
||||
void _insertRows(List<IndexRowOrder> createdRows) {
|
||||
final List<RowOrder> rows = List.from(state.rows);
|
||||
final List<RowData> rows = List.from(state.rows);
|
||||
List<int> insertIndexs = [];
|
||||
for (final newRow in createdRows) {
|
||||
if (newRow.hasIndex()) {
|
||||
rows.insert(newRow.index, newRow.rowOrder);
|
||||
insertIndexs.add(newRow.index);
|
||||
rows.insert(newRow.index, _toRowData(newRow.rowOrder));
|
||||
} else {
|
||||
rows.add(newRow.rowOrder);
|
||||
insertIndexs.add(rows.length);
|
||||
rows.add(_toRowData(newRow.rowOrder));
|
||||
}
|
||||
}
|
||||
add(GridEvent.didReceiveRowUpdate(rows));
|
||||
add(GridEvent.didReceiveRowUpdate(rows, GridListState.insert(insertIndexs)));
|
||||
}
|
||||
|
||||
void _updateRows(List<RowOrder> updatedRows) {
|
||||
final List<RowOrder> rows = List.from(state.rows);
|
||||
final List<RowData> rows = List.from(state.rows);
|
||||
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, updatedRow);
|
||||
rows.insert(index, _toRowData(updatedRow));
|
||||
updatedIndexs.add(index);
|
||||
}
|
||||
}
|
||||
add(GridEvent.didReceiveRowUpdate(rows));
|
||||
add(GridEvent.didReceiveRowUpdate(rows, const GridListState.reload()));
|
||||
}
|
||||
|
||||
List<RowOrder> _buildRows(List<GridBlockOrder> blockOrders) {
|
||||
return blockOrders.expand((blockOrder) => blockOrder.rowOrders).toList();
|
||||
List<RowData> _buildRows(List<GridBlockOrder> blockOrders, List<Field> fields) {
|
||||
return blockOrders.expand((blockOrder) => blockOrder.rowOrders).map((rowOrder) {
|
||||
return RowData.fromBlockRow(state.gridId, rowOrder, fields);
|
||||
}).toList();
|
||||
}
|
||||
|
||||
RowData _toRowData(RowOrder rowOrder) {
|
||||
return RowData.fromBlockRow(state.gridId, rowOrder, state.fields);
|
||||
}
|
||||
}
|
||||
|
||||
@freezed
|
||||
class GridEvent with _$GridEvent {
|
||||
const factory GridEvent.initial() = InitialGrid;
|
||||
const factory GridEvent.updateDesc(String gridId, String desc) = _Desc;
|
||||
const factory GridEvent.createRow() = _CreateRow;
|
||||
const factory GridEvent.didReceiveRowUpdate(List<RowOrder> rows) = _DidReceiveRowUpdate;
|
||||
const factory GridEvent.didReceiveRowUpdate(List<RowData> rows, GridListState listState) = _DidReceiveRowUpdate;
|
||||
const factory GridEvent.didReceiveFieldUpdate(List<Field> fields) = _DidReceiveFieldUpdate;
|
||||
}
|
||||
|
||||
@ -163,18 +184,20 @@ class GridEvent with _$GridEvent {
|
||||
class GridState with _$GridState {
|
||||
const factory GridState({
|
||||
required String gridId,
|
||||
required GridLoadingState loadingState,
|
||||
required List<Field> fields,
|
||||
required List<RowOrder> rows,
|
||||
required Option<Grid> grid,
|
||||
required List<Field> fields,
|
||||
required List<RowData> rows,
|
||||
required GridLoadingState loadingState,
|
||||
required GridListState listState,
|
||||
}) = _GridState;
|
||||
|
||||
factory GridState.initial(String gridId) => GridState(
|
||||
loadingState: const _Loading(),
|
||||
fields: [],
|
||||
rows: [],
|
||||
grid: none(),
|
||||
gridId: gridId,
|
||||
loadingState: const _Loading(),
|
||||
listState: const _Reload(),
|
||||
);
|
||||
}
|
||||
|
||||
@ -183,3 +206,10 @@ class GridLoadingState with _$GridLoadingState {
|
||||
const factory GridLoadingState.loading() = _Loading;
|
||||
const factory GridLoadingState.finish(Either<Unit, FlowyError> successOrFail) = _Finish;
|
||||
}
|
||||
|
||||
@freezed
|
||||
class GridListState with _$GridListState {
|
||||
const factory GridListState.insert(List<int> indexs) = _Insert;
|
||||
const factory GridListState.delete(List<Tuple2<int, RowData>> indexs) = _Delete;
|
||||
const factory GridListState.reload() = _Reload;
|
||||
}
|
||||
|
@ -5,7 +5,9 @@ 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_scrollview.dart';
|
||||
import 'package:flowy_infra_ui/widget/error_page.dart';
|
||||
import 'package:flowy_sdk/log.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-folder-data-model/view.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart' show Field;
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'controller/grid_scroll.dart';
|
||||
@ -90,26 +92,21 @@ class _FlowyGridState extends State<FlowyGrid> {
|
||||
return const Center(child: CircularProgressIndicator.adaptive());
|
||||
}
|
||||
|
||||
// _key.currentState.insertItem(index)
|
||||
final child = BlocBuilder<GridBloc, GridState>(
|
||||
builder: (context, state) {
|
||||
return SizedBox(
|
||||
width: GridLayout.headerWidth(state.fields),
|
||||
child: ScrollConfiguration(
|
||||
behavior: const ScrollBehavior().copyWith(scrollbars: false),
|
||||
child: CustomScrollView(
|
||||
physics: StyledScrollPhysics(),
|
||||
controller: _scrollController.verticalController,
|
||||
slivers: [
|
||||
_renderToolbar(state.gridId),
|
||||
GridHeader(gridId: state.gridId, fields: List.from(state.fields)),
|
||||
_renderRows(gridId: state.gridId, context: context),
|
||||
const GridFooter(),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
final child = SizedBox(
|
||||
width: GridLayout.headerWidth(state.fields),
|
||||
child: ScrollConfiguration(
|
||||
behavior: const ScrollBehavior().copyWith(scrollbars: false),
|
||||
child: CustomScrollView(
|
||||
physics: StyledScrollPhysics(),
|
||||
controller: _scrollController.verticalController,
|
||||
slivers: [
|
||||
_renderToolbar(state.gridId),
|
||||
_renderGridHeader(state.gridId),
|
||||
_renderRows(gridId: state.gridId, context: context),
|
||||
const GridFooter(),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
return _wrapScrollbar(child);
|
||||
@ -130,12 +127,22 @@ class _FlowyGridState extends State<FlowyGrid> {
|
||||
);
|
||||
}
|
||||
|
||||
Widget _renderGridHeader(String gridId) {
|
||||
return BlocSelector<GridBloc, GridState, List<Field>>(
|
||||
selector: (state) => state.fields,
|
||||
builder: (context, fields) {
|
||||
return GridHeader(gridId: gridId, fields: List.from(fields));
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Widget _renderToolbar(String gridId) {
|
||||
return BlocBuilder<GridBloc, GridState>(
|
||||
builder: (context, state) {
|
||||
return BlocSelector<GridBloc, GridState, List<Field>>(
|
||||
selector: (state) => state.fields,
|
||||
builder: (context, fields) {
|
||||
final toolbarContext = GridToolbarContext(
|
||||
gridId: gridId,
|
||||
fields: state.fields,
|
||||
fields: fields,
|
||||
);
|
||||
|
||||
return SliverToBoxAdapter(
|
||||
@ -146,44 +153,40 @@ class _FlowyGridState extends State<FlowyGrid> {
|
||||
}
|
||||
|
||||
Widget _renderRows({required String gridId, required BuildContext context}) {
|
||||
return BlocBuilder<GridBloc, GridState>(
|
||||
buildWhen: (previous, current) {
|
||||
final rowChanged = previous.rows.length != current.rows.length;
|
||||
// final fieldChanged = previous.fields.length != current.fields.length;
|
||||
return rowChanged;
|
||||
},
|
||||
builder: (context, state) {
|
||||
return SliverList(
|
||||
delegate: SliverChildBuilderDelegate(
|
||||
(context, index) {
|
||||
final blockRow = context.read<GridBloc>().state.rows[index];
|
||||
final fields = context.read<GridBloc>().state.fields;
|
||||
final rowData = RowData.fromBlockRow(gridId, blockRow, fields);
|
||||
return GridRowWidget(data: rowData, key: ValueKey(rowData.rowId));
|
||||
return BlocConsumer<GridBloc, GridState>(
|
||||
listener: (context, state) {
|
||||
state.listState.map(
|
||||
insert: (value) {
|
||||
for (final index in value.indexs) {
|
||||
_key.currentState?.insertItem(index);
|
||||
}
|
||||
},
|
||||
childCount: context.read<GridBloc>().state.rows.length,
|
||||
addRepaintBoundaries: true,
|
||||
addAutomaticKeepAlives: true,
|
||||
));
|
||||
|
||||
// return SliverAnimatedList(
|
||||
// key: _key,
|
||||
// initialItemCount: context.read<GridBloc>().state.rows.length,
|
||||
// itemBuilder: (BuildContext context, int index, Animation<double> animation) {
|
||||
// final blockRow = context.read<GridBloc>().state.rows[index];
|
||||
// final fields = context.read<GridBloc>().state.fields;
|
||||
// final rowData = RowData.fromBlockRow(blockRow, fields);
|
||||
// return _renderRow(rowData, animation);
|
||||
// },
|
||||
// );
|
||||
delete: (value) {
|
||||
for (final index in value.indexs) {
|
||||
_key.currentState?.removeItem(index.value1, (context, animation) => _renderRow(index.value2, animation));
|
||||
}
|
||||
},
|
||||
reload: (updatedIndexs) {},
|
||||
);
|
||||
},
|
||||
buildWhen: (previous, current) => false,
|
||||
builder: (context, state) {
|
||||
return SliverAnimatedList(
|
||||
key: _key,
|
||||
initialItemCount: context.read<GridBloc>().state.rows.length,
|
||||
itemBuilder: (BuildContext context, int index, Animation<double> animation) {
|
||||
final rowData = context.read<GridBloc>().state.rows[index];
|
||||
return _renderRow(rowData, animation);
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
// Widget _renderRow(RowData rowData, Animation<double> animation) {
|
||||
// return SizeTransition(
|
||||
// sizeFactor: animation,
|
||||
// child: GridRowWidget(data: rowData, key: ValueKey(rowData.rowId)),
|
||||
// );
|
||||
// }
|
||||
Widget _renderRow(RowData rowData, Animation<double> animation) {
|
||||
return SizeTransition(
|
||||
sizeFactor: animation,
|
||||
child: GridRowWidget(data: rowData, key: ValueKey(rowData.rowId)),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -163,10 +163,10 @@ impl GridBlockMetaPad {
|
||||
None => Ok(None),
|
||||
Some(delta) => {
|
||||
tracing::debug!("[GridBlockMeta] Composing delta {}", delta.to_delta_str());
|
||||
tracing::debug!(
|
||||
"[GridBlockMeta] current delta: {}",
|
||||
self.delta.to_str().unwrap_or_else(|_| "".to_string())
|
||||
);
|
||||
// tracing::debug!(
|
||||
// "[GridBlockMeta] current delta: {}",
|
||||
// self.delta.to_str().unwrap_or_else(|_| "".to_string())
|
||||
// );
|
||||
self.delta = self.delta.compose(&delta)?;
|
||||
Ok(Some(GridBlockMetaChange { delta, md5: self.md5() }))
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user