mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
fix: accept multi-key combination for customizing shortcuts & removes duplicates (#5414)
This commit is contained in:
parent
a8f136eda2
commit
8b6575d1ee
@ -56,7 +56,18 @@ final List<CommandShortcutEvent> commandShortcutEvents = [
|
|||||||
customPasteCommand,
|
customPasteCommand,
|
||||||
customCutCommand,
|
customCutCommand,
|
||||||
...customTextAlignCommands,
|
...customTextAlignCommands,
|
||||||
...standardCommandShortcutEvents,
|
|
||||||
|
// remove standard shortcuts for copy, cut, paste, todo
|
||||||
|
...standardCommandShortcutEvents
|
||||||
|
..removeWhere(
|
||||||
|
(shortcut) => [
|
||||||
|
copyCommand,
|
||||||
|
cutCommand,
|
||||||
|
pasteCommand,
|
||||||
|
toggleTodoListCommand,
|
||||||
|
].contains(shortcut),
|
||||||
|
),
|
||||||
|
|
||||||
emojiShortcutEvent,
|
emojiShortcutEvent,
|
||||||
];
|
];
|
||||||
|
|
||||||
@ -90,7 +101,6 @@ class AppFlowyEditorPage extends StatefulWidget {
|
|||||||
final String Function(Node)? placeholderText;
|
final String Function(Node)? placeholderText;
|
||||||
|
|
||||||
/// Used to provide an initial selection on Page-load
|
/// Used to provide an initial selection on Page-load
|
||||||
///
|
|
||||||
final Selection? initialSelection;
|
final Selection? initialSelection;
|
||||||
|
|
||||||
final bool useViewInfoBloc;
|
final bool useViewInfoBloc;
|
||||||
@ -111,15 +121,8 @@ class _AppFlowyEditorPageState extends State<AppFlowyEditorPage> {
|
|||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
late final List<CommandShortcutEvent> commandShortcutEvents = [
|
late final List<CommandShortcutEvent> cmdShortcutEvents = [
|
||||||
toggleToggleListCommand,
|
...commandShortcutEvents,
|
||||||
...localizedCodeBlockCommands,
|
|
||||||
customCopyCommand,
|
|
||||||
customPasteCommand,
|
|
||||||
customCutCommand,
|
|
||||||
...customTextAlignCommands,
|
|
||||||
...standardCommandShortcutEvents,
|
|
||||||
emojiShortcutEvent,
|
|
||||||
..._buildFindAndReplaceCommands(),
|
..._buildFindAndReplaceCommands(),
|
||||||
];
|
];
|
||||||
|
|
||||||
@ -309,7 +312,7 @@ class _AppFlowyEditorPageState extends State<AppFlowyEditorPage> {
|
|||||||
),
|
),
|
||||||
// customize the shortcuts
|
// customize the shortcuts
|
||||||
characterShortcutEvents: characterShortcutEvents,
|
characterShortcutEvents: characterShortcutEvents,
|
||||||
commandShortcutEvents: commandShortcutEvents,
|
commandShortcutEvents: cmdShortcutEvents,
|
||||||
// customize the context menu items
|
// customize the context menu items
|
||||||
contextMenuItems: customContextMenuItems,
|
contextMenuItems: customContextMenuItems,
|
||||||
// customize the header and footer.
|
// customize the header and footer.
|
||||||
@ -401,7 +404,7 @@ class _AppFlowyEditorPageState extends State<AppFlowyEditorPage> {
|
|||||||
final customizeShortcuts =
|
final customizeShortcuts =
|
||||||
await settingsShortcutService.getCustomizeShortcuts();
|
await settingsShortcutService.getCustomizeShortcuts();
|
||||||
await settingsShortcutService.updateCommandShortcuts(
|
await settingsShortcutService.updateCommandShortcuts(
|
||||||
commandShortcutEvents,
|
cmdShortcutEvents,
|
||||||
customizeShortcuts,
|
customizeShortcuts,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -32,6 +32,7 @@ class ShortcutsCubit extends Cubit<ShortcutsState> {
|
|||||||
error: '',
|
error: '',
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
final customizeShortcuts = await service.getCustomizeShortcuts();
|
final customizeShortcuts = await service.getCustomizeShortcuts();
|
||||||
await service.updateCommandShortcuts(
|
await service.updateCommandShortcuts(
|
||||||
@ -40,7 +41,9 @@ class ShortcutsCubit extends Cubit<ShortcutsState> {
|
|||||||
);
|
);
|
||||||
|
|
||||||
//sort the shortcuts
|
//sort the shortcuts
|
||||||
commandShortcutEvents.sort((a, b) => a.key.compareTo(b.key));
|
commandShortcutEvents.sort(
|
||||||
|
(a, b) => a.key.toLowerCase().compareTo(b.key.toLowerCase()),
|
||||||
|
);
|
||||||
|
|
||||||
emit(
|
emit(
|
||||||
state.copyWith(
|
state.copyWith(
|
||||||
@ -104,11 +107,11 @@ class ShortcutsCubit extends Cubit<ShortcutsState> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
///Checks if the new command is conflicting with other shortcut
|
/// Checks if the new command is conflicting with other shortcut
|
||||||
///We also check using the key, whether this command is a codeblock
|
/// We also check using the key, whether this command is a codeblock
|
||||||
///shortcut, if so we only check a conflict with other codeblock shortcut.
|
/// shortcut, if so we only check a conflict with other codeblock shortcut.
|
||||||
String getConflict(CommandShortcutEvent currentShortcut, String command) {
|
String getConflict(CommandShortcutEvent currentShortcut, String command) {
|
||||||
//check if currentShortcut is a codeblock shortcut.
|
// check if currentShortcut is a codeblock shortcut.
|
||||||
final isCodeBlockCommand = currentShortcut.isCodeBlockCommand;
|
final isCodeBlockCommand = currentShortcut.isCodeBlockCommand;
|
||||||
|
|
||||||
for (final e in state.commandShortcutEvents) {
|
for (final e in state.commandShortcutEvents) {
|
||||||
|
@ -84,7 +84,7 @@ class ShortcutsListView extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class ShortcutsListTile extends StatelessWidget {
|
class ShortcutsListTile extends StatefulWidget {
|
||||||
const ShortcutsListTile({
|
const ShortcutsListTile({
|
||||||
super.key,
|
super.key,
|
||||||
required this.shortcutEvent,
|
required this.shortcutEvent,
|
||||||
@ -92,6 +92,25 @@ class ShortcutsListTile extends StatelessWidget {
|
|||||||
|
|
||||||
final CommandShortcutEvent shortcutEvent;
|
final CommandShortcutEvent shortcutEvent;
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<ShortcutsListTile> createState() => _ShortcutsListTileState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _ShortcutsListTileState extends State<ShortcutsListTile> {
|
||||||
|
late final TextEditingController controller;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
controller = TextEditingController(text: widget.shortcutEvent.command);
|
||||||
|
super.initState();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
controller.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Column(
|
return Column(
|
||||||
@ -100,16 +119,16 @@ class ShortcutsListTile extends StatelessWidget {
|
|||||||
children: [
|
children: [
|
||||||
Expanded(
|
Expanded(
|
||||||
child: FlowyText.medium(
|
child: FlowyText.medium(
|
||||||
key: Key(shortcutEvent.key),
|
key: Key(widget.shortcutEvent.key),
|
||||||
shortcutEvent.description!.capitalize(),
|
widget.shortcutEvent.description!.capitalize(),
|
||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
FlowyTextButton(
|
FlowyTextButton(
|
||||||
shortcutEvent.command,
|
widget.shortcutEvent.command,
|
||||||
fontColor: AFThemeExtension.of(context).textColor,
|
fontColor: AFThemeExtension.of(context).textColor,
|
||||||
fillColor: Colors.transparent,
|
fillColor: Colors.transparent,
|
||||||
onPressed: () => showKeyListenerDialog(context),
|
onPressed: () => showKeyListenerDialog(context, controller),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@ -120,8 +139,10 @@ class ShortcutsListTile extends StatelessWidget {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void showKeyListenerDialog(BuildContext widgetContext) {
|
void showKeyListenerDialog(
|
||||||
final controller = TextEditingController(text: shortcutEvent.command);
|
BuildContext widgetContext,
|
||||||
|
TextEditingController controller,
|
||||||
|
) {
|
||||||
showDialog(
|
showDialog(
|
||||||
context: widgetContext,
|
context: widgetContext,
|
||||||
builder: (builderContext) {
|
builder: (builderContext) {
|
||||||
@ -131,9 +152,10 @@ class ShortcutsListTile extends StatelessWidget {
|
|||||||
content: KeyboardListener(
|
content: KeyboardListener(
|
||||||
focusNode: FocusNode(),
|
focusNode: FocusNode(),
|
||||||
onKeyEvent: (key) {
|
onKeyEvent: (key) {
|
||||||
|
if (key is! KeyDownEvent) return;
|
||||||
if (key.logicalKey == LogicalKeyboardKey.enter &&
|
if (key.logicalKey == LogicalKeyboardKey.enter &&
|
||||||
!HardwareKeyboard.instance.isShiftPressed) {
|
!HardwareKeyboard.instance.isShiftPressed) {
|
||||||
if (controller.text == shortcutEvent.command) {
|
if (controller.text == widget.shortcutEvent.command) {
|
||||||
_dismiss(builderContext);
|
_dismiss(builderContext);
|
||||||
}
|
}
|
||||||
if (formKey.currentState!.validate()) {
|
if (formKey.currentState!.validate()) {
|
||||||
@ -166,12 +188,12 @@ class ShortcutsListTile extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
).then((_) => controller.dispose());
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
String? _validateForConflicts(BuildContext context, String command) {
|
String? _validateForConflicts(BuildContext context, String command) {
|
||||||
final conflict = BlocProvider.of<ShortcutsCubit>(context).getConflict(
|
final conflict = BlocProvider.of<ShortcutsCubit>(context).getConflict(
|
||||||
shortcutEvent,
|
widget.shortcutEvent,
|
||||||
command,
|
command,
|
||||||
);
|
);
|
||||||
if (conflict.isEmpty) return null;
|
if (conflict.isEmpty) return null;
|
||||||
@ -182,7 +204,7 @@ class ShortcutsListTile extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void _updateKey(BuildContext context, String command) {
|
void _updateKey(BuildContext context, String command) {
|
||||||
shortcutEvent.updateCommand(command: command);
|
widget.shortcutEvent.updateCommand(command: command);
|
||||||
BlocProvider.of<ShortcutsCubit>(context).updateAllShortcuts();
|
BlocProvider.of<ShortcutsCubit>(context).updateAllShortcuts();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user