Skip to content

Commit 0225f0a

Browse files
authored
Merge pull request #951 from AppFlowy-IO/feat/create_card_from_header
chore: enable create card from header button
2 parents 565f6cb + cde8ad9 commit 0225f0a

File tree

10 files changed

+115
-46
lines changed

10 files changed

+115
-46
lines changed

frontend/app_flowy/lib/plugins/board/application/board_bloc.dart

Lines changed: 38 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -69,16 +69,31 @@ class BoardBloc extends Bloc<BoardEvent, BoardState> {
6969
_startListening();
7070
await _loadGrid(emit);
7171
},
72-
createRow: (groupId) async {
72+
createBottomRow: (groupId) async {
73+
final startRowId = groupControllers[groupId]?.lastRow()?.id;
74+
final result = await _gridDataController.createBoardCard(
75+
groupId,
76+
startRowId: startRowId,
77+
);
78+
result.fold(
79+
(_) {},
80+
(err) => Log.error(err),
81+
);
82+
},
83+
createHeaderRow: (String groupId) async {
7384
final result = await _gridDataController.createBoardCard(groupId);
7485
result.fold(
7586
(_) {},
7687
(err) => Log.error(err),
7788
);
7889
},
79-
didCreateRow: (String groupId, RowPB row) {
90+
didCreateRow: (String groupId, RowPB row, int? index) {
8091
emit(state.copyWith(
81-
editingRow: Some(BoardEditingRow(columnId: groupId, row: row)),
92+
editingRow: Some(BoardEditingRow(
93+
columnId: groupId,
94+
row: row,
95+
index: index,
96+
)),
8297
));
8398
},
8499
endEditRow: (rowId) {
@@ -142,8 +157,8 @@ class BoardBloc extends Bloc<BoardEvent, BoardState> {
142157
for (final group in groups) {
143158
final delegate = GroupControllerDelegateImpl(
144159
controller: boardController,
145-
onNewColumnItem: (groupId, row) {
146-
add(BoardEvent.didCreateRow(groupId, row));
160+
onNewColumnItem: (groupId, row, index) {
161+
add(BoardEvent.didCreateRow(groupId, row, index));
147162
},
148163
);
149164
final controller = GroupController(
@@ -231,9 +246,13 @@ class BoardBloc extends Bloc<BoardEvent, BoardState> {
231246
@freezed
232247
class BoardEvent with _$BoardEvent {
233248
const factory BoardEvent.initial() = _InitialBoard;
234-
const factory BoardEvent.createRow(String groupId) = _CreateRow;
235-
const factory BoardEvent.didCreateRow(String groupId, RowPB row) =
236-
_DidCreateRow;
249+
const factory BoardEvent.createBottomRow(String groupId) = _CreateBottomRow;
250+
const factory BoardEvent.createHeaderRow(String groupId) = _CreateHeaderRow;
251+
const factory BoardEvent.didCreateRow(
252+
String groupId,
253+
RowPB row,
254+
int? index,
255+
) = _DidCreateRow;
237256
const factory BoardEvent.endEditRow(String rowId) = _EndEditRow;
238257
const factory BoardEvent.didReceiveError(FlowyError error) = _DidReceiveError;
239258
const factory BoardEvent.didReceiveGridUpdate(
@@ -313,7 +332,7 @@ class BoardColumnItem extends AFColumnItem {
313332

314333
class GroupControllerDelegateImpl extends GroupControllerDelegate {
315334
final AFBoardDataController controller;
316-
final void Function(String, RowPB) onNewColumnItem;
335+
final void Function(String, RowPB, int?) onNewColumnItem;
317336

318337
GroupControllerDelegateImpl({
319338
required this.controller,
@@ -351,23 +370,30 @@ class GroupControllerDelegateImpl extends GroupControllerDelegate {
351370
}
352371

353372
@override
354-
void addNewRow(GroupPB group, RowPB row) {
373+
void addNewRow(GroupPB group, RowPB row, int? index) {
355374
final item = BoardColumnItem(
356375
row: row,
357376
fieldId: group.fieldId,
358377
requestFocus: true,
359378
);
360-
controller.addColumnItem(group.groupId, item);
361-
onNewColumnItem(group.groupId, row);
379+
380+
if (index != null) {
381+
controller.insertColumnItem(group.groupId, index, item);
382+
} else {
383+
controller.addColumnItem(group.groupId, item);
384+
}
385+
onNewColumnItem(group.groupId, row, index);
362386
}
363387
}
364388

365389
class BoardEditingRow {
366390
String columnId;
367391
RowPB row;
392+
int? index;
368393

369394
BoardEditingRow({
370395
required this.columnId,
371396
required this.row,
397+
required this.index,
372398
});
373399
}

frontend/app_flowy/lib/plugins/board/application/board_data_controller.dart

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -119,8 +119,9 @@ class BoardDataController {
119119
);
120120
}
121121

122-
Future<Either<RowPB, FlowyError>> createBoardCard(String groupId) {
123-
return _gridFFIService.createBoardCard(groupId);
122+
Future<Either<RowPB, FlowyError>> createBoardCard(String groupId,
123+
{String? startRowId}) {
124+
return _gridFFIService.createBoardCard(groupId, startRowId);
124125
}
125126

126127
Future<void> dispose() async {

frontend/app_flowy/lib/plugins/board/application/group_controller.dart

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ abstract class GroupControllerDelegate {
99
void removeRow(GroupPB group, String rowId);
1010
void insertRow(GroupPB group, RowPB row, int? index);
1111
void updateRow(GroupPB group, RowPB row);
12-
void addNewRow(GroupPB group, RowPB row);
12+
void addNewRow(GroupPB group, RowPB row, int? index);
1313
}
1414

1515
class GroupController {
@@ -31,6 +31,11 @@ class GroupController {
3131
}
3232
}
3333

34+
RowPB? lastRow() {
35+
if (group.rows.isEmpty) return null;
36+
return group.rows.last;
37+
}
38+
3439
void startListening() {
3540
_listener.start(onGroupChanged: (result) {
3641
result.fold(
@@ -50,7 +55,7 @@ class GroupController {
5055
}
5156

5257
if (insertedRow.isNew) {
53-
delegate.addNewRow(group, insertedRow.row);
58+
delegate.addNewRow(group, insertedRow.row, index);
5459
} else {
5560
delegate.insertRow(group, insertedRow.row, index);
5661
}

frontend/app_flowy/lib/plugins/board/presentation/board_page.dart

Lines changed: 35 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -84,11 +84,14 @@ class _BoardContentState extends State<BoardContent> {
8484
() => null,
8585
(editingRow) {
8686
WidgetsBinding.instance.addPostFrameCallback((_) {
87-
scrollManager.scrollToBottom(editingRow.columnId, () {
88-
context
89-
.read<BoardBloc>()
90-
.add(BoardEvent.endEditRow(editingRow.row.id));
91-
});
87+
if (editingRow.index != null) {
88+
} else {
89+
scrollManager.scrollToBottom(editingRow.columnId, () {
90+
context
91+
.read<BoardBloc>()
92+
.add(BoardEvent.endEditRow(editingRow.row.id));
93+
});
94+
}
9295
});
9396
},
9497
);
@@ -131,26 +134,32 @@ class _BoardContentState extends State<BoardContent> {
131134
}
132135

133136
Widget _buildHeader(
134-
BuildContext context, AFBoardColumnHeaderData headerData) {
137+
BuildContext context,
138+
AFBoardColumnData columnData,
139+
) {
135140
return AppFlowyColumnHeader(
136141
title: Flexible(
137142
fit: FlexFit.tight,
138143
child: FlowyText.medium(
139-
headerData.columnName,
144+
columnData.headerData.columnName,
140145
fontSize: 14,
141146
overflow: TextOverflow.clip,
142147
color: context.read<AppTheme>().textColor,
143148
),
144149
),
145-
// addIcon: const Icon(Icons.add, size: 20),
146-
// moreIcon: SizedBox(
147-
// width: 20,
148-
// height: 20,
149-
// child: svgWidget(
150-
// 'grid/details',
151-
// color: context.read<AppTheme>().iconColor,
152-
// ),
153-
// ),
150+
addIcon: SizedBox(
151+
height: 20,
152+
width: 20,
153+
child: svgWidget(
154+
"home/add",
155+
color: context.read<AppTheme>().iconColor,
156+
),
157+
),
158+
onAddButtonClick: () {
159+
context.read<BoardBloc>().add(
160+
BoardEvent.createHeaderRow(columnData.id),
161+
);
162+
},
154163
height: 50,
155164
margin: config.headerPadding,
156165
);
@@ -178,7 +187,9 @@ class _BoardContentState extends State<BoardContent> {
178187
height: 50,
179188
margin: config.footerPadding,
180189
onAddButtonClick: () {
181-
context.read<BoardBloc>().add(BoardEvent.createRow(columnData.id));
190+
context.read<BoardBloc>().add(
191+
BoardEvent.createBottomRow(columnData.id),
192+
);
182193
},
183194
);
184195
}
@@ -205,8 +216,13 @@ class _BoardContentState extends State<BoardContent> {
205216
);
206217

207218
final cellBuilder = BoardCellBuilder(cardController);
208-
209-
final isEditing = context.read<BoardBloc>().state.editingRow.isSome();
219+
bool isEditing = false;
220+
context.read<BoardBloc>().state.editingRow.fold(
221+
() => null,
222+
(editingRow) {
223+
isEditing = editingRow.row.id == columnItem.row.id;
224+
},
225+
);
210226

211227
return AppFlowyColumnItemCard(
212228
key: ValueKey(columnItem.id),

frontend/app_flowy/lib/plugins/grid/application/grid_service.dart

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,18 @@ class GridFFIService {
2727
return GridEventCreateTableRow(payload).send();
2828
}
2929

30-
Future<Either<RowPB, FlowyError>> createBoardCard(String groupId) {
30+
Future<Either<RowPB, FlowyError>> createBoardCard(
31+
String groupId,
32+
String? startRowId,
33+
) {
3134
CreateBoardCardPayloadPB payload = CreateBoardCardPayloadPB.create()
3235
..gridId = gridId
3336
..groupId = groupId;
37+
38+
if (startRowId != null) {
39+
payload.startRowId = startRowId;
40+
}
41+
3442
return GridEventCreateBoardCard(payload).send();
3543
}
3644

frontend/app_flowy/packages/appflowy_board/example/lib/multi_board_list_example.dart

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -73,17 +73,17 @@ class _MultiBoardListExampleState extends State<MultiBoardListExample> {
7373
margin: config.columnItemPadding,
7474
);
7575
},
76-
headerBuilder: (context, headerData) {
76+
headerBuilder: (context, columnData) {
7777
return AppFlowyColumnHeader(
7878
icon: const Icon(Icons.lightbulb_circle),
7979
title: SizedBox(
8080
width: 60,
8181
child: TextField(
8282
controller: TextEditingController()
83-
..text = headerData.columnName,
83+
..text = columnData.headerData.columnName,
8484
onSubmitted: (val) {
8585
boardDataController
86-
.getColumnController(headerData.columnId)!
86+
.getColumnController(columnData.headerData.columnId)!
8787
.updateColumnName(val);
8888
},
8989
),

frontend/app_flowy/packages/appflowy_board/lib/src/widgets/board.dart

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -282,14 +282,16 @@ class _AFBoardContentState extends State<AFBoardContent> {
282282
}
283283

284284
Widget? _buildHeader(
285-
BuildContext context, AFBoardColumnHeaderData headerData) {
285+
BuildContext context,
286+
AFBoardColumnData columnData,
287+
) {
286288
if (widget.headerBuilder == null) {
287289
return null;
288290
}
289291
return Selector<AFBoardColumnDataController, AFBoardColumnHeaderData>(
290292
selector: (context, controller) => controller.columnData.headerData,
291293
builder: (context, headerData, _) {
292-
return widget.headerBuilder!(context, headerData)!;
294+
return widget.headerBuilder!(context, columnData)!;
293295
},
294296
);
295297
}

frontend/app_flowy/packages/appflowy_board/lib/src/widgets/board_column/board_column.dart

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ typedef AFBoardColumnCardBuilder = Widget Function(
3131

3232
typedef AFBoardColumnHeaderBuilder = Widget? Function(
3333
BuildContext context,
34-
AFBoardColumnHeaderData headerData,
34+
AFBoardColumnData headerData,
3535
);
3636

3737
typedef AFBoardColumnFooterBuilder = Widget Function(
@@ -132,8 +132,8 @@ class _AFBoardColumnWidgetState extends State<AFBoardColumnWidget> {
132132
.map((item) => _buildWidget(context, item))
133133
.toList();
134134

135-
final header = widget.headerBuilder
136-
?.call(context, widget.dataSource.columnData.headerData);
135+
final header =
136+
widget.headerBuilder?.call(context, widget.dataSource.columnData);
137137

138138
final footer =
139139
widget.footBuilder?.call(context, widget.dataSource.columnData);

frontend/rust-lib/flowy-grid/src/entities/group_entities/group.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@ pub struct CreateBoardCardPayloadPB {
1414

1515
#[pb(index = 2)]
1616
pub group_id: String,
17+
18+
#[pb(index = 3, one_of)]
19+
pub start_row_id: Option<String>,
1720
}
1821

1922
impl TryInto<CreateRowParams> for CreateBoardCardPayloadPB {
@@ -22,9 +25,13 @@ impl TryInto<CreateRowParams> for CreateBoardCardPayloadPB {
2225
fn try_into(self) -> Result<CreateRowParams, Self::Error> {
2326
let grid_id = NotEmptyStr::parse(self.grid_id).map_err(|_| ErrorCode::GridIdIsEmpty)?;
2427
let group_id = NotEmptyStr::parse(self.group_id).map_err(|_| ErrorCode::GroupIdIsEmpty)?;
28+
let start_row_id = match self.start_row_id {
29+
None => None,
30+
Some(start_row_id) => Some(NotEmptyStr::parse(start_row_id).map_err(|_| ErrorCode::RowIdIsEmpty)?.0),
31+
};
2532
Ok(CreateRowParams {
2633
grid_id: grid_id.0,
27-
start_row_id: None,
34+
start_row_id,
2835
group_id: Some(group_id.0),
2936
layout: GridLayout::Board,
3037
})

frontend/rust-lib/flowy-grid/src/services/grid_view_editor.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,9 +95,13 @@ impl GridViewRevisionEditor {
9595
match params.group_id.as_ref() {
9696
None => {}
9797
Some(group_id) => {
98+
let index = match params.start_row_id {
99+
None => Some(0),
100+
Some(_) => None,
101+
};
98102
let inserted_row = InsertedRowPB {
99103
row: row_pb.clone(),
100-
index: None,
104+
index,
101105
is_new: true,
102106
};
103107
let changeset = GroupChangesetPB::insert(group_id.clone(), vec![inserted_row]);

0 commit comments

Comments
 (0)