chore: enable create card from header button

This commit is contained in:
appflowy 2022-08-31 14:56:03 +08:00
parent 8b7b18bfff
commit cde8ad9084
10 changed files with 115 additions and 46 deletions

View File

@ -69,16 +69,31 @@ class BoardBloc extends Bloc<BoardEvent, BoardState> {
_startListening(); _startListening();
await _loadGrid(emit); await _loadGrid(emit);
}, },
createRow: (groupId) async { createBottomRow: (groupId) async {
final startRowId = groupControllers[groupId]?.lastRow()?.id;
final result = await _gridDataController.createBoardCard(
groupId,
startRowId: startRowId,
);
result.fold(
(_) {},
(err) => Log.error(err),
);
},
createHeaderRow: (String groupId) async {
final result = await _gridDataController.createBoardCard(groupId); final result = await _gridDataController.createBoardCard(groupId);
result.fold( result.fold(
(_) {}, (_) {},
(err) => Log.error(err), (err) => Log.error(err),
); );
}, },
didCreateRow: (String groupId, RowPB row) { didCreateRow: (String groupId, RowPB row, int? index) {
emit(state.copyWith( emit(state.copyWith(
editingRow: Some(BoardEditingRow(columnId: groupId, row: row)), editingRow: Some(BoardEditingRow(
columnId: groupId,
row: row,
index: index,
)),
)); ));
}, },
endEditRow: (rowId) { endEditRow: (rowId) {
@ -142,8 +157,8 @@ class BoardBloc extends Bloc<BoardEvent, BoardState> {
for (final group in groups) { for (final group in groups) {
final delegate = GroupControllerDelegateImpl( final delegate = GroupControllerDelegateImpl(
controller: boardController, controller: boardController,
onNewColumnItem: (groupId, row) { onNewColumnItem: (groupId, row, index) {
add(BoardEvent.didCreateRow(groupId, row)); add(BoardEvent.didCreateRow(groupId, row, index));
}, },
); );
final controller = GroupController( final controller = GroupController(
@ -231,9 +246,13 @@ class BoardBloc extends Bloc<BoardEvent, BoardState> {
@freezed @freezed
class BoardEvent with _$BoardEvent { class BoardEvent with _$BoardEvent {
const factory BoardEvent.initial() = _InitialBoard; const factory BoardEvent.initial() = _InitialBoard;
const factory BoardEvent.createRow(String groupId) = _CreateRow; const factory BoardEvent.createBottomRow(String groupId) = _CreateBottomRow;
const factory BoardEvent.didCreateRow(String groupId, RowPB row) = const factory BoardEvent.createHeaderRow(String groupId) = _CreateHeaderRow;
_DidCreateRow; const factory BoardEvent.didCreateRow(
String groupId,
RowPB row,
int? index,
) = _DidCreateRow;
const factory BoardEvent.endEditRow(String rowId) = _EndEditRow; const factory BoardEvent.endEditRow(String rowId) = _EndEditRow;
const factory BoardEvent.didReceiveError(FlowyError error) = _DidReceiveError; const factory BoardEvent.didReceiveError(FlowyError error) = _DidReceiveError;
const factory BoardEvent.didReceiveGridUpdate( const factory BoardEvent.didReceiveGridUpdate(
@ -313,7 +332,7 @@ class BoardColumnItem extends AFColumnItem {
class GroupControllerDelegateImpl extends GroupControllerDelegate { class GroupControllerDelegateImpl extends GroupControllerDelegate {
final AFBoardDataController controller; final AFBoardDataController controller;
final void Function(String, RowPB) onNewColumnItem; final void Function(String, RowPB, int?) onNewColumnItem;
GroupControllerDelegateImpl({ GroupControllerDelegateImpl({
required this.controller, required this.controller,
@ -351,23 +370,30 @@ class GroupControllerDelegateImpl extends GroupControllerDelegate {
} }
@override @override
void addNewRow(GroupPB group, RowPB row) { void addNewRow(GroupPB group, RowPB row, int? index) {
final item = BoardColumnItem( final item = BoardColumnItem(
row: row, row: row,
fieldId: group.fieldId, fieldId: group.fieldId,
requestFocus: true, requestFocus: true,
); );
controller.addColumnItem(group.groupId, item);
onNewColumnItem(group.groupId, row); if (index != null) {
controller.insertColumnItem(group.groupId, index, item);
} else {
controller.addColumnItem(group.groupId, item);
}
onNewColumnItem(group.groupId, row, index);
} }
} }
class BoardEditingRow { class BoardEditingRow {
String columnId; String columnId;
RowPB row; RowPB row;
int? index;
BoardEditingRow({ BoardEditingRow({
required this.columnId, required this.columnId,
required this.row, required this.row,
required this.index,
}); });
} }

View File

@ -118,8 +118,9 @@ class BoardDataController {
); );
} }
Future<Either<RowPB, FlowyError>> createBoardCard(String groupId) { Future<Either<RowPB, FlowyError>> createBoardCard(String groupId,
return _gridFFIService.createBoardCard(groupId); {String? startRowId}) {
return _gridFFIService.createBoardCard(groupId, startRowId);
} }
Future<void> dispose() async { Future<void> dispose() async {

View File

@ -9,7 +9,7 @@ abstract class GroupControllerDelegate {
void removeRow(GroupPB group, String rowId); void removeRow(GroupPB group, String rowId);
void insertRow(GroupPB group, RowPB row, int? index); void insertRow(GroupPB group, RowPB row, int? index);
void updateRow(GroupPB group, RowPB row); void updateRow(GroupPB group, RowPB row);
void addNewRow(GroupPB group, RowPB row); void addNewRow(GroupPB group, RowPB row, int? index);
} }
class GroupController { class GroupController {
@ -31,6 +31,11 @@ class GroupController {
} }
} }
RowPB? lastRow() {
if (group.rows.isEmpty) return null;
return group.rows.last;
}
void startListening() { void startListening() {
_listener.start(onGroupChanged: (result) { _listener.start(onGroupChanged: (result) {
result.fold( result.fold(
@ -50,7 +55,7 @@ class GroupController {
} }
if (insertedRow.isNew) { if (insertedRow.isNew) {
delegate.addNewRow(group, insertedRow.row); delegate.addNewRow(group, insertedRow.row, index);
} else { } else {
delegate.insertRow(group, insertedRow.row, index); delegate.insertRow(group, insertedRow.row, index);
} }

View File

@ -84,11 +84,14 @@ class _BoardContentState extends State<BoardContent> {
() => null, () => null,
(editingRow) { (editingRow) {
WidgetsBinding.instance.addPostFrameCallback((_) { WidgetsBinding.instance.addPostFrameCallback((_) {
scrollManager.scrollToBottom(editingRow.columnId, () { if (editingRow.index != null) {
context } else {
.read<BoardBloc>() scrollManager.scrollToBottom(editingRow.columnId, () {
.add(BoardEvent.endEditRow(editingRow.row.id)); context
}); .read<BoardBloc>()
.add(BoardEvent.endEditRow(editingRow.row.id));
});
}
}); });
}, },
); );
@ -131,26 +134,32 @@ class _BoardContentState extends State<BoardContent> {
} }
Widget _buildHeader( Widget _buildHeader(
BuildContext context, AFBoardColumnHeaderData headerData) { BuildContext context,
AFBoardColumnData columnData,
) {
return AppFlowyColumnHeader( return AppFlowyColumnHeader(
title: Flexible( title: Flexible(
fit: FlexFit.tight, fit: FlexFit.tight,
child: FlowyText.medium( child: FlowyText.medium(
headerData.columnName, columnData.headerData.columnName,
fontSize: 14, fontSize: 14,
overflow: TextOverflow.clip, overflow: TextOverflow.clip,
color: context.read<AppTheme>().textColor, color: context.read<AppTheme>().textColor,
), ),
), ),
// addIcon: const Icon(Icons.add, size: 20), addIcon: SizedBox(
// moreIcon: SizedBox( height: 20,
// width: 20, width: 20,
// height: 20, child: svgWidget(
// child: svgWidget( "home/add",
// 'grid/details', color: context.read<AppTheme>().iconColor,
// color: context.read<AppTheme>().iconColor, ),
// ), ),
// ), onAddButtonClick: () {
context.read<BoardBloc>().add(
BoardEvent.createHeaderRow(columnData.id),
);
},
height: 50, height: 50,
margin: config.headerPadding, margin: config.headerPadding,
); );
@ -178,7 +187,9 @@ class _BoardContentState extends State<BoardContent> {
height: 50, height: 50,
margin: config.footerPadding, margin: config.footerPadding,
onAddButtonClick: () { onAddButtonClick: () {
context.read<BoardBloc>().add(BoardEvent.createRow(columnData.id)); context.read<BoardBloc>().add(
BoardEvent.createBottomRow(columnData.id),
);
}, },
); );
} }
@ -205,8 +216,13 @@ class _BoardContentState extends State<BoardContent> {
); );
final cellBuilder = BoardCellBuilder(cardController); final cellBuilder = BoardCellBuilder(cardController);
bool isEditing = false;
final isEditing = context.read<BoardBloc>().state.editingRow.isSome(); context.read<BoardBloc>().state.editingRow.fold(
() => null,
(editingRow) {
isEditing = editingRow.row.id == columnItem.row.id;
},
);
return AppFlowyColumnItemCard( return AppFlowyColumnItemCard(
key: ValueKey(columnItem.id), key: ValueKey(columnItem.id),

View File

@ -27,10 +27,18 @@ class GridFFIService {
return GridEventCreateTableRow(payload).send(); return GridEventCreateTableRow(payload).send();
} }
Future<Either<RowPB, FlowyError>> createBoardCard(String groupId) { Future<Either<RowPB, FlowyError>> createBoardCard(
String groupId,
String? startRowId,
) {
CreateBoardCardPayloadPB payload = CreateBoardCardPayloadPB.create() CreateBoardCardPayloadPB payload = CreateBoardCardPayloadPB.create()
..gridId = gridId ..gridId = gridId
..groupId = groupId; ..groupId = groupId;
if (startRowId != null) {
payload.startRowId = startRowId;
}
return GridEventCreateBoardCard(payload).send(); return GridEventCreateBoardCard(payload).send();
} }

View File

@ -73,17 +73,17 @@ class _MultiBoardListExampleState extends State<MultiBoardListExample> {
margin: config.columnItemPadding, margin: config.columnItemPadding,
); );
}, },
headerBuilder: (context, headerData) { headerBuilder: (context, columnData) {
return AppFlowyColumnHeader( return AppFlowyColumnHeader(
icon: const Icon(Icons.lightbulb_circle), icon: const Icon(Icons.lightbulb_circle),
title: SizedBox( title: SizedBox(
width: 60, width: 60,
child: TextField( child: TextField(
controller: TextEditingController() controller: TextEditingController()
..text = headerData.columnName, ..text = columnData.headerData.columnName,
onSubmitted: (val) { onSubmitted: (val) {
boardDataController boardDataController
.getColumnController(headerData.columnId)! .getColumnController(columnData.headerData.columnId)!
.updateColumnName(val); .updateColumnName(val);
}, },
), ),

View File

@ -282,14 +282,16 @@ class _AFBoardContentState extends State<AFBoardContent> {
} }
Widget? _buildHeader( Widget? _buildHeader(
BuildContext context, AFBoardColumnHeaderData headerData) { BuildContext context,
AFBoardColumnData columnData,
) {
if (widget.headerBuilder == null) { if (widget.headerBuilder == null) {
return null; return null;
} }
return Selector<AFBoardColumnDataController, AFBoardColumnHeaderData>( return Selector<AFBoardColumnDataController, AFBoardColumnHeaderData>(
selector: (context, controller) => controller.columnData.headerData, selector: (context, controller) => controller.columnData.headerData,
builder: (context, headerData, _) { builder: (context, headerData, _) {
return widget.headerBuilder!(context, headerData)!; return widget.headerBuilder!(context, columnData)!;
}, },
); );
} }

View File

@ -31,7 +31,7 @@ typedef AFBoardColumnCardBuilder = Widget Function(
typedef AFBoardColumnHeaderBuilder = Widget? Function( typedef AFBoardColumnHeaderBuilder = Widget? Function(
BuildContext context, BuildContext context,
AFBoardColumnHeaderData headerData, AFBoardColumnData headerData,
); );
typedef AFBoardColumnFooterBuilder = Widget Function( typedef AFBoardColumnFooterBuilder = Widget Function(
@ -132,8 +132,8 @@ class _AFBoardColumnWidgetState extends State<AFBoardColumnWidget> {
.map((item) => _buildWidget(context, item)) .map((item) => _buildWidget(context, item))
.toList(); .toList();
final header = widget.headerBuilder final header =
?.call(context, widget.dataSource.columnData.headerData); widget.headerBuilder?.call(context, widget.dataSource.columnData);
final footer = final footer =
widget.footBuilder?.call(context, widget.dataSource.columnData); widget.footBuilder?.call(context, widget.dataSource.columnData);

View File

@ -14,6 +14,9 @@ pub struct CreateBoardCardPayloadPB {
#[pb(index = 2)] #[pb(index = 2)]
pub group_id: String, pub group_id: String,
#[pb(index = 3, one_of)]
pub start_row_id: Option<String>,
} }
impl TryInto<CreateRowParams> for CreateBoardCardPayloadPB { impl TryInto<CreateRowParams> for CreateBoardCardPayloadPB {
@ -22,9 +25,13 @@ impl TryInto<CreateRowParams> for CreateBoardCardPayloadPB {
fn try_into(self) -> Result<CreateRowParams, Self::Error> { fn try_into(self) -> Result<CreateRowParams, Self::Error> {
let grid_id = NotEmptyStr::parse(self.grid_id).map_err(|_| ErrorCode::GridIdIsEmpty)?; let grid_id = NotEmptyStr::parse(self.grid_id).map_err(|_| ErrorCode::GridIdIsEmpty)?;
let group_id = NotEmptyStr::parse(self.group_id).map_err(|_| ErrorCode::GroupIdIsEmpty)?; let group_id = NotEmptyStr::parse(self.group_id).map_err(|_| ErrorCode::GroupIdIsEmpty)?;
let start_row_id = match self.start_row_id {
None => None,
Some(start_row_id) => Some(NotEmptyStr::parse(start_row_id).map_err(|_| ErrorCode::RowIdIsEmpty)?.0),
};
Ok(CreateRowParams { Ok(CreateRowParams {
grid_id: grid_id.0, grid_id: grid_id.0,
start_row_id: None, start_row_id,
group_id: Some(group_id.0), group_id: Some(group_id.0),
layout: GridLayout::Board, layout: GridLayout::Board,
}) })

View File

@ -95,9 +95,13 @@ impl GridViewRevisionEditor {
match params.group_id.as_ref() { match params.group_id.as_ref() {
None => {} None => {}
Some(group_id) => { Some(group_id) => {
let index = match params.start_row_id {
None => Some(0),
Some(_) => None,
};
let inserted_row = InsertedRowPB { let inserted_row = InsertedRowPB {
row: row_pb.clone(), row: row_pb.clone(),
index: None, index,
is_new: true, is_new: true,
}; };
let changeset = GroupChangesetPB::insert(group_id.clone(), vec![inserted_row]); let changeset = GroupChangesetPB::insert(group_id.clone(), vec![inserted_row]);