mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
feat: adjust toggle list, callout, quote and divider on mobile (#3894)
* feat: adjust toggle list block * feat: show block actions when tapping divider * feat: add toggle list and callout to toolbar * feat: refactor the emoji picker button * fix: toggle list integration tests
This commit is contained in:
@ -1,22 +1,21 @@
|
||||
import 'package:appflowy/plugins/base/icon/icon_picker.dart';
|
||||
import 'package:appflowy/plugins/base/icon/icon_picker_page.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
|
||||
class MobileEmojiPickerScreen extends StatelessWidget {
|
||||
static const routeName = '/emoji_picker';
|
||||
static const viewId = 'id';
|
||||
|
||||
const MobileEmojiPickerScreen({
|
||||
super.key,
|
||||
required this.id,
|
||||
});
|
||||
|
||||
/// view id
|
||||
final String id;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return IconPickerPage(
|
||||
id: id,
|
||||
onSelected: (result) {
|
||||
context.pop<EmojiPickerResult>(result);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -12,13 +12,23 @@ enum FlowyIconType {
|
||||
custom;
|
||||
}
|
||||
|
||||
class EmojiPickerResult {
|
||||
const EmojiPickerResult(
|
||||
this.type,
|
||||
this.emoji,
|
||||
);
|
||||
|
||||
final FlowyIconType type;
|
||||
final String emoji;
|
||||
}
|
||||
|
||||
class FlowyIconPicker extends StatefulWidget {
|
||||
const FlowyIconPicker({
|
||||
super.key,
|
||||
required this.onSelected,
|
||||
});
|
||||
|
||||
final void Function(FlowyIconType type, String value) onSelected;
|
||||
final void Function(EmojiPickerResult result) onSelected;
|
||||
|
||||
@override
|
||||
State<FlowyIconPicker> createState() => _FlowyIconPickerState();
|
||||
@ -45,7 +55,12 @@ class _FlowyIconPickerState extends State<FlowyIconPicker>
|
||||
const Spacer(),
|
||||
_RemoveIconButton(
|
||||
onTap: () {
|
||||
widget.onSelected(FlowyIconType.icon, '');
|
||||
widget.onSelected(
|
||||
const EmojiPickerResult(
|
||||
FlowyIconType.icon,
|
||||
'',
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
@ -58,7 +73,12 @@ class _FlowyIconPickerState extends State<FlowyIconPicker>
|
||||
children: [
|
||||
FlowyEmojiPicker(
|
||||
onEmojiSelected: (_, emoji) {
|
||||
widget.onSelected(FlowyIconType.emoji, emoji);
|
||||
widget.onSelected(
|
||||
EmojiPickerResult(
|
||||
FlowyIconType.emoji,
|
||||
emoji,
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
|
@ -1,6 +1,5 @@
|
||||
import 'package:appflowy/mobile/presentation/base/app_bar_actions.dart';
|
||||
import 'package:appflowy/plugins/base/icon/icon_picker.dart';
|
||||
import 'package:appflowy/workspace/application/view/view_service.dart';
|
||||
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
@ -8,11 +7,10 @@ import 'package:go_router/go_router.dart';
|
||||
class IconPickerPage extends StatefulWidget {
|
||||
const IconPickerPage({
|
||||
super.key,
|
||||
required this.id,
|
||||
required this.onSelected,
|
||||
});
|
||||
|
||||
/// view id
|
||||
final String id;
|
||||
final void Function(EmojiPickerResult) onSelected;
|
||||
|
||||
@override
|
||||
State<IconPickerPage> createState() => _IconPickerPageState();
|
||||
@ -34,13 +32,7 @@ class _IconPickerPageState extends State<IconPickerPage> {
|
||||
),
|
||||
body: SafeArea(
|
||||
child: FlowyIconPicker(
|
||||
onSelected: (_, emoji) {
|
||||
ViewBackendService.updateViewIcon(
|
||||
viewId: widget.id,
|
||||
viewIcon: emoji,
|
||||
);
|
||||
context.pop();
|
||||
},
|
||||
onSelected: widget.onSelected,
|
||||
),
|
||||
),
|
||||
);
|
||||
|
@ -1,3 +1,4 @@
|
||||
import 'package:appflowy/plugins/document/presentation/editor_plugins/actions/mobile_block_action_buttons.dart';
|
||||
import 'package:appflowy/plugins/document/presentation/editor_plugins/image/custom_image_block_component.dart';
|
||||
import 'package:appflowy/plugins/document/presentation/editor_plugins/plugins.dart';
|
||||
import 'package:appflowy/plugins/document/presentation/editor_style.dart';
|
||||
@ -26,6 +27,9 @@ Map<String, BlockComponentBuilder> getEditorBuilderMap({
|
||||
|
||||
final configuration = BlockComponentConfiguration(
|
||||
padding: (_) => const EdgeInsets.symmetric(vertical: 5.0),
|
||||
indentPadding: (node, textDirection) => textDirection == TextDirection.ltr
|
||||
? const EdgeInsets.only(left: 26.0)
|
||||
: const EdgeInsets.only(right: 26.0),
|
||||
);
|
||||
|
||||
final customBlockComponentBuilderMap = {
|
||||
@ -119,6 +123,14 @@ Map<String, BlockComponentBuilder> getEditorBuilderMap({
|
||||
DividerBlockKeys.type: DividerBlockComponentBuilder(
|
||||
configuration: configuration,
|
||||
height: 28.0,
|
||||
wrapper: (context, node, child) {
|
||||
return MobileBlockActionButtons(
|
||||
showThreeDots: false,
|
||||
node: node,
|
||||
editorState: editorState,
|
||||
child: child,
|
||||
);
|
||||
},
|
||||
),
|
||||
MathEquationBlockKeys.type: MathEquationBlockComponentBuilder(
|
||||
configuration: configuration,
|
||||
@ -146,9 +158,7 @@ Map<String, BlockComponentBuilder> getEditorBuilderMap({
|
||||
),
|
||||
),
|
||||
errorBlockComponentBuilderKey: ErrorBlockComponentBuilder(
|
||||
configuration: configuration.copyWith(
|
||||
padding: (_) => const EdgeInsets.symmetric(vertical: 10),
|
||||
),
|
||||
configuration: configuration,
|
||||
),
|
||||
};
|
||||
|
||||
|
@ -286,10 +286,8 @@ class _AppFlowyEditorPageState extends State<AppFlowyEditorPage> {
|
||||
textDecorationMobileToolbarItem,
|
||||
buildTextAndBackgroundColorMobileToolbarItem(),
|
||||
headingMobileToolbarItem,
|
||||
todoListMobileToolbarItem,
|
||||
listMobileToolbarItem,
|
||||
customListMobileToolbarItem,
|
||||
linkMobileToolbarItem,
|
||||
quoteMobileToolbarItem,
|
||||
dividerMobileToolbarItem,
|
||||
imageMobileToolbarItem,
|
||||
mathEquationMobileToolbarItem,
|
||||
|
@ -21,6 +21,7 @@ class MobileBlockActionButtons extends StatelessWidget {
|
||||
const MobileBlockActionButtons({
|
||||
super.key,
|
||||
this.extendActionWidgets = const [],
|
||||
this.showThreeDots = true,
|
||||
required this.node,
|
||||
required this.editorState,
|
||||
required this.child,
|
||||
@ -30,6 +31,7 @@ class MobileBlockActionButtons extends StatelessWidget {
|
||||
final EditorState editorState;
|
||||
final List<Widget> extendActionWidgets;
|
||||
final Widget child;
|
||||
final bool showThreeDots;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@ -37,7 +39,15 @@ class MobileBlockActionButtons extends StatelessWidget {
|
||||
return child;
|
||||
}
|
||||
|
||||
const padding = 5.0;
|
||||
if (!showThreeDots) {
|
||||
return GestureDetector(
|
||||
behavior: HitTestBehavior.opaque,
|
||||
onTap: () => _showBottomSheet(context),
|
||||
child: child,
|
||||
);
|
||||
}
|
||||
|
||||
const padding = 10.0;
|
||||
return Stack(
|
||||
children: [
|
||||
child,
|
||||
|
@ -1,7 +1,11 @@
|
||||
import 'package:appflowy/plugins/base/emoji/emoji_picker_screen.dart';
|
||||
import 'package:appflowy/plugins/base/icon/icon_picker.dart';
|
||||
import 'package:appflowy/workspace/presentation/settings/widgets/emoji_picker/emoji_picker.dart';
|
||||
import 'package:appflowy_editor/appflowy_editor.dart';
|
||||
import 'package:appflowy_popover/appflowy_popover.dart';
|
||||
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
|
||||
class EmojiPickerButton extends StatelessWidget {
|
||||
EmojiPickerButton({
|
||||
@ -15,20 +19,43 @@ class EmojiPickerButton extends StatelessWidget {
|
||||
final String emoji;
|
||||
final double emojiSize;
|
||||
final Size emojiPickerSize;
|
||||
final void Function(String emoji, PopoverController controller) onSubmitted;
|
||||
final void Function(String emoji, PopoverController? controller) onSubmitted;
|
||||
final PopoverController popoverController = PopoverController();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return AppFlowyPopover(
|
||||
controller: popoverController,
|
||||
triggerActions: PopoverTriggerFlags.click,
|
||||
constraints: BoxConstraints.expand(
|
||||
width: emojiPickerSize.width,
|
||||
height: emojiPickerSize.height,
|
||||
),
|
||||
popupBuilder: (context) => _buildEmojiPicker(),
|
||||
child: FlowyTextButton(
|
||||
if (PlatformExtension.isDesktopOrWeb) {
|
||||
return AppFlowyPopover(
|
||||
controller: popoverController,
|
||||
triggerActions: PopoverTriggerFlags.click,
|
||||
constraints: BoxConstraints.expand(
|
||||
width: emojiPickerSize.width,
|
||||
height: emojiPickerSize.height,
|
||||
),
|
||||
popupBuilder: (context) => Container(
|
||||
width: emojiPickerSize.width,
|
||||
height: emojiPickerSize.height,
|
||||
padding: const EdgeInsets.all(4.0),
|
||||
child: EmojiSelectionMenu(
|
||||
onSubmitted: (emoji) => onSubmitted(emoji, popoverController),
|
||||
onExit: () {},
|
||||
),
|
||||
),
|
||||
child: FlowyTextButton(
|
||||
emoji,
|
||||
overflow: TextOverflow.visible,
|
||||
fontSize: emojiSize,
|
||||
padding: EdgeInsets.zero,
|
||||
constraints: const BoxConstraints(minWidth: 35.0),
|
||||
fillColor: Colors.transparent,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
onPressed: () {
|
||||
popoverController.show();
|
||||
},
|
||||
),
|
||||
);
|
||||
} else {
|
||||
return FlowyTextButton(
|
||||
emoji,
|
||||
overflow: TextOverflow.visible,
|
||||
fontSize: emojiSize,
|
||||
@ -36,22 +63,18 @@ class EmojiPickerButton extends StatelessWidget {
|
||||
constraints: const BoxConstraints(minWidth: 35.0),
|
||||
fillColor: Colors.transparent,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
onPressed: () {
|
||||
popoverController.show();
|
||||
onPressed: () async {
|
||||
final result = await context.push<EmojiPickerResult>(
|
||||
MobileEmojiPickerScreen.routeName,
|
||||
);
|
||||
if (result != null) {
|
||||
onSubmitted(
|
||||
result.emoji,
|
||||
null,
|
||||
);
|
||||
}
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildEmojiPicker() {
|
||||
return Container(
|
||||
width: emojiPickerSize.width,
|
||||
height: emojiPickerSize.height,
|
||||
padding: const EdgeInsets.all(4.0),
|
||||
child: EmojiSelectionMenu(
|
||||
onSubmitted: (emoji) => onSubmitted(emoji, popoverController),
|
||||
onExit: () {},
|
||||
),
|
||||
);
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -187,7 +187,7 @@ class _CalloutBlockComponentWidgetState
|
||||
emoji: emoji,
|
||||
onSubmitted: (emoji, controller) {
|
||||
setEmoji(emoji);
|
||||
controller.close();
|
||||
controller?.close();
|
||||
},
|
||||
),
|
||||
),
|
||||
|
@ -1,6 +1,7 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:appflowy/generated/locale_keys.g.dart';
|
||||
import 'package:appflowy/plugins/document/presentation/editor_plugins/actions/mobile_block_action_buttons.dart';
|
||||
import 'package:appflowy/plugins/document/presentation/editor_plugins/copy_and_paste/clipboard_service.dart';
|
||||
import 'package:appflowy/startup/startup.dart';
|
||||
import 'package:appflowy/workspace/presentation/home/toast.dart';
|
||||
@ -8,6 +9,7 @@ import 'package:appflowy_editor/appflowy_editor.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
|
||||
class ErrorBlockComponentBuilder extends BlockComponentBuilder {
|
||||
ErrorBlockComponentBuilder({
|
||||
@ -72,11 +74,15 @@ class _DividerBlockComponentWidgetState extends State<ErrorBlockComponentWidget>
|
||||
ClipboardServiceData(plainText: jsonEncode(node.toJson())),
|
||||
);
|
||||
},
|
||||
text: Container(
|
||||
height: 48,
|
||||
alignment: Alignment.center,
|
||||
child: FlowyText(
|
||||
LocaleKeys.document_errorBlock_theBlockIsNotSupported.tr(),
|
||||
text: SizedBox(
|
||||
height: 52,
|
||||
child: Row(
|
||||
children: [
|
||||
const HSpace(4),
|
||||
FlowyText(
|
||||
LocaleKeys.document_errorBlock_theBlockIsNotSupported.tr(),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -95,6 +101,14 @@ class _DividerBlockComponentWidgetState extends State<ErrorBlockComponentWidget>
|
||||
);
|
||||
}
|
||||
|
||||
if (PlatformExtension.isMobile) {
|
||||
child = MobileBlockActionButtons(
|
||||
node: node,
|
||||
editorState: context.read<EditorState>(),
|
||||
child: child,
|
||||
);
|
||||
}
|
||||
|
||||
return child;
|
||||
}
|
||||
}
|
||||
|
@ -6,7 +6,6 @@ import 'package:appflowy/plugins/base/emoji/emoji_picker_screen.dart';
|
||||
import 'package:appflowy/plugins/base/icon/icon_picker.dart';
|
||||
import 'package:appflowy/plugins/document/presentation/editor_plugins/header/emoji_icon_widget.dart';
|
||||
import 'package:appflowy/plugins/document/presentation/editor_style.dart';
|
||||
import 'package:appflowy/workspace/application/view/view_bloc.dart';
|
||||
import 'package:appflowy/workspace/application/view/view_listener.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-folder2/view.pb.dart';
|
||||
import 'package:appflowy_editor/appflowy_editor.dart';
|
||||
@ -16,7 +15,6 @@ import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
||||
import 'package:flowy_infra_ui/widget/rounded_button.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
import 'cover_editor.dart';
|
||||
|
||||
@ -303,15 +301,14 @@ class _DocumentHeaderToolbarState extends State<DocumentHeaderToolbar> {
|
||||
),
|
||||
onTap: PlatformExtension.isDesktop
|
||||
? null
|
||||
: () => context.push(
|
||||
Uri(
|
||||
path: MobileEmojiPickerScreen.routeName,
|
||||
queryParameters: {
|
||||
MobileEmojiPickerScreen.viewId:
|
||||
context.read<ViewBloc>().state.view.id,
|
||||
},
|
||||
).toString(),
|
||||
),
|
||||
: () async {
|
||||
final result = await context.push<EmojiPickerResult>(
|
||||
MobileEmojiPickerScreen.routeName,
|
||||
);
|
||||
if (result != null) {
|
||||
widget.onCoverChanged(icon: result.emoji);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
if (PlatformExtension.isDesktop) {
|
||||
@ -325,8 +322,8 @@ class _DocumentHeaderToolbarState extends State<DocumentHeaderToolbar> {
|
||||
popupBuilder: (BuildContext popoverContext) {
|
||||
isPopoverOpen = true;
|
||||
return FlowyIconPicker(
|
||||
onSelected: (type, value) {
|
||||
widget.onCoverChanged(icon: value);
|
||||
onSelected: (result) {
|
||||
widget.onCoverChanged(icon: result.emoji);
|
||||
_popoverController.close();
|
||||
},
|
||||
);
|
||||
@ -532,8 +529,8 @@ class _DocumentIconState extends State<DocumentIcon> {
|
||||
child: child,
|
||||
popupBuilder: (BuildContext popoverContext) {
|
||||
return FlowyIconPicker(
|
||||
onSelected: (type, value) {
|
||||
widget.onIconChanged(value);
|
||||
onSelected: (result) {
|
||||
widget.onIconChanged(result.emoji);
|
||||
_popoverController.close();
|
||||
},
|
||||
);
|
||||
@ -542,15 +539,14 @@ class _DocumentIconState extends State<DocumentIcon> {
|
||||
} else {
|
||||
child = GestureDetector(
|
||||
child: child,
|
||||
onTap: () => context.push(
|
||||
Uri(
|
||||
path: MobileEmojiPickerScreen.routeName,
|
||||
queryParameters: {
|
||||
MobileEmojiPickerScreen.viewId:
|
||||
context.read<ViewBloc>().state.view.id,
|
||||
},
|
||||
).toString(),
|
||||
),
|
||||
onTap: () async {
|
||||
final result = await context.push<EmojiPickerResult>(
|
||||
MobileEmojiPickerScreen.routeName,
|
||||
);
|
||||
if (result != null) {
|
||||
widget.onIconChanged(result.emoji);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,121 @@
|
||||
import 'package:appflowy/generated/flowy_svgs.g.dart';
|
||||
import 'package:appflowy/generated/locale_keys.g.dart';
|
||||
import 'package:appflowy/plugins/document/presentation/editor_plugins/plugins.dart';
|
||||
import 'package:appflowy_editor/appflowy_editor.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
final customListMobileToolbarItem = MobileToolbarItem.withMenu(
|
||||
itemIcon: const AFMobileIcon(afMobileIcons: AFMobileIcons.list),
|
||||
itemMenuBuilder: (editorState, selection, _) {
|
||||
return _MobileListMenu(
|
||||
editorState: editorState,
|
||||
selection: selection,
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
class _MobileListMenu extends StatelessWidget {
|
||||
const _MobileListMenu({
|
||||
required this.editorState,
|
||||
required this.selection,
|
||||
});
|
||||
|
||||
final Selection selection;
|
||||
final EditorState editorState;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return GridView.count(
|
||||
crossAxisCount: 2,
|
||||
mainAxisSpacing: 8,
|
||||
crossAxisSpacing: 8,
|
||||
childAspectRatio: 5,
|
||||
shrinkWrap: true,
|
||||
children: [
|
||||
// bulleted list, numbered list
|
||||
_buildListButton(
|
||||
context,
|
||||
BulletedListBlockKeys.type,
|
||||
const AFMobileIcon(afMobileIcons: AFMobileIcons.bulletedList),
|
||||
LocaleKeys.document_plugins_bulletedList.tr(),
|
||||
),
|
||||
_buildListButton(
|
||||
context,
|
||||
NumberedListBlockKeys.type,
|
||||
const AFMobileIcon(afMobileIcons: AFMobileIcons.numberedList),
|
||||
LocaleKeys.document_plugins_numberedList.tr(),
|
||||
),
|
||||
|
||||
// todo list, quote list
|
||||
_buildListButton(
|
||||
context,
|
||||
TodoListBlockKeys.type,
|
||||
const AFMobileIcon(afMobileIcons: AFMobileIcons.checkbox),
|
||||
LocaleKeys.document_plugins_todoList.tr(),
|
||||
),
|
||||
_buildListButton(
|
||||
context,
|
||||
QuoteBlockKeys.type,
|
||||
const AFMobileIcon(afMobileIcons: AFMobileIcons.quote),
|
||||
LocaleKeys.document_plugins_quoteList.tr(),
|
||||
),
|
||||
|
||||
// toggle list, callout
|
||||
_buildListButton(
|
||||
context,
|
||||
ToggleListBlockKeys.type,
|
||||
const FlowySvg(
|
||||
FlowySvgs.toggle_list_s,
|
||||
size: Size.square(24),
|
||||
),
|
||||
LocaleKeys.document_plugins_toggleList.tr(),
|
||||
),
|
||||
_buildListButton(
|
||||
context,
|
||||
CalloutBlockKeys.type,
|
||||
const Icon(Icons.note_rounded),
|
||||
LocaleKeys.document_plugins_callout.tr(),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildListButton(
|
||||
BuildContext context,
|
||||
String listBlockType,
|
||||
Widget icon,
|
||||
String label,
|
||||
) {
|
||||
final node = editorState.getNodeAtPath(selection.start.path);
|
||||
final type = node?.type;
|
||||
if (node == null || type == null) {
|
||||
const SizedBox.shrink();
|
||||
}
|
||||
final isSelected = type == listBlockType;
|
||||
return MobileToolbarItemMenuBtn(
|
||||
icon: icon,
|
||||
label: FlowyText(label),
|
||||
isSelected: isSelected,
|
||||
onPressed: () async {
|
||||
await editorState.formatNode(
|
||||
selection,
|
||||
(node) {
|
||||
final attributes = {
|
||||
ParagraphBlockKeys.delta: (node.delta ?? Delta()).toJson(),
|
||||
if (listBlockType == TodoListBlockKeys.type)
|
||||
TodoListBlockKeys.checked: false,
|
||||
if (listBlockType == CalloutBlockKeys.type)
|
||||
CalloutBlockKeys.icon: '📌',
|
||||
};
|
||||
return node.copyWith(
|
||||
type: isSelected ? ParagraphBlockKeys.type : listBlockType,
|
||||
attributes: attributes,
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
@ -25,7 +25,8 @@ export 'image/mobile_image_toolbar_item.dart';
|
||||
export 'inline_math_equation/inline_math_equation.dart';
|
||||
export 'inline_math_equation/inline_math_equation_toolbar_item.dart';
|
||||
export 'math_equation/math_equation_block_component.dart';
|
||||
export 'math_equation/mobile_math_eqaution_toolbar_item.dart';
|
||||
export 'math_equation/mobile_math_equation_toolbar_item.dart';
|
||||
export 'mobile_toolbar_item/list_mobile_toolbar_item.dart';
|
||||
export 'openai/widgets/auto_completion_node_widget.dart';
|
||||
export 'openai/widgets/smart_edit_node_widget.dart';
|
||||
export 'openai/widgets/smart_edit_toolbar_item.dart';
|
||||
|
@ -166,13 +166,17 @@ class _ToggleListBlockComponentWidgetState
|
||||
Container(
|
||||
constraints: const BoxConstraints(minWidth: 26, minHeight: 22),
|
||||
padding: const EdgeInsets.only(right: 4.0),
|
||||
child: FlowyIconButton(
|
||||
width: 18.0,
|
||||
icon: Icon(
|
||||
collapsed ? Icons.arrow_right : Icons.arrow_drop_down,
|
||||
size: 18.0,
|
||||
child: AnimatedRotation(
|
||||
turns: collapsed ? 0.0 : 0.25,
|
||||
duration: const Duration(milliseconds: 200),
|
||||
child: FlowyIconButton(
|
||||
width: 18.0,
|
||||
icon: const Icon(
|
||||
Icons.arrow_right,
|
||||
size: 18.0,
|
||||
),
|
||||
onPressed: onCollapsed,
|
||||
),
|
||||
onPressed: onCollapsed,
|
||||
),
|
||||
),
|
||||
|
||||
|
Reference in New Issue
Block a user