Skip to content

Commit 18752e7

Browse files
committed
chore: show create option message on bottom
1 parent 228695d commit 18752e7

File tree

6 files changed

+137
-29
lines changed

6 files changed

+137
-29
lines changed

frontend/app_flowy/assets/translations/en.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,7 @@
181181
"textPlaceholder": "Empty"
182182
},
183183
"selectOption": {
184+
"create": "Create",
184185
"purpleColor": "Purple",
185186
"pinkColor": "Pink",
186187
"lightPinkColor": "Light Pink",

frontend/app_flowy/lib/workspace/application/grid/cell/selection_editor_bloc.dart

Lines changed: 54 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
1-
import 'package:app_flowy/workspace/application/grid/cell/cell_service.dart';
1+
import 'dart:async';
2+
3+
import 'package:dartz/dartz.dart';
24
import 'package:flowy_sdk/log.dart';
35
import 'package:flowy_sdk/protobuf/flowy-grid/selection_type_option.pb.dart';
46
import 'package:flutter_bloc/flutter_bloc.dart';
57
import 'package:freezed_annotation/freezed_annotation.dart';
6-
import 'dart:async';
8+
9+
import 'package:app_flowy/workspace/application/grid/cell/cell_service.dart';
10+
711
import 'select_option_service.dart';
812

913
part 'selection_editor_bloc.freezed.dart';
@@ -24,14 +28,19 @@ class SelectOptionEditorBloc extends Bloc<SelectOptionEditorEvent, SelectOptionE
2428
_startListening();
2529
},
2630
didReceiveOptions: (_DidReceiveOptions value) {
31+
final result = _makeOptions(state.filter, value.options);
2732
emit(state.copyWith(
2833
allOptions: value.options,
29-
options: _makeOptions(state.filter, value.options),
34+
options: result.options,
35+
createOption: result.createOption,
3036
selectedOptions: value.selectedOptions,
3137
));
3238
},
3339
newOption: (_NewOption value) {
3440
_createOption(value.optionName);
41+
emit(state.copyWith(
42+
filter: none(),
43+
));
3544
},
3645
deleteOption: (_DeleteOption value) {
3746
_deleteOption(value.option);
@@ -91,16 +100,37 @@ class SelectOptionEditorBloc extends Bloc<SelectOptionEditorEvent, SelectOptionE
91100
}
92101

93102
void _filterOption(String optionName, Emitter<SelectOptionEditorState> emit) {
94-
emit(state.copyWith(filter: optionName, options: _makeOptions(optionName, state.allOptions)));
103+
final _MakeOptionResult result = _makeOptions(Some(optionName), state.allOptions);
104+
emit(state.copyWith(
105+
filter: Some(optionName),
106+
options: result.options,
107+
createOption: result.createOption,
108+
));
95109
}
96110

97-
List<SelectOption> _makeOptions(String filter, List<SelectOption> allOptions) {
111+
_MakeOptionResult _makeOptions(Option<String> filter, List<SelectOption> allOptions) {
98112
final List<SelectOption> options = List.from(allOptions);
99-
if (filter.isNotEmpty) {
100-
options.retainWhere((option) => option.name.toLowerCase().contains(filter.toLowerCase()));
101-
}
102-
103-
return options;
113+
Option<String> createOption = filter;
114+
115+
filter.foldRight(null, (filter, previous) {
116+
if (filter.isNotEmpty) {
117+
options.retainWhere((option) {
118+
final name = option.name.toLowerCase();
119+
final lFilter = filter.toLowerCase();
120+
121+
if (name == lFilter) {
122+
createOption = none();
123+
}
124+
125+
return name.contains(lFilter);
126+
});
127+
}
128+
});
129+
130+
return _MakeOptionResult(
131+
options: options,
132+
createOption: createOption,
133+
);
104134
}
105135

106136
void _startListening() {
@@ -135,7 +165,8 @@ class SelectOptionEditorState with _$SelectOptionEditorState {
135165
required List<SelectOption> options,
136166
required List<SelectOption> allOptions,
137167
required List<SelectOption> selectedOptions,
138-
required String filter,
168+
required Option<String> createOption,
169+
required Option<String> filter,
139170
}) = _SelectOptionEditorState;
140171

141172
factory SelectOptionEditorState.initial(GridSelectOptionCellContext context) {
@@ -144,7 +175,18 @@ class SelectOptionEditorState with _$SelectOptionEditorState {
144175
options: data?.options ?? [],
145176
allOptions: data?.options ?? [],
146177
selectedOptions: data?.selectOptions ?? [],
147-
filter: "",
178+
createOption: none(),
179+
filter: none(),
148180
);
149181
}
150182
}
183+
184+
class _MakeOptionResult {
185+
List<SelectOption> options;
186+
Option<String> createOption;
187+
188+
_MakeOptionResult({
189+
required this.options,
190+
required this.createOption,
191+
});
192+
}

frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/selection_cell/extension.dart

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -60,17 +60,35 @@ extension SelectOptionColorExtension on SelectOptionColor {
6060
}
6161

6262
class SelectOptionTag extends StatelessWidget {
63-
final SelectOption option;
63+
final String name;
64+
final Color color;
6465
final bool isSelected;
65-
const SelectOptionTag({required this.option, this.isSelected = false, Key? key}) : super(key: key);
66+
const SelectOptionTag({
67+
required this.name,
68+
required this.color,
69+
this.isSelected = false,
70+
Key? key,
71+
}) : super(key: key);
72+
73+
factory SelectOptionTag.fromSelectOption({
74+
required BuildContext context,
75+
required SelectOption option,
76+
bool isSelected = false,
77+
}) {
78+
return SelectOptionTag(
79+
name: option.name,
80+
color: option.color.make(context),
81+
isSelected: isSelected,
82+
);
83+
}
6684

6785
@override
6886
Widget build(BuildContext context) {
6987
return ChoiceChip(
7088
pressElevation: 1,
71-
label: FlowyText.medium(option.name, fontSize: 12),
72-
selectedColor: option.color.make(context),
73-
backgroundColor: option.color.make(context),
89+
label: FlowyText.medium(name, fontSize: 12),
90+
selectedColor: color,
91+
backgroundColor: color,
7492
labelPadding: const EdgeInsets.symmetric(horizontal: 6),
7593
selected: true,
7694
onSelected: (_) {},

frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/selection_cell/selection_cell.dart

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,14 @@ class _SelectOptionCell extends StatelessWidget {
150150
child: FlowyText.medium(cellStyle!.placeholder, fontSize: 14, color: theme.shader3),
151151
);
152152
} else {
153-
final tags = selectOptions.map((option) => SelectOptionTag(option: option)).toList();
153+
final tags = selectOptions
154+
.map(
155+
(option) => SelectOptionTag.fromSelectOption(
156+
context: context,
157+
option: option,
158+
),
159+
)
160+
.toList();
154161
child = Align(
155162
alignment: Alignment.centerLeft,
156163
child: Wrap(children: tags, spacing: 4, runSpacing: 4),

frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/selection_cell/selection_editor.dart

Lines changed: 46 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -104,9 +104,18 @@ class _OptionList extends StatelessWidget {
104104
Widget build(BuildContext context) {
105105
return BlocBuilder<SelectOptionEditorBloc, SelectOptionEditorState>(
106106
builder: (context, state) {
107-
final cells = state.options.map((option) {
107+
List<Widget> cells = [];
108+
cells.addAll(state.options.map((option) {
108109
return _SelectOptionCell(option, state.selectedOptions.contains(option));
109-
}).toList();
110+
}).toList());
111+
112+
state.createOption.fold(
113+
() => null,
114+
(createOption) {
115+
cells.add(_CreateOptionCell(name: createOption));
116+
},
117+
);
118+
110119
final list = ListView.separated(
111120
shrinkWrap: true,
112121
controller: ScrollController(),
@@ -119,7 +128,11 @@ class _OptionList extends StatelessWidget {
119128
return cells[index];
120129
},
121130
);
122-
return list;
131+
132+
return Padding(
133+
padding: const EdgeInsets.all(3.0),
134+
child: list,
135+
);
123136
},
124137
);
125138
}
@@ -177,6 +190,30 @@ class _Title extends StatelessWidget {
177190
}
178191
}
179192

193+
class _CreateOptionCell extends StatelessWidget {
194+
final String name;
195+
const _CreateOptionCell({required this.name, Key? key}) : super(key: key);
196+
197+
@override
198+
Widget build(BuildContext context) {
199+
final theme = context.watch<AppTheme>();
200+
return Row(
201+
children: [
202+
FlowyText.medium(
203+
LocaleKeys.grid_selectOption_create.tr(),
204+
fontSize: 12,
205+
color: theme.shader3,
206+
),
207+
const HSpace(10),
208+
SelectOptionTag(
209+
name: name,
210+
color: theme.shader6,
211+
),
212+
],
213+
);
214+
}
215+
}
216+
180217
class _SelectOptionCell extends StatelessWidget {
181218
final SelectOption option;
182219
final bool isSelected;
@@ -206,7 +243,11 @@ class _SelectOptionCell extends StatelessWidget {
206243
style: HoverStyle(hoverColor: theme.hover),
207244
builder: (_, onHover) {
208245
List<Widget> children = [
209-
SelectOptionTag(option: option, isSelected: isSelected),
246+
SelectOptionTag(
247+
name: option.name,
248+
color: option.color.make(context),
249+
isSelected: isSelected,
250+
),
210251
const Spacer(),
211252
];
212253

@@ -223,10 +264,7 @@ class _SelectOptionCell extends StatelessWidget {
223264
));
224265
}
225266

226-
return Padding(
227-
padding: const EdgeInsets.all(3.0),
228-
child: Row(children: children),
229-
);
267+
return Row(children: children);
230268
},
231269
);
232270
}

frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/selection_cell/text_field.dart

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ class SelectOptionTextField extends StatelessWidget {
7676
borderRadius: Corners.s10Border,
7777
),
7878
isDense: true,
79-
prefixIcon: _renderTags(sc),
79+
prefixIcon: _renderTags(context, sc),
8080
hintText: LocaleKeys.grid_selectOption_searchOption.tr(),
8181
prefixIconConstraints: BoxConstraints(maxWidth: distanceToText),
8282
focusedBorder: OutlineInputBorder(
@@ -90,12 +90,14 @@ class SelectOptionTextField extends StatelessWidget {
9090
);
9191
}
9292

93-
Widget? _renderTags(ScrollController sc) {
93+
Widget? _renderTags(BuildContext context, ScrollController sc) {
9494
if (selectedOptionMap.isEmpty) {
9595
return null;
9696
}
9797

98-
final children = selectedOptionMap.values.map((option) => SelectOptionTag(option: option)).toList();
98+
final children = selectedOptionMap.values
99+
.map((option) => SelectOptionTag.fromSelectOption(context: context, option: option))
100+
.toList();
99101
return Padding(
100102
padding: const EdgeInsets.all(8.0),
101103
child: SingleChildScrollView(

0 commit comments

Comments
 (0)