@@ -2,8 +2,7 @@ import 'package:appflowy/generated/flowy_svgs.g.dart';
22import 'package:appflowy/generated/locale_keys.g.dart' ;
33import 'package:appflowy/plugins/document/presentation/editor_plugins/actions/block_action_option_cubit.dart' ;
44import 'package:appflowy/plugins/document/presentation/editor_plugins/plugins.dart' ;
5- import 'package:appflowy/startup/startup.dart' ;
6- import 'package:appflowy/workspace/presentation/home/menu/menu_shared_state.dart' ;
5+ import 'package:appflowy/plugins/document/presentation/editor_plugins/toolbar_item/text_suggestions_toolbar_item.dart' ;
76import 'package:appflowy/workspace/presentation/widgets/pop_up_action.dart' ;
87import 'package:appflowy_editor/appflowy_editor.dart'
98 hide QuoteBlockKeys, quoteNode;
@@ -149,214 +148,134 @@ class TurnIntoOptionMenu extends StatelessWidget {
149148
150149 @override
151150 Widget build (BuildContext context) {
152- return Column (
153- mainAxisSize: MainAxisSize .min,
154- children: _buildTurnIntoOptions (context, node),
155- );
156- }
157-
158- List <Widget > _buildTurnIntoOptions (BuildContext context, Node node) {
159- final children = < Widget > [];
160-
161151 if (hasNonSupportedTypes) {
162- return children
163- ..add (
164- _TurnInfoButton (
165- type: SubPageBlockKeys .type,
166- node: node,
167- ),
168- );
152+ return buildItem (
153+ pateItem,
154+ textSuggestionItem,
155+ context.read <BlockActionOptionCubit >().editorState,
156+ );
169157 }
170158
171- for (final type in EditorOptionActionType .turnInto.supportTypes) {
172- if (type == ToggleListBlockKeys .type) {
173- // toggle list block and toggle heading block are the same type,
174- // but they have different attributes.
175-
176- // toggle list block
177- children.add (
178- _TurnInfoButton (
179- type: type,
180- node: node,
181- ),
182- );
159+ return _buildTurnIntoOptions (context, node);
160+ }
183161
184- // toggle heading block
185- for (final i in [1 , 2 , 3 ]) {
186- children.add (
187- _TurnInfoButton (
188- type: type,
189- node: node,
190- level: i,
191- ),
192- );
162+ Widget _buildTurnIntoOptions (BuildContext context, Node node) {
163+ final editorState = context.read <BlockActionOptionCubit >().editorState;
164+ SuggestionItem currentSuggestionItem = textSuggestionItem;
165+ final List <SuggestionItem > suggestionItems = suggestions.sublist (0 , 4 );
166+ final List <SuggestionItem > turnIntoItems =
167+ suggestions.sublist (4 , suggestions.length);
168+ final textColor = Color (0xff99A1A8 );
169+
170+ void refreshSuggestions () {
171+ final selection = editorState.selection;
172+ if (selection == null || ! selection.isSingle) return ;
173+ final node = editorState.getNodeAtPath (selection.start.path);
174+ if (node == null || node.delta == null ) return ;
175+ final nodeType = node.type;
176+ SuggestionType ? suggestionType;
177+ if (nodeType == HeadingBlockKeys .type) {
178+ final level = node.attributes[HeadingBlockKeys .level] ?? 1 ;
179+ if (level == 1 ) {
180+ suggestionType = SuggestionType .h1;
181+ } else if (level == 2 ) {
182+ suggestionType = SuggestionType .h2;
183+ } else if (level == 3 ) {
184+ suggestionType = SuggestionType .h3;
185+ }
186+ } else if (nodeType == ToggleListBlockKeys .type) {
187+ final level = node.attributes[ToggleListBlockKeys .level];
188+ if (level == null ) {
189+ suggestionType = SuggestionType .toggle;
190+ } else if (level == 1 ) {
191+ suggestionType = SuggestionType .toggleH1;
192+ } else if (level == 2 ) {
193+ suggestionType = SuggestionType .toggleH2;
194+ } else if (level == 3 ) {
195+ suggestionType = SuggestionType .toggleH3;
193196 }
194- } else if (type != HeadingBlockKeys .type) {
195- children.add (
196- _TurnInfoButton (
197- type: type,
198- node: node,
199- ),
200- );
201197 } else {
202- for (final i in [1 , 2 , 3 ]) {
203- children.add (
204- _TurnInfoButton (
205- type: type,
206- node: node,
207- level: i,
208- ),
209- );
198+ suggestionType = nodeType2SuggestionType[nodeType];
199+ }
200+ if (suggestionType == null ) return ;
201+ suggestionItems.clear ();
202+ turnIntoItems.clear ();
203+ for (final item in suggestions) {
204+ if (item.type.group == suggestionType.group &&
205+ item.type != suggestionType) {
206+ suggestionItems.add (item);
207+ } else {
208+ turnIntoItems.add (item);
210209 }
211210 }
211+ currentSuggestionItem =
212+ suggestions.where ((item) => item.type == suggestionType).first;
212213 }
213214
214- return children;
215- }
216- }
217-
218- class _TurnInfoButton extends StatelessWidget {
219- const _TurnInfoButton ({
220- required this .type,
221- required this .node,
222- this .level,
223- });
224-
225- final String type;
226- final Node node;
227- final int ? level;
228-
229- @override
230- Widget build (BuildContext context) {
231- final name = _buildLocalization (type, level: level);
232- final leftIcon = _buildLeftIcon (type, level: level);
233- final rightIcon = _buildRightIcon (type, node, level: level);
215+ refreshSuggestions ();
234216
235- return HoverButton (
236- name: name,
237- leftIcon: FlowySvg (leftIcon),
238- rightIcon: rightIcon,
239- itemHeight: ActionListSizes .itemHeight,
240- onTap: () => BlockActionOptionCubit .turnIntoBlock (
241- type,
242- node,
243- context.read <BlockActionOptionCubit >().editorState,
244- level: level,
245- currentViewId: getIt <MenuSharedState >().latestOpenView? .id,
246- ),
217+ return Column (
218+ mainAxisSize: MainAxisSize .min,
219+ crossAxisAlignment: CrossAxisAlignment .start,
220+ children: [
221+ buildSubTitle (
222+ LocaleKeys .document_toolbar_suggestions.tr (),
223+ textColor,
224+ ),
225+ ...List .generate (suggestionItems.length, (index) {
226+ return buildItem (
227+ suggestionItems[index],
228+ currentSuggestionItem,
229+ editorState,
230+ );
231+ }),
232+ buildSubTitle (LocaleKeys .document_toolbar_turnInto.tr (), textColor),
233+ ...List .generate (turnIntoItems.length, (index) {
234+ return buildItem (
235+ turnIntoItems[index],
236+ currentSuggestionItem,
237+ editorState,
238+ );
239+ }),
240+ ],
247241 );
248242 }
249243
250- Widget ? _buildRightIcon (String type, Node node, {int ? level}) {
251- if (type != node.type) {
252- return null ;
253- }
254-
255- if (node.type == HeadingBlockKeys .type) {
256- final nodeLevel = node.attributes[HeadingBlockKeys .level] ?? 1 ;
257- if (level != nodeLevel) {
258- return null ;
259- }
260- }
261-
262- if (node.type == ToggleListBlockKeys .type) {
263- final nodeLevel = node.attributes[ToggleListBlockKeys .level];
264- if (level != nodeLevel) {
265- return null ;
266- }
267- }
268-
269- return const FlowySvg (
270- FlowySvgs .workspace_selected_s,
271- blendMode: null ,
244+ Widget buildSubTitle (String text, Color color) {
245+ return Container (
246+ height: 32 ,
247+ margin: EdgeInsets .symmetric (horizontal: 8 ),
248+ child: Align (
249+ alignment: Alignment .centerLeft,
250+ child: FlowyText .semibold (
251+ text,
252+ color: color,
253+ figmaLineHeight: 16 ,
254+ ),
255+ ),
272256 );
273257 }
274258
275- FlowySvgData _buildLeftIcon (String type, {int ? level}) {
276- if (type == ParagraphBlockKeys .type) {
277- return FlowySvgs .type_text_m;
278- } else if (type == HeadingBlockKeys .type) {
279- switch (level) {
280- case 1 :
281- return FlowySvgs .type_h1_m;
282- case 2 :
283- return FlowySvgs .type_h2_m;
284- case 3 :
285- return FlowySvgs .type_h3_m;
286- default :
287- return FlowySvgs .type_text_m;
288- }
289- } else if (type == QuoteBlockKeys .type) {
290- return FlowySvgs .type_quote_m;
291- } else if (type == BulletedListBlockKeys .type) {
292- return FlowySvgs .type_bulleted_list_m;
293- } else if (type == NumberedListBlockKeys .type) {
294- return FlowySvgs .type_numbered_list_m;
295- } else if (type == TodoListBlockKeys .type) {
296- return FlowySvgs .type_todo_m;
297- } else if (type == CalloutBlockKeys .type) {
298- return FlowySvgs .type_callout_m;
299- } else if (type == SubPageBlockKeys .type) {
300- return FlowySvgs .icon_document_s;
301- } else if (type == ToggleListBlockKeys .type) {
302- switch (level) {
303- case 1 :
304- return FlowySvgs .type_toggle_h1_m;
305- case 2 :
306- return FlowySvgs .type_toggle_h2_m;
307- case 3 :
308- return FlowySvgs .type_toggle_h3_m;
309- default :
310- return FlowySvgs .type_toggle_list_m;
311- }
312- }
313-
314- throw UnimplementedError ('Unsupported block type: $type ' );
315- }
316-
317- String _buildLocalization (
318- String type, {
319- int ? level,
320- }) {
321- switch (type) {
322- case ParagraphBlockKeys .type:
323- return LocaleKeys .document_slashMenu_name_text.tr ();
324- case HeadingBlockKeys .type:
325- switch (level) {
326- case 1 :
327- return LocaleKeys .document_slashMenu_name_heading1.tr ();
328- case 2 :
329- return LocaleKeys .document_slashMenu_name_heading2.tr ();
330- case 3 :
331- return LocaleKeys .document_slashMenu_name_heading3.tr ();
332- default :
333- return LocaleKeys .document_slashMenu_name_text.tr ();
334- }
335- case QuoteBlockKeys .type:
336- return LocaleKeys .document_slashMenu_name_quote.tr ();
337- case BulletedListBlockKeys .type:
338- return LocaleKeys .editor_bulletedListShortForm.tr ();
339- case NumberedListBlockKeys .type:
340- return LocaleKeys .editor_numberedListShortForm.tr ();
341- case TodoListBlockKeys .type:
342- return LocaleKeys .editor_checkbox.tr ();
343- case CalloutBlockKeys .type:
344- return LocaleKeys .document_slashMenu_name_callout.tr ();
345- case SubPageBlockKeys .type:
346- return LocaleKeys .editor_page.tr ();
347- case ToggleListBlockKeys .type:
348- switch (level) {
349- case 1 :
350- return LocaleKeys .editor_toggleHeading1ShortForm.tr ();
351- case 2 :
352- return LocaleKeys .editor_toggleHeading2ShortForm.tr ();
353- case 3 :
354- return LocaleKeys .editor_toggleHeading3ShortForm.tr ();
355- default :
356- return LocaleKeys .editor_toggleListShortForm.tr ();
357- }
358- }
359-
360- throw UnimplementedError ('Unsupported block type: $type ' );
259+ Widget buildItem (
260+ SuggestionItem item,
261+ SuggestionItem currentSuggestionItem,
262+ EditorState state,
263+ ) {
264+ final isSelected = item.type == currentSuggestionItem.type;
265+ return SizedBox (
266+ height: 36 ,
267+ child: FlowyButton (
268+ leftIconSize: const Size .square (20 ),
269+ leftIcon: FlowySvg (item.svg),
270+ iconPadding: 12 ,
271+ text: FlowyText (
272+ item.title,
273+ fontWeight: FontWeight .w400,
274+ figmaLineHeight: 20 ,
275+ ),
276+ rightIcon: isSelected ? FlowySvg (FlowySvgs .toolbar_check_m) : null ,
277+ onTap: () => item.onTap.call (state, false ),
278+ ),
279+ );
361280 }
362281}
0 commit comments