feat: move emoji_picker to appflowy editor plugin

This commit is contained in:
Lucas.Xu 2022-12-12 11:27:04 +08:00
commit a3252158ad
11 changed files with 55 additions and 214 deletions

View file

@ -59,6 +59,8 @@ class SimpleEditor extends StatelessWidget {
mathEquationMenuItem,
// Code Block
codeBlockMenuItem,
// Emoji
emojiMenuItem,
],
);
} else {

View file

@ -6,10 +6,14 @@
#include "generated_plugin_registrant.h"
#include <flowy_infra_ui/flowy_infra_u_i_plugin.h>
#include <rich_clipboard_linux/rich_clipboard_plugin.h>
#include <url_launcher_linux/url_launcher_plugin.h>
void fl_register_plugins(FlPluginRegistry* registry) {
g_autoptr(FlPluginRegistrar) flowy_infra_ui_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "FlowyInfraUIPlugin");
flowy_infra_u_i_plugin_register_with_registrar(flowy_infra_ui_registrar);
g_autoptr(FlPluginRegistrar) rich_clipboard_linux_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "RichClipboardPlugin");
rich_clipboard_plugin_register_with_registrar(rich_clipboard_linux_registrar);

View file

@ -3,6 +3,7 @@
#
list(APPEND FLUTTER_PLUGIN_LIST
flowy_infra_ui
rich_clipboard_linux
url_launcher_linux
)

View file

@ -5,12 +5,16 @@
import FlutterMacOS
import Foundation
import flowy_infra_ui
import path_provider_macos
import rich_clipboard_macos
import shared_preferences_macos
import url_launcher_macos
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
FlowyInfraUIPlugin.register(with: registry.registrar(forPlugin: "FlowyInfraUIPlugin"))
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
RichClipboardPlugin.register(with: registry.registrar(forPlugin: "RichClipboardPlugin"))
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin"))
}

View file

@ -1,32 +1,44 @@
PODS:
- flowy_infra_ui (0.0.1):
- FlutterMacOS
- FlutterMacOS (1.0.0)
- path_provider_macos (0.0.1):
- FlutterMacOS
- rich_clipboard_macos (0.0.1):
- FlutterMacOS
- shared_preferences_macos (0.0.1):
- FlutterMacOS
- url_launcher_macos (0.0.1):
- FlutterMacOS
DEPENDENCIES:
- flowy_infra_ui (from `Flutter/ephemeral/.symlinks/plugins/flowy_infra_ui/macos`)
- FlutterMacOS (from `Flutter/ephemeral`)
- path_provider_macos (from `Flutter/ephemeral/.symlinks/plugins/path_provider_macos/macos`)
- rich_clipboard_macos (from `Flutter/ephemeral/.symlinks/plugins/rich_clipboard_macos/macos`)
- shared_preferences_macos (from `Flutter/ephemeral/.symlinks/plugins/shared_preferences_macos/macos`)
- url_launcher_macos (from `Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos`)
EXTERNAL SOURCES:
flowy_infra_ui:
:path: Flutter/ephemeral/.symlinks/plugins/flowy_infra_ui/macos
FlutterMacOS:
:path: Flutter/ephemeral
path_provider_macos:
:path: Flutter/ephemeral/.symlinks/plugins/path_provider_macos/macos
rich_clipboard_macos:
:path: Flutter/ephemeral/.symlinks/plugins/rich_clipboard_macos/macos
shared_preferences_macos:
:path: Flutter/ephemeral/.symlinks/plugins/shared_preferences_macos/macos
url_launcher_macos:
:path: Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos
SPEC CHECKSUMS:
flowy_infra_ui: c34d49d615ed9fe552cd47f90d7850815a74e9e9
FlutterMacOS: 57701585bf7de1b3fc2bb61f6378d73bbdea8424
path_provider_macos: 3c0c3b4b0d4a76d2bf989a913c2de869c5641a19
rich_clipboard_macos: 43364b66b9dc69d203eb8dd6d758e2d12e02723c
shared_preferences_macos: a64dc611287ed6cbe28fd1297898db1336975727
url_launcher_macos: 597e05b8e514239626bcf4a850fcf9ef5c856ec3
PODFILE CHECKSUM: 6eac6b3292e5142cfc23bdeb71848a40ec51c14c

View file

@ -6,9 +6,12 @@
#include "generated_plugin_registrant.h"
#include <flowy_infra_ui/flowy_infra_u_i_plugin.h>
#include <url_launcher_windows/url_launcher_windows.h>
void RegisterPlugins(flutter::PluginRegistry* registry) {
FlowyInfraUIPluginRegisterWithRegistrar(
registry->GetRegistrarForPlugin("FlowyInfraUIPlugin"));
UrlLauncherWindowsRegisterWithRegistrar(
registry->GetRegistrarForPlugin("UrlLauncherWindows"));
}

View file

@ -3,6 +3,7 @@
#
list(APPEND FLUTTER_PLUGIN_LIST
flowy_infra_ui
url_launcher_windows
)

View file

@ -15,6 +15,7 @@ export 'src/editor_state.dart';
export 'src/core/transform/operation.dart';
export 'src/core/transform/transaction.dart';
export 'src/render/selection/selectable.dart';
export 'src/render/selection_menu/selection_menu_service.dart';
export 'src/service/editor_service.dart';
export 'src/service/render_plugin_service.dart';
export 'src/service/service.dart';

View file

@ -131,16 +131,6 @@ class AppFlowyEditorLocalizations {
);
}
/// `Emoji`
String get emoji {
return Intl.message(
'Emoji',
name: 'emoji',
desc: '',
args: [],
);
}
/// `Image`
String get image {
return Intl.message(

View file

@ -1,187 +0,0 @@
import 'package:appflowy_editor/src/core/document/node.dart';
import 'package:appflowy_editor/src/editor_state.dart';
import 'package:appflowy_editor/src/infra/flowy_svg.dart';
import 'package:appflowy_editor/src/render/selection_menu/selection_menu_service.dart';
import 'package:appflowy_editor/src/render/style/editor_style.dart';
import 'package:flutter/material.dart';
import 'package:app_flowy/workspace/presentation/widgets/emoji_picker/src/emoji_picker.dart';
import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:app_flowy/workspace/presentation/widgets/emoji_picker/src/models/emoji_model.dart';
import 'package:app_flowy/workspace/presentation/widgets/emoji_picker/src/config.dart';
import 'package:app_flowy/workspace/presentation/widgets/emoji_picker/src/emoji_button.dart';
import 'dart:collection';
import 'package:appflowy_popover/appflowy_popover.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter/foundation.dart' as foundation;
OverlayEntry? _imojiSelectionMenu;
EditorState? _editorState;
void showEmojiSelectionMenu(
EditorState editorState,
SelectionMenuService menuService,
BuildContext context,
) {
menuService.dismiss();
_imojiSelectionMenu?.remove();
_imojiSelectionMenu = OverlayEntry(builder: (context) {
return Positioned(
top: menuService.topLeft.dy,
left: menuService.topLeft.dx,
child: Material(
child: EmojiSelectionMenu(
editorState: editorState,
onSubmitted: (text) {
// insert emoji
editorState.insertEmojiNode(text);
},
onExit: () {
_dismissEmojiSelectionMenu();
//close emoji panel
},
),
),
);
});
Overlay.of(context)?.insert(_imojiSelectionMenu!);
editorState.service.selectionService.currentSelection
.addListener(_dismissEmojiSelectionMenu);
}
void _dismissEmojiSelectionMenu() {
_imojiSelectionMenu?.remove();
_imojiSelectionMenu = null;
_editorState?.service.selectionService.currentSelection
.removeListener(_dismissEmojiSelectionMenu);
_editorState = null;
}
class EmojiSelectionMenu extends StatefulWidget {
const EmojiSelectionMenu({
Key? key,
required this.onSubmitted,
required this.onExit,
this.editorState,
}) : super(key: key);
final void Function(Emoji Emoji) onSubmitted;
final void Function() onExit;
final EditorState? editorState;
@override
State<EmojiSelectionMenu> createState() => _EmojiSelectionMenuState();
}
class _EmojiSelectionMenuState extends State<EmojiSelectionMenu> {
EditorStyle? get style => widget.editorState?.editorStyle;
@override
void initState() {
HardwareKeyboard.instance.addHandler(_handleGlobalKeyEvent);
super.initState();
}
bool _handleGlobalKeyEvent(KeyEvent event) {
if (event.logicalKey == LogicalKeyboardKey.escape &&
event is KeyDownEvent) {
//triggers on esc
widget.onExit();
return true;
} else {
return false;
}
}
@override
void deactivate() {
HardwareKeyboard.instance.removeHandler(_handleGlobalKeyEvent);
super.deactivate();
}
@override
void dispose() {
super.dispose();
}
@override
Widget build(BuildContext context) {
return Container(
width: 300,
padding: const EdgeInsets.all(24.0),
decoration: BoxDecoration(
color: style?.selectionMenuBackgroundColor ?? Colors.white,
boxShadow: [
BoxShadow(
blurRadius: 5,
spreadRadius: 1,
color: Colors.black.withOpacity(0.1),
),
],
// borderRadius: BorderRadius.circular(6.0),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_buildHeader(context),
FlowyEmojiStyleButton(normalIcon: '', tooltipText: ''),
const SizedBox(height: 10.0),
_buildEmojiBox(context),
],
),
);
}
Widget _buildHeader(BuildContext context) {
return Text(
'Pick Emoji',
textAlign: TextAlign.left,
style: TextStyle(
fontSize: 14.0,
color: style?.selectionMenuItemTextColor ?? Colors.black,
fontWeight: FontWeight.w500,
),
);
}
Widget _buildEmojiBox(BuildContext context) {
return SizedBox(
height: 300,
child: EmojiPicker(
onEmojiSelected: (category, emoji) => widget.onSubmitted(emoji),
config: const Config(
columns: 8,
emojiSizeMax: 28,
bgColor: Color(0xffF2F2F2),
iconColor: Colors.grey,
iconColorSelected: Color(0xff333333),
indicatorColor: Color(0xff333333),
progressIndicatorColor: Color(0xff333333),
buttonMode: ButtonMode.CUPERTINO,
initCategory: Category.RECENT,
),
),
);
}
}
extension on EditorState {
void insertEmojiNode(Emoji emoji) {
final selectionService = service.selectionService;
final currentSelection = selectionService.currentSelection.value;
if (currentSelection == null) {
return;
}
final textNode = selectionService.currentSelectedNodes.first as TextNode;
final transaction = this.transaction;
transaction.insertText(textNode, currentSelection.endIndex, emoji.emoji);
apply(transaction);
}
}

View file

@ -1,15 +1,17 @@
import 'package:appflowy_editor/src/editor_state.dart';
import 'package:appflowy_editor/src/infra/flowy_svg.dart';
import 'package:appflowy_editor/src/l10n/l10n.dart';
import 'package:appflowy_editor/src/render/image/image_upload_widget.dart';
import 'package:appflowy_editor/src/render/selection_menu/selection_menu_widget.dart';
import 'package:appflowy_editor/src/service/default_text_operations/format_rich_text_style.dart';
import 'package:appflowy_editor/src/render/emoji/emoji_select_widget.dart';
import 'package:flutter/material.dart';
import 'package:appflowy_editor/src/core/legacy/built_in_attribute_keys.dart';
import '../../core/legacy/built_in_attribute_keys.dart';
import '../../editor_state.dart';
import '../../infra/flowy_svg.dart';
import '../../l10n/l10n.dart';
import '../../service/default_text_operations/format_rich_text_style.dart';
import '../image/image_upload_widget.dart';
import 'selection_menu_widget.dart';
abstract class SelectionMenuService {
Offset get topLeft;
Offset get offset;
Alignment get alignment;
void show();
void dismiss();
@ -27,6 +29,8 @@ class SelectionMenu implements SelectionMenuService {
OverlayEntry? _selectionMenuEntry;
bool _selectionUpdateByInner = false;
Offset? _topLeft;
Offset _offset = Offset.zero;
Alignment _alignment = Alignment.topLeft;
@override
void dismiss() {
@ -67,6 +71,7 @@ class SelectionMenu implements SelectionMenuService {
// show below defualt
var showBelow = true;
_alignment = Alignment.bottomLeft;
final bottomRight = selectionRects.first.bottomRight;
final topRight = selectionRects.first.topRight;
var offset = bottomRight + menuOffset;
@ -75,14 +80,16 @@ class SelectionMenu implements SelectionMenuService {
// show above
offset = topRight - menuOffset;
showBelow = false;
_alignment = Alignment.topRight;
}
_topLeft = offset;
_offset = Offset(offset.dx, showBelow ? offset.dy : MediaQuery.of(context).size.height - offset.dy);
_selectionMenuEntry = OverlayEntry(builder: (context) {
return Positioned(
top: showBelow ? offset.dy : null,
top: showBelow ? _offset.dy : null,
bottom:
showBelow ? null : MediaQuery.of(context).size.height - offset.dy,
showBelow ? null : _offset.dy,
left: offset.dx,
child: SelectionMenuWidget(
items: [
@ -114,6 +121,16 @@ class SelectionMenu implements SelectionMenuService {
return _topLeft ?? Offset.zero;
}
@override
Alignment get alignment {
return _alignment;
}
@override
Offset get offset {
return _offset;
}
void _onSelectionChange() {
// workaround: SelectionService has been released after hot reload.
final isSelectionDisposed =
@ -181,13 +198,6 @@ final List<SelectionMenuItem> _defaultSelectionMenuItems = [
keywords: ['image'],
handler: showImageUploadMenu,
),
SelectionMenuItem(
name: () => AppFlowyEditorLocalizations.current.emoji,
icon: (editorState, onSelected) =>
_selectionMenuIcon('image', editorState, onSelected),
keywords: ['emoji'],
handler: showEmojiSelectionMenu,
),
SelectionMenuItem(
name: () => AppFlowyEditorLocalizations.current.bulletedList,
icon: (editorState, onSelected) =>