Skip to content

Commit b61e3f4

Browse files
authored
Merge pull request #944 from AppFlowy-IO/feat/edit_card_button
chore: add edit card button
2 parents d068370 + a7349f4 commit b61e3f4

File tree

10 files changed

+178
-34
lines changed

10 files changed

+178
-34
lines changed

frontend/app_flowy/lib/plugins/board/application/card/board_text_cell_bloc.dart

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ class BoardTextCellBloc extends Bloc<BoardTextCellEvent, BoardTextCellState> {
2727
emit(state.copyWith(content: text));
2828
}
2929
},
30+
enableEdit: (bool enabled) {
31+
emit(state.copyWith(enableEdit: enabled));
32+
},
3033
);
3134
},
3235
);
@@ -57,6 +60,7 @@ class BoardTextCellBloc extends Bloc<BoardTextCellEvent, BoardTextCellState> {
5760
class BoardTextCellEvent with _$BoardTextCellEvent {
5861
const factory BoardTextCellEvent.initial() = _InitialCell;
5962
const factory BoardTextCellEvent.updateText(String text) = _UpdateContent;
63+
const factory BoardTextCellEvent.enableEdit(bool enabled) = _EnableEdit;
6064
const factory BoardTextCellEvent.didReceiveCellUpdate(String cellContent) =
6165
_DidReceiveCellUpdate;
6266
}
@@ -65,10 +69,12 @@ class BoardTextCellEvent with _$BoardTextCellEvent {
6569
class BoardTextCellState with _$BoardTextCellState {
6670
const factory BoardTextCellState({
6771
required String content,
72+
required bool enableEdit,
6873
}) = _BoardTextCellState;
6974

7075
factory BoardTextCellState.initial(GridCellController context) =>
7176
BoardTextCellState(
7277
content: context.getCellData() ?? "",
78+
enableEdit: false,
7379
);
7480
}

frontend/app_flowy/lib/plugins/board/application/card/card_bloc.dart

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,10 @@ class BoardCardState with _$BoardCardState {
107107

108108
factory BoardCardState.initial(
109109
RowPB rowPB, UnmodifiableListView<BoardCellEquatable> cells) =>
110-
BoardCardState(rowPB: rowPB, cells: cells);
110+
BoardCardState(
111+
rowPB: rowPB,
112+
cells: cells,
113+
);
111114
}
112115

113116
class BoardCellEquatable extends Equatable {
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,54 @@
1+
import 'package:app_flowy/plugins/grid/application/prelude.dart';
2+
import 'package:flowy_infra/notifier.dart';
3+
14
abstract class FocusableBoardCell {
25
set becomeFocus(bool isFocus);
36
}
7+
8+
class EditableCellNotifier {
9+
final Notifier becomeFirstResponder = Notifier();
10+
11+
final Notifier resignFirstResponder = Notifier();
12+
13+
EditableCellNotifier();
14+
}
15+
16+
class EditableRowNotifier {
17+
Map<EditableCellId, EditableCellNotifier> cells = {};
18+
19+
void insertCell(
20+
GridCellIdentifier cellIdentifier,
21+
EditableCellNotifier notifier,
22+
) {
23+
cells[EditableCellId.from(cellIdentifier)] = notifier;
24+
}
25+
26+
void becomeFirstResponder() {
27+
for (final notifier in cells.values) {
28+
notifier.becomeFirstResponder.notify();
29+
}
30+
}
31+
32+
void resignFirstResponder() {
33+
for (final notifier in cells.values) {
34+
notifier.resignFirstResponder.notify();
35+
}
36+
}
37+
}
38+
39+
abstract class EditableCell {
40+
EditableCellNotifier? get editableNotifier;
41+
}
42+
43+
class EditableCellId {
44+
String fieldId;
45+
String rowId;
46+
47+
EditableCellId(this.rowId, this.fieldId);
48+
49+
factory EditableCellId.from(GridCellIdentifier cellIdentifier) =>
50+
EditableCellId(
51+
cellIdentifier.rowId,
52+
cellIdentifier.fieldId,
53+
);
54+
}

frontend/app_flowy/lib/plugins/board/presentation/card/board_select_option_cell.dart

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,18 @@ import 'package:app_flowy/plugins/grid/presentation/widgets/cell/select_option_c
55
import 'package:flutter/material.dart';
66
import 'package:flutter_bloc/flutter_bloc.dart';
77

8-
class BoardSelectOptionCell extends StatefulWidget {
8+
import 'board_cell.dart';
9+
10+
class BoardSelectOptionCell extends StatefulWidget with EditableCell {
911
final String groupId;
1012
final GridCellControllerBuilder cellControllerBuilder;
13+
@override
14+
final EditableCellNotifier? editableNotifier;
1115

1216
const BoardSelectOptionCell({
1317
required this.groupId,
1418
required this.cellControllerBuilder,
19+
this.editableNotifier,
1520
Key? key,
1621
}) : super(key: key);
1722

frontend/app_flowy/lib/plugins/board/presentation/card/board_text_cell.dart

Lines changed: 38 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,19 @@ import 'package:app_flowy/plugins/grid/presentation/widgets/cell/cell_builder.da
44
import 'package:flutter/material.dart';
55
import 'package:flutter_bloc/flutter_bloc.dart';
66

7-
class BoardTextCell extends StatefulWidget {
7+
import 'board_cell.dart';
8+
9+
class BoardTextCell extends StatefulWidget with EditableCell {
810
final String groupId;
911
final bool isFocus;
10-
12+
@override
13+
final EditableCellNotifier? editableNotifier;
1114
final GridCellControllerBuilder cellControllerBuilder;
1215

1316
const BoardTextCell({
1417
required this.groupId,
1518
required this.cellControllerBuilder,
19+
this.editableNotifier,
1620
this.isFocus = false,
1721
Key? key,
1822
}) : super(key: key);
@@ -37,6 +41,18 @@ class _BoardTextCellState extends State<BoardTextCell> {
3741
if (widget.isFocus) {
3842
focusNode.requestFocus();
3943
}
44+
45+
widget.editableNotifier?.becomeFirstResponder.addListener(() {
46+
if (!mounted) return;
47+
focusNode.requestFocus();
48+
_cellBloc.add(const BoardTextCellEvent.enableEdit(true));
49+
});
50+
51+
widget.editableNotifier?.resignFirstResponder.addListener(() {
52+
if (!mounted) return;
53+
_cellBloc.add(const BoardTextCellEvent.enableEdit(false));
54+
});
55+
4056
super.initState();
4157
}
4258

@@ -50,18 +66,26 @@ class _BoardTextCellState extends State<BoardTextCell> {
5066
_controller.text = state.content;
5167
}
5268
},
53-
child: TextField(
54-
controller: _controller,
55-
focusNode: focusNode,
56-
onChanged: (value) => focusChanged(),
57-
onEditingComplete: () => focusNode.unfocus(),
58-
maxLines: 1,
59-
style: const TextStyle(fontSize: 14, fontWeight: FontWeight.w500),
60-
decoration: const InputDecoration(
61-
contentPadding: EdgeInsets.symmetric(vertical: 6),
62-
border: InputBorder.none,
63-
isDense: true,
64-
),
69+
child: BlocBuilder<BoardTextCellBloc, BoardTextCellState>(
70+
buildWhen: (previous, current) =>
71+
previous.enableEdit != current.enableEdit,
72+
builder: (context, state) {
73+
return TextField(
74+
// autofocus: true,
75+
// enabled: state.enableEdit,
76+
controller: _controller,
77+
focusNode: focusNode,
78+
onChanged: (value) => focusChanged(),
79+
onEditingComplete: () => focusNode.unfocus(),
80+
maxLines: 1,
81+
style: const TextStyle(fontSize: 14, fontWeight: FontWeight.w500),
82+
decoration: const InputDecoration(
83+
contentPadding: EdgeInsets.symmetric(vertical: 6),
84+
border: InputBorder.none,
85+
isDense: true,
86+
),
87+
);
88+
},
6589
),
6690
),
6791
);

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

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import 'package:flowy_infra/theme.dart';
77
import 'package:flowy_infra_ui/flowy_infra_ui_web.dart';
88
import 'package:flutter/material.dart';
99
import 'package:flutter_bloc/flutter_bloc.dart';
10+
import 'board_cell.dart';
1011
import 'card_cell_builder.dart';
1112
import 'card_container.dart';
1213

@@ -36,9 +37,11 @@ class BoardCard extends StatefulWidget {
3637

3738
class _BoardCardState extends State<BoardCard> {
3839
late BoardCardBloc _cardBloc;
40+
late EditableRowNotifier rowNotifier;
3941

4042
@override
4143
void initState() {
44+
rowNotifier = EditableRowNotifier();
4245
_cardBloc = BoardCardBloc(
4346
gridId: widget.gridId,
4447
fieldId: widget.fieldId,
@@ -58,7 +61,12 @@ class _BoardCardState extends State<BoardCard> {
5861
builder: (context, state) {
5962
return BoardCardContainer(
6063
accessoryBuilder: (context) {
61-
return [const _CardMoreOption()];
64+
return [
65+
_CardEditOption(
66+
startEditing: () => rowNotifier.becomeFirstResponder(),
67+
),
68+
const _CardMoreOption(),
69+
];
6270
},
6371
onTap: (context) {
6472
widget.openCard(context);
@@ -83,11 +91,14 @@ class _BoardCardState extends State<BoardCard> {
8391
final List<Widget> children = [];
8492
cells.asMap().forEach(
8593
(int index, GridCellIdentifier cellId) {
94+
final cellNotifier = EditableCellNotifier();
8695
Widget child = widget.cellBuilder.buildCell(
8796
widget.groupId,
8897
cellId,
8998
widget.isEditing,
99+
cellNotifier,
90100
);
101+
rowNotifier.insertCell(cellId, cellNotifier);
91102

92103
if (index != 0) {
93104
child = Padding(
@@ -121,7 +132,11 @@ class _CardMoreOption extends StatelessWidget with CardAccessory {
121132

122133
@override
123134
Widget build(BuildContext context) {
124-
return svgWidget('grid/details', color: context.read<AppTheme>().iconColor);
135+
return Padding(
136+
padding: const EdgeInsets.all(3.0),
137+
child:
138+
svgWidget('grid/details', color: context.read<AppTheme>().iconColor),
139+
);
125140
}
126141

127142
@override
@@ -131,3 +146,27 @@ class _CardMoreOption extends StatelessWidget with CardAccessory {
131146
).show(context, direction: AnchorDirection.bottomWithCenterAligned);
132147
}
133148
}
149+
150+
class _CardEditOption extends StatelessWidget with CardAccessory {
151+
final VoidCallback startEditing;
152+
const _CardEditOption({
153+
required this.startEditing,
154+
Key? key,
155+
}) : super(key: key);
156+
157+
@override
158+
Widget build(BuildContext context) {
159+
return Padding(
160+
padding: const EdgeInsets.all(3.0),
161+
child: svgWidget(
162+
'editor/edit',
163+
color: context.read<AppTheme>().iconColor,
164+
),
165+
);
166+
}
167+
168+
@override
169+
void onTap(BuildContext context) {
170+
startEditing();
171+
}
172+
}

frontend/app_flowy/lib/plugins/board/presentation/card/card_cell_builder.dart

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import 'package:app_flowy/plugins/grid/application/cell/cell_service/cell_servic
22
import 'package:flowy_sdk/protobuf/flowy-grid/field_entities.pb.dart';
33
import 'package:flutter/material.dart';
44

5+
import 'board_cell.dart';
56
import 'board_checkbox_cell.dart';
67
import 'board_date_cell.dart';
78
import 'board_number_cell.dart';
@@ -23,6 +24,7 @@ class BoardCellBuilder {
2324
String groupId,
2425
GridCellIdentifier cellId,
2526
bool isEditing,
27+
EditableCellNotifier cellNotifier,
2628
) {
2729
final cellControllerBuilder = GridCellControllerBuilder(
2830
delegate: delegate,
@@ -54,6 +56,7 @@ class BoardCellBuilder {
5456
return BoardSelectOptionCell(
5557
groupId: groupId,
5658
cellControllerBuilder: cellControllerBuilder,
59+
editableNotifier: cellNotifier,
5760
key: key,
5861
);
5962
case FieldType.Number:
@@ -67,6 +70,7 @@ class BoardCellBuilder {
6770
groupId: groupId,
6871
cellControllerBuilder: cellControllerBuilder,
6972
isFocus: isEditing,
73+
editableNotifier: cellNotifier,
7074
key: key,
7175
);
7276
case FieldType.URL:

frontend/app_flowy/lib/plugins/board/presentation/card/card_container.dart

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -69,12 +69,11 @@ class CardAccessoryContainer extends StatelessWidget {
6969
style: HoverStyle(
7070
hoverColor: theme.hover,
7171
backgroundColor: theme.surface,
72+
borderRadius: BorderRadius.zero,
7273
),
73-
builder: (_, onHover) => Container(
74-
width: 26,
75-
height: 26,
76-
padding: const EdgeInsets.all(3),
77-
decoration: _makeBoxDecoration(context),
74+
builder: (_, onHover) => SizedBox(
75+
width: 24,
76+
height: 24,
7877
child: accessory,
7978
),
8079
);
@@ -85,7 +84,11 @@ class CardAccessoryContainer extends StatelessWidget {
8584
);
8685
}).toList();
8786

88-
return Wrap(children: children, spacing: 6);
87+
return Container(
88+
clipBehavior: Clip.hardEdge,
89+
decoration: _makeBoxDecoration(context),
90+
child: Row(children: children),
91+
);
8992
}
9093
}
9194

@@ -95,15 +98,16 @@ BoxDecoration _makeBoxDecoration(BuildContext context) {
9598
return BoxDecoration(
9699
color: Colors.transparent,
97100
border: Border.fromBorderSide(borderSide),
98-
boxShadow: const [
99-
BoxShadow(
100-
color: Colors.transparent,
101-
spreadRadius: 0,
102-
blurRadius: 2,
103-
offset: Offset.zero,
104-
)
105-
],
106-
borderRadius: const BorderRadius.all(Radius.circular(6)),
101+
// boxShadow: const [
102+
// BoxShadow(
103+
// color: Colors.transparent,
104+
// spreadRadius: 0,
105+
// blurRadius: 5,
106+
// offset: Offset.zero,
107+
// )
108+
// ],
109+
110+
borderRadius: const BorderRadius.all(Radius.circular(4)),
107111
);
108112
}
109113

frontend/app_flowy/packages/flowy_infra/lib/notifier.dart

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,8 @@ class PublishNotifier<T> extends ChangeNotifier {
3131

3232
T? get currentValue => _value;
3333

34-
void addPublishListener(void Function(T) callback, {bool Function()? listenWhen}) {
34+
void addPublishListener(void Function(T) callback,
35+
{bool Function()? listenWhen}) {
3536
super.addListener(
3637
() {
3738
if (_value == null) {
@@ -47,3 +48,9 @@ class PublishNotifier<T> extends ChangeNotifier {
4748
);
4849
}
4950
}
51+
52+
class Notifier extends ChangeNotifier {
53+
void notify() {
54+
notifyListeners();
55+
}
56+
}

0 commit comments

Comments
 (0)