chore: card ui

This commit is contained in:
appflowy
2022-08-12 20:10:56 +08:00
parent 61114f2726
commit 800fb82211
21 changed files with 480 additions and 47 deletions

View File

@ -1,5 +1,6 @@
import 'dart:async'; import 'dart:async';
import 'package:app_flowy/plugins/grid/application/block/block_cache.dart'; import 'package:app_flowy/plugins/grid/application/block/block_cache.dart';
import 'package:app_flowy/plugins/grid/application/field/field_cache.dart';
import 'package:app_flowy/plugins/grid/application/row/row_cache.dart'; import 'package:app_flowy/plugins/grid/application/row/row_cache.dart';
import 'package:appflowy_board/appflowy_board.dart'; import 'package:appflowy_board/appflowy_board.dart';
import 'package:dartz/dartz.dart'; import 'package:dartz/dartz.dart';
@ -20,6 +21,9 @@ class BoardBloc extends Bloc<BoardEvent, BoardState> {
final BoardDataController _dataController; final BoardDataController _dataController;
late final AFBoardDataController boardDataController; late final AFBoardDataController boardDataController;
GridFieldCache get fieldCache => _dataController.fieldCache;
String get gridId => _dataController.gridId;
BoardBloc({required ViewPB view}) BoardBloc({required ViewPB view})
: _dataController = BoardDataController(view: view), : _dataController = BoardDataController(view: view),
super(BoardState.initial(view.id)) { super(BoardState.initial(view.id)) {
@ -57,6 +61,9 @@ class BoardBloc extends Bloc<BoardEvent, BoardState> {
didReceiveGroups: (List<GroupPB> groups) { didReceiveGroups: (List<GroupPB> groups) {
emit(state.copyWith(groups: groups)); emit(state.copyWith(groups: groups));
}, },
didReceiveRows: (List<RowInfo> rowInfos) {
emit(state.copyWith(rowInfos: rowInfos));
},
); );
}, },
); );
@ -68,7 +75,7 @@ class BoardBloc extends Bloc<BoardEvent, BoardState> {
return super.close(); return super.close();
} }
GridRowCache? getRowCache(String blockId, String rowId) { GridRowCache? getRowCache(String blockId) {
final GridBlockCache? blockCache = _dataController.blocks[blockId]; final GridBlockCache? blockCache = _dataController.blocks[blockId];
return blockCache?.rowCache; return blockCache?.rowCache;
} }
@ -92,6 +99,9 @@ class BoardBloc extends Bloc<BoardEvent, BoardState> {
boardDataController.addColumns(columns); boardDataController.addColumns(columns);
}, },
onRowsChanged: (List<RowInfo> rowInfos, RowChangeReason reason) {
add(BoardEvent.didReceiveRows(rowInfos));
},
onError: (err) { onError: (err) {
Log.error(err); Log.error(err);
}, },
@ -100,15 +110,15 @@ class BoardBloc extends Bloc<BoardEvent, BoardState> {
List<BoardColumnItem> _buildRows(List<RowPB> rows) { List<BoardColumnItem> _buildRows(List<RowPB> rows) {
return rows.map((row) { return rows.map((row) {
final rowInfo = RowInfo( // final rowInfo = RowInfo(
gridId: _dataController.gridId, // gridId: _dataController.gridId,
blockId: row.blockId, // blockId: row.blockId,
id: row.id, // id: row.id,
fields: _dataController.fieldCache.unmodifiableFields, // fields: _dataController.fieldCache.unmodifiableFields,
height: row.height.toDouble(), // height: row.height.toDouble(),
rawRow: row, // rawRow: row,
); // );
return BoardColumnItem(row: rowInfo); return BoardColumnItem(row: row);
}).toList(); }).toList();
} }
@ -131,6 +141,8 @@ class BoardEvent with _$BoardEvent {
const factory BoardEvent.createRow() = _CreateRow; const factory BoardEvent.createRow() = _CreateRow;
const factory BoardEvent.didReceiveGroups(List<GroupPB> groups) = const factory BoardEvent.didReceiveGroups(List<GroupPB> groups) =
_DidReceiveGroup; _DidReceiveGroup;
const factory BoardEvent.didReceiveRows(List<RowInfo> rowInfos) =
_DidReceiveRows;
const factory BoardEvent.didReceiveGridUpdate( const factory BoardEvent.didReceiveGridUpdate(
GridPB grid, GridPB grid,
) = _DidReceiveGridUpdate; ) = _DidReceiveGridUpdate;
@ -186,7 +198,7 @@ class GridFieldEquatable extends Equatable {
} }
class BoardColumnItem extends AFColumnItem { class BoardColumnItem extends AFColumnItem {
final RowInfo row; final RowPB row;
BoardColumnItem({required this.row}); BoardColumnItem({required this.row});

View File

@ -3,6 +3,8 @@ import 'dart:collection';
import 'package:app_flowy/plugins/grid/application/block/block_cache.dart'; import 'package:app_flowy/plugins/grid/application/block/block_cache.dart';
import 'package:app_flowy/plugins/grid/application/field/field_cache.dart'; import 'package:app_flowy/plugins/grid/application/field/field_cache.dart';
import 'package:app_flowy/plugins/grid/application/grid_service.dart'; import 'package:app_flowy/plugins/grid/application/grid_service.dart';
import 'package:app_flowy/plugins/grid/application/row/row_cache.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-folder/view.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-folder/view.pb.dart';
import 'dart:async'; import 'dart:async';
@ -12,6 +14,10 @@ import 'package:flowy_sdk/protobuf/flowy-grid/protobuf.dart';
typedef OnFieldsChanged = void Function(UnmodifiableListView<FieldPB>); typedef OnFieldsChanged = void Function(UnmodifiableListView<FieldPB>);
typedef OnGridChanged = void Function(GridPB); typedef OnGridChanged = void Function(GridPB);
typedef OnGroupChanged = void Function(List<GroupPB>); typedef OnGroupChanged = void Function(List<GroupPB>);
typedef OnRowsChanged = void Function(
List<RowInfo> rowInfos,
RowChangeReason,
);
typedef OnError = void Function(FlowyError); typedef OnError = void Function(FlowyError);
class BoardDataController { class BoardDataController {
@ -21,17 +27,25 @@ class BoardDataController {
// key: the block id // key: the block id
final LinkedHashMap<String, GridBlockCache> _blocks; final LinkedHashMap<String, GridBlockCache> _blocks;
UnmodifiableMapView<String, GridBlockCache> get blocks => LinkedHashMap<String, GridBlockCache> get blocks => _blocks;
UnmodifiableMapView(_blocks);
OnFieldsChanged? _onFieldsChanged; OnFieldsChanged? _onFieldsChanged;
OnGridChanged? _onGridChanged; OnGridChanged? _onGridChanged;
OnGroupChanged? _onGroupChanged; OnGroupChanged? _onGroupChanged;
OnRowsChanged? _onRowsChanged;
OnError? _onError; OnError? _onError;
List<RowInfo> get rowInfos {
final List<RowInfo> rows = [];
for (var block in _blocks.values) {
rows.addAll(block.rows);
}
return rows;
}
BoardDataController({required ViewPB view}) BoardDataController({required ViewPB view})
: gridId = view.id, : gridId = view.id,
_blocks = LinkedHashMap.identity(), _blocks = LinkedHashMap.new(),
_gridFFIService = GridService(gridId: view.id), _gridFFIService = GridService(gridId: view.id),
fieldCache = GridFieldCache(gridId: view.id); fieldCache = GridFieldCache(gridId: view.id);
@ -39,11 +53,13 @@ class BoardDataController {
OnGridChanged? onGridChanged, OnGridChanged? onGridChanged,
OnFieldsChanged? onFieldsChanged, OnFieldsChanged? onFieldsChanged,
OnGroupChanged? onGroupChanged, OnGroupChanged? onGroupChanged,
OnRowsChanged? onRowsChanged,
OnError? onError, OnError? onError,
}) { }) {
_onGridChanged = onGridChanged; _onGridChanged = onGridChanged;
_onFieldsChanged = onFieldsChanged; _onFieldsChanged = onFieldsChanged;
_onGroupChanged = onGroupChanged; _onGroupChanged = onGroupChanged;
_onRowsChanged = onRowsChanged;
_onError = onError; _onError = onError;
fieldCache.addListener(onFields: (fields) { fieldCache.addListener(onFields: (fields) {
@ -57,6 +73,7 @@ class BoardDataController {
() => result.fold( () => result.fold(
(grid) async { (grid) async {
_onGridChanged?.call(grid); _onGridChanged?.call(grid);
_initialBlocks(grid.blocks);
return await _loadFields(grid).then((result) { return await _loadFields(grid).then((result) {
return result.fold( return result.fold(
(l) { (l) {
@ -85,6 +102,29 @@ class BoardDataController {
} }
} }
void _initialBlocks(List<BlockPB> blocks) {
for (final block in blocks) {
if (_blocks[block.id] != null) {
Log.warn("Initial duplicate block's cache: ${block.id}");
return;
}
final cache = GridBlockCache(
gridId: gridId,
block: block,
fieldCache: fieldCache,
);
cache.addListener(
onChangeReason: (reason) {
_onRowsChanged?.call(rowInfos, reason);
},
);
_blocks[block.id] = cache;
}
}
Future<Either<Unit, FlowyError>> _loadFields(GridPB grid) async { Future<Either<Unit, FlowyError>> _loadFields(GridPB grid) async {
final result = await _gridFFIService.getFields(fieldIds: grid.fields); final result = await _gridFFIService.getFields(fieldIds: grid.fields);
return Future( return Future(

View File

@ -0,0 +1,111 @@
import 'dart:collection';
import 'package:app_flowy/plugins/grid/application/cell/cell_service/cell_service.dart';
import 'package:app_flowy/plugins/grid/application/row/row_cache.dart';
import 'package:app_flowy/plugins/grid/application/row/row_service.dart';
import 'package:equatable/equatable.dart';
import 'package:flowy_sdk/protobuf/flowy-grid/block_entities.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pb.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'dart:async';
import 'card_data_controller.dart';
part 'card_bloc.freezed.dart';
class BoardCardBloc extends Bloc<BoardCardEvent, BoardCardState> {
final RowFFIService _rowService;
final CardDataController _dataController;
BoardCardBloc({
required String gridId,
required CardDataController dataController,
}) : _rowService = RowFFIService(
gridId: gridId,
blockId: dataController.rowPB.blockId,
rowId: dataController.rowPB.id,
),
_dataController = dataController,
super(BoardCardState.initial(
dataController.rowPB, dataController.loadData())) {
on<BoardCardEvent>(
(event, emit) async {
await event.map(
initial: (_InitialRow value) async {
await _startListening();
},
createRow: (_CreateRow value) {
_rowService.createRow();
},
didReceiveCells: (_DidReceiveCells value) async {
final cells = value.gridCellMap.values
.map((e) => GridCellEquatable(e.field))
.toList();
emit(state.copyWith(
gridCellMap: value.gridCellMap,
cells: UnmodifiableListView(cells),
changeReason: value.reason,
));
},
);
},
);
}
@override
Future<void> close() async {
_dataController.dispose();
return super.close();
}
Future<void> _startListening() async {
_dataController.addListener(
onRowChanged: (cells, reason) {
if (!isClosed) {
add(BoardCardEvent.didReceiveCells(cells, reason));
}
},
);
}
}
@freezed
class BoardCardEvent with _$BoardCardEvent {
const factory BoardCardEvent.initial() = _InitialRow;
const factory BoardCardEvent.createRow() = _CreateRow;
const factory BoardCardEvent.didReceiveCells(
GridCellMap gridCellMap, RowChangeReason reason) = _DidReceiveCells;
}
@freezed
class BoardCardState with _$BoardCardState {
const factory BoardCardState({
required RowPB rowPB,
required GridCellMap gridCellMap,
required UnmodifiableListView<GridCellEquatable> cells,
RowChangeReason? changeReason,
}) = _BoardCardState;
factory BoardCardState.initial(RowPB rowPB, GridCellMap cellDataMap) =>
BoardCardState(
rowPB: rowPB,
gridCellMap: cellDataMap,
cells: UnmodifiableListView(
cellDataMap.values.map((e) => GridCellEquatable(e.field)).toList(),
),
);
}
class GridCellEquatable extends Equatable {
final FieldPB _field;
const GridCellEquatable(FieldPB field) : _field = field;
@override
List<Object?> get props => [
_field.id,
_field.fieldType,
_field.visibility,
_field.width,
];
}

View File

@ -0,0 +1,49 @@
import 'package:app_flowy/plugins/board/presentation/card/card_cell_builder.dart';
import 'package:app_flowy/plugins/grid/application/cell/cell_service/cell_service.dart';
import 'package:app_flowy/plugins/grid/application/cell/cell_service/cell_field_notifier.dart';
import 'package:app_flowy/plugins/grid/application/field/field_cache.dart';
import 'package:app_flowy/plugins/grid/application/row/row_cache.dart';
import 'package:flowy_sdk/protobuf/flowy-grid/block_entities.pb.dart';
import 'package:flutter/foundation.dart';
typedef OnCardChanged = void Function(GridCellMap, RowChangeReason);
class CardDataController extends BoardCellBuilderDelegate {
final RowPB rowPB;
final GridFieldCache _fieldCache;
final GridRowCache _rowCache;
final List<VoidCallback> _onCardChangedListeners = [];
CardDataController({
required this.rowPB,
required GridFieldCache fieldCache,
required GridRowCache rowCache,
}) : _fieldCache = fieldCache,
_rowCache = rowCache;
GridCellMap loadData() {
return _rowCache.loadGridCells(rowPB.id);
}
void addListener({OnCardChanged? onRowChanged}) {
_onCardChangedListeners.add(_rowCache.addListener(
rowId: rowPB.id,
onCellUpdated: onRowChanged,
));
}
void dispose() {
for (final fn in _onCardChangedListeners) {
_rowCache.removeRowListener(fn);
}
}
@override
GridCellFieldNotifier buildFieldNotifier() {
return GridCellFieldNotifier(
notifier: GridCellFieldNotifierImpl(_fieldCache));
}
@override
GridCellCache get cellCache => _rowCache.cellCache;
}

View File

@ -31,7 +31,7 @@ class BoardPluginBuilder implements PluginBuilder {
class BoardPluginConfig implements PluginConfig { class BoardPluginConfig implements PluginConfig {
@override @override
bool get creatable => false; bool get creatable => true;
} }
class BoardPlugin extends Plugin { class BoardPlugin extends Plugin {

View File

@ -1,5 +1,6 @@
// ignore_for_file: unused_field // ignore_for_file: unused_field
import 'package:app_flowy/plugins/board/application/card/card_data_controller.dart';
import 'package:appflowy_board/appflowy_board.dart'; import 'package:appflowy_board/appflowy_board.dart';
import 'package:flowy_infra_ui/widget/error_page.dart'; import 'package:flowy_infra_ui/widget/error_page.dart';
import 'package:flowy_sdk/protobuf/flowy-folder/view.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-folder/view.pb.dart';
@ -7,6 +8,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import '../application/board_bloc.dart'; import '../application/board_bloc.dart';
import 'card/card.dart'; import 'card/card.dart';
import 'card/card_cell_builder.dart';
class BoardPage extends StatelessWidget { class BoardPage extends StatelessWidget {
final ViewPB view; final ViewPB view;
@ -51,6 +53,7 @@ class BoardContent extends StatelessWidget {
child: Padding( child: Padding(
padding: const EdgeInsets.symmetric(vertical: 30, horizontal: 20), padding: const EdgeInsets.symmetric(vertical: 30, horizontal: 20),
child: AFBoard( child: AFBoard(
key: UniqueKey(),
dataController: context.read<BoardBloc>().boardDataController, dataController: context.read<BoardBloc>().boardDataController,
headerBuilder: _buildHeader, headerBuilder: _buildHeader,
footBuilder: _buildFooter, footBuilder: _buildFooter,
@ -87,10 +90,29 @@ class BoardContent extends StatelessWidget {
} }
Widget _buildCard(BuildContext context, AFColumnItem item) { Widget _buildCard(BuildContext context, AFColumnItem item) {
final rowInfo = (item as BoardColumnItem).row; final rowPB = (item as BoardColumnItem).row;
final rowCache = context.read<BoardBloc>().getRowCache(rowPB.blockId);
/// Return placeholder widget if the rowCache is null.
if (rowCache == null) return SizedBox(key: ObjectKey(item));
final fieldCache = context.read<BoardBloc>().fieldCache;
final gridId = context.read<BoardBloc>().gridId;
final cardController = CardDataController(
fieldCache: fieldCache,
rowCache: rowCache,
rowPB: rowPB,
);
final cellBuilder = BoardCellBuilder(cardController);
return AppFlowyColumnItemCard( return AppFlowyColumnItemCard(
key: ObjectKey(item), key: ObjectKey(item),
child: BoardCard(rowInfo: rowInfo), child: BoardCard(
cellBuilder: cellBuilder,
dataController: cardController,
gridId: gridId,
),
); );
} }
} }

View File

@ -0,0 +1,21 @@
import 'package:app_flowy/plugins/grid/application/cell/cell_service/cell_service.dart';
import 'package:flutter/material.dart';
class BoardCheckboxCell extends StatefulWidget {
final GridCellControllerBuilder cellControllerBuilder;
const BoardCheckboxCell({
required this.cellControllerBuilder,
Key? key,
}) : super(key: key);
@override
State<BoardCheckboxCell> createState() => _BoardCheckboxCellState();
}
class _BoardCheckboxCellState extends State<BoardCheckboxCell> {
@override
Widget build(BuildContext context) {
return Container();
}
}

View File

@ -0,0 +1,21 @@
import 'package:app_flowy/plugins/grid/application/cell/cell_service/cell_service.dart';
import 'package:flutter/material.dart';
class BoardDateCell extends StatefulWidget {
final GridCellControllerBuilder cellControllerBuilder;
const BoardDateCell({
required this.cellControllerBuilder,
Key? key,
}) : super(key: key);
@override
State<BoardDateCell> createState() => _BoardDateCellState();
}
class _BoardDateCellState extends State<BoardDateCell> {
@override
Widget build(BuildContext context) {
return Container();
}
}

View File

@ -0,0 +1,21 @@
import 'package:app_flowy/plugins/grid/application/cell/cell_service/cell_service.dart';
import 'package:flutter/material.dart';
class BoardNumberCell extends StatefulWidget {
final GridCellControllerBuilder cellControllerBuilder;
const BoardNumberCell({
required this.cellControllerBuilder,
Key? key,
}) : super(key: key);
@override
State<BoardNumberCell> createState() => _BoardNumberCellState();
}
class _BoardNumberCellState extends State<BoardNumberCell> {
@override
Widget build(BuildContext context) {
return Container();
}
}

View File

@ -0,0 +1,21 @@
import 'package:app_flowy/plugins/grid/application/cell/cell_service/cell_service.dart';
import 'package:flutter/material.dart';
class BoardUrlCell extends StatefulWidget {
final GridCellControllerBuilder cellControllerBuilder;
const BoardUrlCell({
required this.cellControllerBuilder,
Key? key,
}) : super(key: key);
@override
State<BoardUrlCell> createState() => _BoardUrlCellState();
}
class _BoardUrlCellState extends State<BoardUrlCell> {
@override
Widget build(BuildContext context) {
return Container();
}
}

View File

@ -1,13 +1,63 @@
import 'package:app_flowy/plugins/grid/application/row/row_cache.dart'; import 'package:app_flowy/plugins/board/application/card/card_bloc.dart';
import 'package:app_flowy/plugins/board/application/card/card_data_controller.dart';
import 'package:app_flowy/plugins/grid/application/cell/cell_service/cell_service.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
class BoardCard extends StatelessWidget { import 'card_cell_builder.dart';
final RowInfo rowInfo;
const BoardCard({required this.rowInfo, Key? key}) : super(key: key); class BoardCard extends StatefulWidget {
final String gridId;
final CardDataController dataController;
final BoardCellBuilder cellBuilder;
const BoardCard({
required this.gridId,
required this.dataController,
required this.cellBuilder,
Key? key,
}) : super(key: key);
@override
State<BoardCard> createState() => _BoardCardState();
}
class _BoardCardState extends State<BoardCard> {
late BoardCardBloc _cardBloc;
@override
void initState() {
_cardBloc = BoardCardBloc(
gridId: widget.gridId,
dataController: widget.dataController,
);
super.initState();
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return const SizedBox(height: 20, child: Text('1234')); return BlocProvider.value(
value: _cardBloc,
child: BlocBuilder<BoardCardBloc, BoardCardState>(
builder: (context, state) {
return SizedBox(
height: 100,
child: Column(
children: _makeCells(context, state.gridCellMap),
),
);
},
),
);
}
List<Widget> _makeCells(BuildContext context, GridCellMap cellMap) {
return cellMap.values.map(
(cellId) {
final child = widget.cellBuilder.buildCell(cellId);
return SizedBox(height: 39, child: child);
},
).toList();
} }
} }

View File

@ -0,0 +1,69 @@
import 'package:app_flowy/plugins/grid/application/cell/cell_service/cell_service.dart';
import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pb.dart';
import 'package:flutter/material.dart';
import 'board_checkbox_cell.dart';
import 'board_date_cell.dart';
import 'board_number_cell.dart';
import 'board_select_option_cell.dart';
import 'board_text_cell.dart';
import 'board_url_cell.dart';
abstract class BoardCellBuilderDelegate
extends GridCellControllerBuilderDelegate {
GridCellCache get cellCache;
}
class BoardCellBuilder {
final BoardCellBuilderDelegate delegate;
BoardCellBuilder(this.delegate);
Widget buildCell(GridCellIdentifier cellId) {
final cellControllerBuilder = GridCellControllerBuilder(
delegate: delegate,
cellId: cellId,
cellCache: delegate.cellCache,
);
final key = cellId.key();
switch (cellId.fieldType) {
case FieldType.Checkbox:
return BoardCheckboxCell(
cellControllerBuilder: cellControllerBuilder,
key: key,
);
case FieldType.DateTime:
return BoardDateCell(
cellControllerBuilder: cellControllerBuilder,
key: key,
);
case FieldType.SingleSelect:
return BoardSelectOptionCell(
cellControllerBuilder: cellControllerBuilder,
key: key,
);
case FieldType.MultiSelect:
return BoardSelectOptionCell(
cellControllerBuilder: cellControllerBuilder,
key: key,
);
case FieldType.Number:
return BoardNumberCell(
cellControllerBuilder: cellControllerBuilder,
key: key,
);
case FieldType.RichText:
return BoardTextCell(
cellControllerBuilder: cellControllerBuilder,
key: key,
);
case FieldType.URL:
return BoardUrlCell(
cellControllerBuilder: cellControllerBuilder,
key: key,
);
}
throw UnimplementedError;
}
}

View File

@ -46,7 +46,7 @@ class GridDataController {
GridDataController({required ViewPB view}) GridDataController({required ViewPB view})
: gridId = view.id, : gridId = view.id,
_blocks = LinkedHashMap.identity(), _blocks = LinkedHashMap.new(),
_gridFFIService = GridService(gridId: view.id), _gridFFIService = GridService(gridId: view.id),
fieldCache = GridFieldCache(gridId: view.id); fieldCache = GridFieldCache(gridId: view.id);

View File

@ -12,10 +12,10 @@ part 'row_action_sheet_bloc.freezed.dart';
class RowActionSheetBloc class RowActionSheetBloc
extends Bloc<RowActionSheetEvent, RowActionSheetState> { extends Bloc<RowActionSheetEvent, RowActionSheetState> {
final RowService _rowService; final RowFFIService _rowService;
RowActionSheetBloc({required RowInfo rowData}) RowActionSheetBloc({required RowInfo rowData})
: _rowService = RowService( : _rowService = RowFFIService(
gridId: rowData.gridId, gridId: rowData.gridId,
blockId: rowData.blockId, blockId: rowData.blockId,
rowId: rowData.id, rowId: rowData.id,

View File

@ -12,13 +12,13 @@ import 'row_service.dart';
part 'row_bloc.freezed.dart'; part 'row_bloc.freezed.dart';
class RowBloc extends Bloc<RowEvent, RowState> { class RowBloc extends Bloc<RowEvent, RowState> {
final RowService _rowService; final RowFFIService _rowService;
final GridRowDataController _dataController; final GridRowDataController _dataController;
RowBloc({ RowBloc({
required RowInfo rowInfo, required RowInfo rowInfo,
required GridRowDataController dataController, required GridRowDataController dataController,
}) : _rowService = RowService( }) : _rowService = RowFFIService(
gridId: rowInfo.gridId, gridId: rowInfo.gridId,
blockId: rowInfo.blockId, blockId: rowInfo.blockId,
rowId: rowInfo.id, rowId: rowInfo.id,
@ -35,13 +35,12 @@ class RowBloc extends Bloc<RowEvent, RowState> {
_rowService.createRow(); _rowService.createRow();
}, },
didReceiveCells: (_DidReceiveCells value) async { didReceiveCells: (_DidReceiveCells value) async {
final fields = value.gridCellMap.values final cells = value.gridCellMap.values
.map((e) => GridCellEquatable(e.field)) .map((e) => GridCellEquatable(e.field))
.toList(); .toList();
final snapshots = UnmodifiableListView(fields);
emit(state.copyWith( emit(state.copyWith(
gridCellMap: value.gridCellMap, gridCellMap: value.gridCellMap,
snapshots: snapshots, cells: UnmodifiableListView(cells),
changeReason: value.reason, changeReason: value.reason,
)); ));
}, },
@ -80,7 +79,7 @@ class RowState with _$RowState {
const factory RowState({ const factory RowState({
required RowInfo rowInfo, required RowInfo rowInfo,
required GridCellMap gridCellMap, required GridCellMap gridCellMap,
required UnmodifiableListView<GridCellEquatable> snapshots, required UnmodifiableListView<GridCellEquatable> cells,
RowChangeReason? changeReason, RowChangeReason? changeReason,
}) = _RowState; }) = _RowState;
@ -88,8 +87,9 @@ class RowState with _$RowState {
RowState( RowState(
rowInfo: rowInfo, rowInfo: rowInfo,
gridCellMap: cellDataMap, gridCellMap: cellDataMap,
snapshots: UnmodifiableListView( cells: UnmodifiableListView(
cellDataMap.values.map((e) => GridCellEquatable(e.field)).toList()), cellDataMap.values.map((e) => GridCellEquatable(e.field)).toList(),
),
); );
} }

View File

@ -13,10 +13,6 @@ class GridRowDataController extends GridCellBuilderDelegate {
final GridFieldCache _fieldCache; final GridFieldCache _fieldCache;
final GridRowCache _rowCache; final GridRowCache _rowCache;
GridFieldCache get fieldCache => _fieldCache;
GridRowCache get rowCache => _rowCache;
GridRowDataController({ GridRowDataController({
required this.rowInfo, required this.rowInfo,
required GridFieldCache fieldCache, required GridFieldCache fieldCache,
@ -49,5 +45,5 @@ class GridRowDataController extends GridCellBuilderDelegate {
} }
@override @override
GridCellCache get cellCache => rowCache.cellCache; GridCellCache get cellCache => _rowCache.cellCache;
} }

View File

@ -5,12 +5,12 @@ import 'package:flowy_sdk/protobuf/flowy-grid/block_entities.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-grid/grid_entities.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-grid/grid_entities.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-grid/row_entities.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-grid/row_entities.pb.dart';
class RowService { class RowFFIService {
final String gridId; final String gridId;
final String blockId; final String blockId;
final String rowId; final String rowId;
RowService( RowFFIService(
{required this.gridId, required this.blockId, required this.rowId}); {required this.gridId, required this.blockId, required this.rowId});
Future<Either<RowPB, FlowyError>> createRow() { Future<Either<RowPB, FlowyError>> createRow() {

View File

@ -164,7 +164,7 @@ class RowContent extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return BlocBuilder<RowBloc, RowState>( return BlocBuilder<RowBloc, RowState>(
buildWhen: (previous, current) => buildWhen: (previous, current) =>
!listEquals(previous.snapshots, current.snapshots), !listEquals(previous.cells, current.cells),
builder: (context, state) { builder: (context, state) {
return IntrinsicHeight( return IntrinsicHeight(
child: Row( child: Row(

View File

@ -53,7 +53,7 @@ class MenuUser extends StatelessWidget {
borderRadius: Corners.s5Border, borderRadius: Corners.s5Border,
child: CircleAvatar( child: CircleAvatar(
backgroundColor: Colors.transparent, backgroundColor: Colors.transparent,
child: svgWidget('emoji/$iconUrl'), child: Container(),
)), )),
); );
} }

View File

@ -150,7 +150,7 @@ impl FolderTest {
// assert_eq!(json, expected_json); // assert_eq!(json, expected_json);
// } // }
FolderScript::AssertWorkspace(workspace) => { FolderScript::AssertWorkspace(workspace) => {
assert_eq!(self.workspace, workspace); assert_eq!(self.workspace, workspace, "Workspace not equal");
} }
FolderScript::ReadWorkspace(workspace_id) => { FolderScript::ReadWorkspace(workspace_id) => {
let workspace = read_workspace(sdk, workspace_id).await.pop().unwrap(); let workspace = read_workspace(sdk, workspace_id).await.pop().unwrap();
@ -166,7 +166,7 @@ impl FolderTest {
// assert_eq!(json, expected_json); // assert_eq!(json, expected_json);
// } // }
FolderScript::AssertApp(app) => { FolderScript::AssertApp(app) => {
assert_eq!(self.app, app); assert_eq!(self.app, app, "App not equal");
} }
FolderScript::ReadApp(app_id) => { FolderScript::ReadApp(app_id) => {
let app = read_app(sdk, &app_id).await; let app = read_app(sdk, &app_id).await;
@ -184,7 +184,7 @@ impl FolderTest {
self.view = view; self.view = view;
} }
FolderScript::AssertView(view) => { FolderScript::AssertView(view) => {
assert_eq!(self.view, view); assert_eq!(self.view, view, "View not equal");
} }
FolderScript::ReadView(view_id) => { FolderScript::ReadView(view_id) => {
let view = read_view(sdk, &view_id).await; let view = read_view(sdk, &view_id).await;
@ -215,7 +215,7 @@ impl FolderTest {
} }
FolderScript::AssertRevisionState { rev_id, state } => { FolderScript::AssertRevisionState { rev_id, state } => {
let record = cache.get(rev_id).await.unwrap(); let record = cache.get(rev_id).await.unwrap();
assert_eq!(record.state, state); assert_eq!(record.state, state, "Revision state is not match");
if let RevisionState::Ack = state { if let RevisionState::Ack = state {
// There is a defer action that writes the revisions to disk, so we wait here. // There is a defer action that writes the revisions to disk, so we wait here.
// Make sure everything is written. // Make sure everything is written.
@ -235,7 +235,7 @@ impl FolderTest {
.unwrap_or_else(|| panic!("Expected Next revision is {}, but receive None", rev_id.unwrap())); .unwrap_or_else(|| panic!("Expected Next revision is {}, but receive None", rev_id.unwrap()));
let mut notify = rev_manager.ack_notify(); let mut notify = rev_manager.ack_notify();
let _ = notify.recv().await; let _ = notify.recv().await;
assert_eq!(next_revision.rev_id, rev_id.unwrap()); assert_eq!(next_revision.rev_id, rev_id.unwrap(), "Revision id not match");
} }
} }
} }