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:
parent
663f9d3423
commit
afc6473582
@ -15,14 +15,23 @@ void main() {
|
||||
TestWidgetsFlutterBinding.ensureInitialized();
|
||||
|
||||
group('toggle list in document', () {
|
||||
Finder findToggleListIcon({
|
||||
required bool isExpanded,
|
||||
}) {
|
||||
final turns = isExpanded ? 0.25 : 0.0;
|
||||
return find.byWidgetPredicate(
|
||||
(widget) => widget is AnimatedRotation && widget.turns == turns,
|
||||
);
|
||||
}
|
||||
|
||||
void expectToggleListOpened() {
|
||||
expect(find.byIcon(Icons.arrow_drop_down), findsOneWidget);
|
||||
expect(find.byIcon(Icons.arrow_right), findsNothing);
|
||||
expect(findToggleListIcon(isExpanded: true), findsOneWidget);
|
||||
expect(findToggleListIcon(isExpanded: false), findsNothing);
|
||||
}
|
||||
|
||||
void expectToggleListClosed() {
|
||||
expect(find.byIcon(Icons.arrow_drop_down), findsNothing);
|
||||
expect(find.byIcon(Icons.arrow_right), findsOneWidget);
|
||||
expect(findToggleListIcon(isExpanded: false), findsOneWidget);
|
||||
expect(findToggleListIcon(isExpanded: true), findsNothing);
|
||||
}
|
||||
|
||||
testWidgets('convert > to toggle list, and click the icon to close it',
|
||||
@ -63,7 +72,7 @@ void main() {
|
||||
expect(find.text(text2, findRichText: true), findsOneWidget);
|
||||
|
||||
// Click the toggle list icon to close it
|
||||
final toggleListIcon = find.byIcon(Icons.arrow_drop_down);
|
||||
final toggleListIcon = find.byIcon(Icons.arrow_right);
|
||||
await tester.tapButton(toggleListIcon);
|
||||
|
||||
// expect the toggle list to be closed
|
||||
@ -88,7 +97,7 @@ void main() {
|
||||
await tester.ime.insertText('> $text');
|
||||
|
||||
// Click the toggle list icon to close it
|
||||
final toggleListIcon = find.byIcon(Icons.arrow_drop_down);
|
||||
final toggleListIcon = find.byIcon(Icons.arrow_right);
|
||||
await tester.tapButton(toggleListIcon);
|
||||
|
||||
// Press the enter key
|
||||
@ -164,7 +173,7 @@ void main() {
|
||||
|
||||
// Press the enter key
|
||||
// Click the toggle list icon to close it
|
||||
final toggleListIcon = find.byIcon(Icons.arrow_drop_down);
|
||||
final toggleListIcon = find.byIcon(Icons.arrow_right);
|
||||
await tester.tapButton(toggleListIcon);
|
||||
|
||||
await tester.editor.updateSelection(
|
||||
|
@ -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,
|
||||
),
|
||||
),
|
||||
|
||||
|
@ -209,11 +209,8 @@ GoRoute _mobileEmojiPickerPageRoute() {
|
||||
parentNavigatorKey: AppGlobals.rootNavKey,
|
||||
path: MobileEmojiPickerScreen.routeName,
|
||||
pageBuilder: (context, state) {
|
||||
final id = state.uri.queryParameters[MobileEmojiPickerScreen.viewId]!;
|
||||
return MaterialPage(
|
||||
child: MobileEmojiPickerScreen(
|
||||
id: id,
|
||||
),
|
||||
return const MaterialPage(
|
||||
child: MobileEmojiPickerScreen(),
|
||||
);
|
||||
},
|
||||
);
|
||||
|
@ -361,10 +361,10 @@ class _SingleInnerViewItemState extends State<SingleInnerViewItem> {
|
||||
popupBuilder: (context) {
|
||||
isIconPickerOpened = true;
|
||||
return FlowyIconPicker(
|
||||
onSelected: (_, emoji) {
|
||||
onSelected: (result) {
|
||||
ViewBackendService.updateViewIcon(
|
||||
viewId: widget.view.id,
|
||||
viewIcon: emoji,
|
||||
viewIcon: result.emoji,
|
||||
);
|
||||
controller.close();
|
||||
},
|
||||
|
@ -54,8 +54,8 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
path: "."
|
||||
ref: a47fc6f
|
||||
resolved-ref: a47fc6fc712b06991f578ae2ab314cbe23034e96
|
||||
ref: "50117b6"
|
||||
resolved-ref: "50117b6900e4b239603ee48f6f3e7b7bc603c865"
|
||||
url: "https://github.com/AppFlowy-IO/appflowy-editor.git"
|
||||
source: git
|
||||
version: "1.5.2"
|
||||
|
@ -47,7 +47,8 @@ dependencies:
|
||||
appflowy_editor:
|
||||
git:
|
||||
url: https://github.com/AppFlowy-IO/appflowy-editor.git
|
||||
ref: a47fc6f
|
||||
ref: 50117b6
|
||||
|
||||
appflowy_popover:
|
||||
path: packages/appflowy_popover
|
||||
|
||||
|
@ -616,7 +616,12 @@
|
||||
"smartEditDisabled": "Connect OpenAI in Settings",
|
||||
"discardResponse": "Do you want to discard the AI responses?",
|
||||
"createInlineMathEquation": "Create equation",
|
||||
"toggleList": "Toggle List",
|
||||
"toggleList": "Toggle list",
|
||||
"quoteList":"Quote list",
|
||||
"numberedList":"Numbered list",
|
||||
"bulletedList":"Bulleted list",
|
||||
"todoList": "Todo List",
|
||||
"callout": "Callout",
|
||||
"cover": {
|
||||
"changeCover": "Change Cover",
|
||||
"colors": "Colors",
|
||||
|
Loading…
Reference in New Issue
Block a user