Skip to content

Commit 29e0708

Browse files
committed
fix: checklist cell did get notified after the cell content change
1 parent 3cdd666 commit 29e0708

File tree

12 files changed

+195
-90
lines changed

12 files changed

+195
-90
lines changed

frontend/app_flowy/lib/plugins/grid/application/cell/checklist_cell_bloc.dart

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,11 @@ class ChecklistCellBloc extends Bloc<ChecklistCellEvent, ChecklistCellState> {
5151
onCellFieldChanged: () {
5252
_loadOptions();
5353
},
54-
onCellChanged: (_) {},
54+
onCellChanged: (data) {
55+
if (!isClosed && data != null) {
56+
add(ChecklistCellEvent.didReceiveOptions(data));
57+
}
58+
},
5559
);
5660
}
5761

frontend/app_flowy/lib/plugins/grid/application/cell/checklist_cell_editor_bloc.dart

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ class ChecklistCellEditorBloc
1515
extends Bloc<ChecklistCellEditorEvent, ChecklistCellEditorState> {
1616
final SelectOptionFFIService _selectOptionService;
1717
final GridChecklistCellController cellController;
18-
Timer? _delayOperation;
1918

2019
ChecklistCellEditorBloc({
2120
required this.cellController,
@@ -27,7 +26,6 @@ class ChecklistCellEditorBloc
2726
await event.when(
2827
initial: () async {
2928
_startListening();
30-
_loadOptions();
3129
},
3230
didReceiveOptions: (data) {
3331
emit(state.copyWith(
@@ -47,11 +45,12 @@ class ChecklistCellEditorBloc
4745
updateOption: (option) {
4846
_updateOption(option);
4947
},
50-
selectOption: (optionId) {
51-
_selectOptionService.select(optionIds: [optionId]);
52-
},
53-
unSelectOption: (optionId) {
54-
_selectOptionService.unSelect(optionIds: [optionId]);
48+
selectOption: (option) async {
49+
if (option.isSelected) {
50+
await _selectOptionService.unSelect(optionIds: [option.data.id]);
51+
} else {
52+
await _selectOptionService.select(optionIds: [option.data.id]);
53+
}
5554
},
5655
filterOption: (String predicate) {},
5756
);
@@ -61,7 +60,6 @@ class ChecklistCellEditorBloc
6160

6261
@override
6362
Future<void> close() async {
64-
_delayOperation?.cancel();
6563
await cellController.dispose();
6664
return super.close();
6765
}
@@ -119,10 +117,8 @@ class ChecklistCellEditorEvent with _$ChecklistCellEditorEvent {
119117
SelectOptionCellDataPB data) = _DidReceiveOptions;
120118
const factory ChecklistCellEditorEvent.newOption(String optionName) =
121119
_NewOption;
122-
const factory ChecklistCellEditorEvent.selectOption(String optionId) =
123-
_SelectOption;
124-
const factory ChecklistCellEditorEvent.unSelectOption(String optionId) =
125-
_UnSelectOption;
120+
const factory ChecklistCellEditorEvent.selectOption(
121+
ChecklistSelectOption option) = _SelectOption;
126122
const factory ChecklistCellEditorEvent.updateOption(SelectOptionPB option) =
127123
_UpdateOption;
128124
const factory ChecklistCellEditorEvent.deleteOption(SelectOptionPB option) =

frontend/app_flowy/lib/plugins/grid/application/field/field_controller.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -522,6 +522,7 @@ class FieldInfo {
522522
case FieldType.MultiSelect:
523523
case FieldType.RichText:
524524
case FieldType.SingleSelect:
525+
// case FieldType.Checklist:
525526
return true;
526527
default:
527528
return false;

frontend/app_flowy/lib/plugins/grid/presentation/widgets/cell/checklist_cell/checklist_cell.dart

Lines changed: 10 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -36,20 +36,16 @@ class GridChecklistCellState extends State<GridChecklistCell> {
3636
Widget build(BuildContext context) {
3737
return BlocProvider.value(
3838
value: _cellBloc,
39-
child: BlocBuilder<ChecklistCellBloc, ChecklistCellState>(
40-
builder: (context, state) {
41-
return Stack(
42-
alignment: AlignmentDirectional.center,
43-
fit: StackFit.expand,
44-
children: [
45-
Padding(
46-
padding: GridSize.cellContentInsets,
47-
child: _wrapPopover(const ChecklistProgressBar()),
48-
),
49-
InkWell(onTap: () => _popover.show()),
50-
],
51-
);
52-
},
39+
child: Stack(
40+
alignment: AlignmentDirectional.center,
41+
fit: StackFit.expand,
42+
children: [
43+
Padding(
44+
padding: GridSize.cellContentInsets,
45+
child: _wrapPopover(const ChecklistProgressBar()),
46+
),
47+
InkWell(onTap: () => _popover.show()),
48+
],
5349
),
5450
);
5551
}

frontend/app_flowy/lib/plugins/grid/presentation/widgets/cell/checklist_cell/checklist_cell_editor.dart

Lines changed: 52 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import 'package:app_flowy/plugins/grid/presentation/widgets/header/type_option/s
66
import 'package:appflowy_popover/appflowy_popover.dart';
77
import 'package:flowy_infra/image.dart';
88
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
9+
import 'package:flowy_infra_ui/style_widget/button.dart';
910
import 'package:flowy_infra_ui/style_widget/icon_button.dart';
1011
import 'package:flowy_infra_ui/style_widget/scrolling/styled_list.dart';
1112
import 'package:flowy_infra_ui/widget/spacing.dart';
@@ -24,9 +25,11 @@ class GridChecklistCellEditor extends StatefulWidget {
2425

2526
class _GridChecklistCellEditorState extends State<GridChecklistCellEditor> {
2627
late ChecklistCellEditorBloc bloc;
28+
late PopoverMutex popoverMutex;
2729

2830
@override
2931
void initState() {
32+
popoverMutex = PopoverMutex();
3033
bloc = ChecklistCellEditorBloc(cellController: widget.cellController);
3134
bloc.add(const ChecklistCellEditorEvent.initial());
3235
super.initState();
@@ -47,23 +50,28 @@ class _GridChecklistCellEditorState extends State<GridChecklistCellEditor> {
4750
final List<Widget> slivers = [
4851
const SliverChecklistPrograssBar(),
4952
SliverToBoxAdapter(
50-
child: Container(color: Colors.red, height: 2, width: 2100)),
51-
SliverToBoxAdapter(
52-
child: ListView.separated(
53-
controller: ScrollController(),
54-
shrinkWrap: true,
55-
itemCount: state.allOptions.length,
56-
itemBuilder: (BuildContext context, int index) {
57-
return _ChecklistOptionCell(option: state.allOptions[index]);
58-
},
59-
separatorBuilder: (BuildContext context, int index) {
60-
return VSpace(GridSize.typeOptionSeparatorHeight);
61-
},
53+
child: Padding(
54+
padding: GridSize.typeOptionContentInsets,
55+
child: ListView.separated(
56+
controller: ScrollController(),
57+
shrinkWrap: true,
58+
itemCount: state.allOptions.length,
59+
itemBuilder: (BuildContext context, int index) {
60+
return _ChecklistOptionCell(
61+
option: state.allOptions[index],
62+
popoverMutex: popoverMutex,
63+
);
64+
},
65+
separatorBuilder: (BuildContext context, int index) {
66+
return VSpace(GridSize.typeOptionSeparatorHeight);
67+
},
68+
),
6269
),
6370
),
6471
];
65-
return Padding(
66-
padding: const EdgeInsets.symmetric(horizontal: 8),
72+
73+
return ScrollConfiguration(
74+
behavior: const ScrollBehavior().copyWith(scrollbars: false),
6775
child: CustomScrollView(
6876
shrinkWrap: true,
6977
slivers: slivers,
@@ -79,8 +87,10 @@ class _GridChecklistCellEditorState extends State<GridChecklistCellEditor> {
7987

8088
class _ChecklistOptionCell extends StatefulWidget {
8189
final ChecklistSelectOption option;
90+
final PopoverMutex popoverMutex;
8291
const _ChecklistOptionCell({
8392
required this.option,
93+
required this.popoverMutex,
8494
Key? key,
8595
}) : super(key: key);
8696

@@ -107,10 +117,15 @@ class _ChecklistOptionCellState extends State<_ChecklistOptionCell> {
107117
height: GridSize.typeOptionItemHeight,
108118
child: Row(
109119
children: [
110-
icon,
111-
const HSpace(6),
112-
FlowyText(widget.option.data.name),
113-
const Spacer(),
120+
Expanded(
121+
child: FlowyButton(
122+
text: FlowyText(widget.option.data.name),
123+
leftIcon: icon,
124+
onTap: () => context
125+
.read<ChecklistCellEditorBloc>()
126+
.add(ChecklistCellEditorEvent.selectOption(widget.option)),
127+
),
128+
),
114129
_disclosureButton(),
115130
],
116131
),
@@ -122,8 +137,7 @@ class _ChecklistOptionCellState extends State<_ChecklistOptionCell> {
122137
return FlowyIconButton(
123138
width: 20,
124139
onPressed: () => _popoverController.show(),
125-
hoverColor: Colors.transparent,
126-
iconPadding: const EdgeInsets.fromLTRB(4, 4, 4, 4),
140+
iconPadding: const EdgeInsets.fromLTRB(2, 2, 2, 2),
127141
icon: svgWidget(
128142
"editor/details",
129143
color: Theme.of(context).colorScheme.onSurface,
@@ -137,15 +151,30 @@ class _ChecklistOptionCellState extends State<_ChecklistOptionCell> {
137151
offset: const Offset(20, 0),
138152
asBarrier: true,
139153
constraints: BoxConstraints.loose(const Size(200, 300)),
154+
mutex: widget.popoverMutex,
155+
triggerActions: PopoverTriggerFlags.none,
140156
child: child,
141157
popupBuilder: (BuildContext popoverContext) {
142158
return SelectOptionTypeOptionEditor(
143159
option: widget.option.data,
144-
onDeleted: () {},
145-
onUpdated: (updatedOption) {},
160+
onDeleted: () {
161+
context.read<ChecklistCellEditorBloc>().add(
162+
ChecklistCellEditorEvent.deleteOption(widget.option.data),
163+
);
164+
165+
_popoverController.close();
166+
},
167+
onUpdated: (updatedOption) {
168+
context.read<ChecklistCellEditorBloc>().add(
169+
ChecklistCellEditorEvent.updateOption(widget.option.data),
170+
);
171+
},
172+
showOptions: false,
173+
autoFocus: false,
174+
// Use ValueKey to refresh the UI, otherwise, it will remain the old value.
146175
key: ValueKey(
147176
widget.option.data.id,
148-
), // Use ValueKey to refresh the UI, otherwise, it will remain the old value.
177+
),
149178
);
150179
},
151180
);

frontend/app_flowy/lib/plugins/grid/presentation/widgets/cell/checklist_cell/checklist_prograss_bar.dart

Lines changed: 27 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import 'package:app_flowy/generated/locale_keys.g.dart';
22
import 'package:app_flowy/plugins/grid/application/cell/checklist_cell_editor_bloc.dart';
3+
import 'package:app_flowy/plugins/grid/presentation/layout/sizes.dart';
34
import 'package:easy_localization/easy_localization.dart';
45
import 'package:flowy_infra/color_extension.dart';
56
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
@@ -41,34 +42,39 @@ class _SliverChecklistPrograssBarDelegate
4142
extends SliverPersistentHeaderDelegate {
4243
_SliverChecklistPrograssBarDelegate();
4344

44-
double fixHeight = 80;
45+
double fixHeight = 60;
4546

4647
@override
4748
Widget build(
4849
BuildContext context, double shrinkOffset, bool overlapsContent) {
4950
return BlocBuilder<ChecklistCellEditorBloc, ChecklistCellEditorState>(
5051
builder: (context, state) {
51-
return Column(
52-
children: [
53-
if (state.percent != 0)
54-
Padding(
55-
padding: const EdgeInsets.symmetric(vertical: 8.0),
56-
child: ChecklistPrograssBar(percent: state.percent),
52+
return Container(
53+
color: Theme.of(context).colorScheme.background,
54+
padding: GridSize.typeOptionContentInsets,
55+
child: Column(
56+
children: [
57+
FlowyTextField(
58+
autoClearWhenDone: true,
59+
hintText: LocaleKeys.grid_checklist_panelTitle.tr(),
60+
onChanged: (text) {
61+
context
62+
.read<ChecklistCellEditorBloc>()
63+
.add(ChecklistCellEditorEvent.filterOption(text));
64+
},
65+
onSubmitted: (text) {
66+
context
67+
.read<ChecklistCellEditorBloc>()
68+
.add(ChecklistCellEditorEvent.newOption(text));
69+
},
5770
),
58-
FlowyTextField(
59-
hintText: LocaleKeys.grid_checklist_panelTitle.tr(),
60-
onChanged: (text) {
61-
context
62-
.read<ChecklistCellEditorBloc>()
63-
.add(ChecklistCellEditorEvent.filterOption(text));
64-
},
65-
onSubmitted: (text) {
66-
context
67-
.read<ChecklistCellEditorBloc>()
68-
.add(ChecklistCellEditorEvent.newOption(text));
69-
},
70-
)
71-
],
71+
if (state.percent != 0)
72+
Padding(
73+
padding: const EdgeInsets.symmetric(vertical: 8.0),
74+
child: ChecklistPrograssBar(percent: state.percent),
75+
),
76+
],
77+
),
7278
);
7379
},
7480
);

frontend/app_flowy/lib/plugins/grid/presentation/widgets/header/type_option/select_option_editor.dart

Lines changed: 27 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import 'package:flowy_infra/image.dart';
44
import 'package:flowy_infra_ui/style_widget/button.dart';
55
import 'package:flowy_infra_ui/style_widget/scrolling/styled_list.dart';
66
import 'package:flowy_infra_ui/style_widget/text.dart';
7+
import 'package:flowy_infra_ui/style_widget/text_field.dart';
78
import 'package:flowy_infra_ui/widget/spacing.dart';
89
import 'package:flowy_sdk/protobuf/flowy-grid/select_type_option.pb.dart';
910
import 'package:flutter/material.dart';
@@ -18,10 +19,14 @@ class SelectOptionTypeOptionEditor extends StatelessWidget {
1819
final SelectOptionPB option;
1920
final VoidCallback onDeleted;
2021
final Function(SelectOptionPB) onUpdated;
22+
final bool showOptions;
23+
final bool autoFocus;
2124
const SelectOptionTypeOptionEditor({
2225
required this.option,
2326
required this.onDeleted,
2427
required this.onUpdated,
28+
this.showOptions = true,
29+
this.autoFocus = true,
2530
Key? key,
2631
}) : super(key: key);
2732

@@ -50,21 +55,29 @@ class SelectOptionTypeOptionEditor extends StatelessWidget {
5055
builder: (context, state) {
5156
List<Widget> slivers = [
5257
SliverToBoxAdapter(
53-
child: _OptionNameTextField(state.option.name)),
58+
child: _OptionNameTextField(
59+
name: state.option.name,
60+
autoFocus: autoFocus,
61+
)),
5462
const SliverToBoxAdapter(child: VSpace(10)),
5563
const SliverToBoxAdapter(child: _DeleteTag()),
56-
const SliverToBoxAdapter(child: TypeOptionSeparator()),
57-
SliverToBoxAdapter(
58-
child:
59-
SelectOptionColorList(selectedColor: state.option.color)),
6064
];
6165

66+
if (showOptions) {
67+
slivers
68+
.add(const SliverToBoxAdapter(child: TypeOptionSeparator()));
69+
slivers.add(SliverToBoxAdapter(
70+
child: SelectOptionColorList(
71+
selectedColor: state.option.color)));
72+
}
73+
6274
return SizedBox(
6375
width: 160,
6476
child: Padding(
6577
padding: const EdgeInsets.all(6.0),
6678
child: CustomScrollView(
6779
slivers: slivers,
80+
shrinkWrap: true,
6881
controller: ScrollController(),
6982
physics: StyledScrollPhysics(),
7083
),
@@ -102,19 +115,21 @@ class _DeleteTag extends StatelessWidget {
102115

103116
class _OptionNameTextField extends StatelessWidget {
104117
final String name;
105-
const _OptionNameTextField(this.name, {Key? key}) : super(key: key);
118+
final bool autoFocus;
119+
const _OptionNameTextField(
120+
{required this.name, required this.autoFocus, Key? key})
121+
: super(key: key);
106122

107123
@override
108124
Widget build(BuildContext context) {
109-
return InputTextField(
125+
return FlowyTextField(
126+
autoFucous: autoFocus,
110127
text: name,
111-
maxLength: 30,
112-
onCanceled: () {},
113-
onDone: (optionName) {
114-
if (name != optionName) {
128+
onSubmitted: (newName) {
129+
if (name != newName) {
115130
context
116131
.read<EditSelectOptionBloc>()
117-
.add(EditSelectOptionEvent.updateName(optionName));
132+
.add(EditSelectOptionEvent.updateName(newName));
118133
}
119134
},
120135
);

0 commit comments

Comments
 (0)