diff --git a/lib/screens/post/post_editor.dart b/lib/screens/post/post_editor.dart index 8794750..10ba720 100644 --- a/lib/screens/post/post_editor.dart +++ b/lib/screens/post/post_editor.dart @@ -1,11 +1,17 @@ +import 'dart:io'; + import 'package:collection/collection.dart'; import 'package:dropdown_button2/dropdown_button2.dart'; import 'package:easy_localization/easy_localization.dart'; +import 'package:flutter/foundation.dart'; import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; import 'package:gap/gap.dart'; import 'package:go_router/go_router.dart'; +import 'package:hotkey_manager/hotkey_manager.dart'; import 'package:material_symbols_icons/symbols.dart'; +import 'package:pasteboard/pasteboard.dart'; import 'package:styled_widget/styled_widget.dart'; import 'package:surface/controllers/post_write_controller.dart'; import 'package:surface/providers/config.dart'; @@ -20,6 +26,8 @@ import 'package:surface/widgets/post/post_meta_editor.dart'; import 'package:surface/widgets/dialog.dart'; import 'package:provider/provider.dart'; +import '../../types/attachment.dart'; + class PostEditorExtra { final String? text; final String? title; @@ -94,15 +102,39 @@ class _PostEditorScreenState extends State { ); } + final HotKey _pasteHotKey = HotKey( + key: PhysicalKeyboardKey.keyV, + modifiers: [Platform.isMacOS ? HotKeyModifier.meta : HotKeyModifier.control], + scope: HotKeyScope.inapp, + ); + + void _registerHotKey() { + if (kIsWeb || Platform.isAndroid || Platform.isIOS) return; + hotKeyManager.register(_pasteHotKey, keyDownHandler: (_) async { + final imageBytes = await Pasteboard.image; + if (imageBytes == null) return; + _writeController.addAttachments([ + PostWriteMedia.fromBytes( + imageBytes, + 'attachmentPastedImage'.tr(), + SnMediaType.image, + ), + ]); + setState(() {}); + }); + } + @override void dispose() { _writeController.dispose(); + if (!kIsWeb && !(Platform.isAndroid || Platform.isIOS)) hotKeyManager.unregister(_pasteHotKey); super.dispose(); } @override void initState() { super.initState(); + _registerHotKey(); if (!PostWriteController.kTitleMap.keys.contains(widget.mode)) { context.showErrorDialog('Unknown post type'); Navigator.pop(context); diff --git a/lib/widgets/chat/chat_message_input.dart b/lib/widgets/chat/chat_message_input.dart index 8da6692..d03932f 100644 --- a/lib/widgets/chat/chat_message_input.dart +++ b/lib/widgets/chat/chat_message_input.dart @@ -1,10 +1,15 @@ +import 'dart:io'; import 'dart:math' show min; import 'package:easy_localization/easy_localization.dart'; +import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; import 'package:gap/gap.dart'; import 'package:google_fonts/google_fonts.dart'; +import 'package:hotkey_manager/hotkey_manager.dart'; import 'package:material_symbols_icons/symbols.dart'; +import 'package:pasteboard/pasteboard.dart'; import 'package:provider/provider.dart'; import 'package:styled_widget/styled_widget.dart'; import 'package:surface/controllers/chat_message_controller.dart'; @@ -38,9 +43,30 @@ class ChatMessageInputState extends State { final TextEditingController _contentController = TextEditingController(); final FocusNode _focusNode = FocusNode(); + final HotKey _pasteHotKey = HotKey( + key: PhysicalKeyboardKey.keyV, + modifiers: [Platform.isMacOS ? HotKeyModifier.meta : HotKeyModifier.control], + scope: HotKeyScope.inapp, + ); + + void _registerHotKey() { + if (kIsWeb || Platform.isAndroid || Platform.isIOS) return; + hotKeyManager.register(_pasteHotKey, keyDownHandler: (_) async { + final imageBytes = await Pasteboard.image; + if (imageBytes == null) return; + _attachments.add(PostWriteMedia.fromBytes( + imageBytes, + 'attachmentPastedImage'.tr(), + SnMediaType.image, + )); + setState(() {}); + }); + } + @override void initState() { super.initState(); + _registerHotKey(); _contentController.addListener(() { if (_contentController.text.isNotEmpty) { widget.controller.pingTypingStatus(); @@ -177,6 +203,7 @@ class ChatMessageInputState extends State { void dispose() { _contentController.dispose(); _focusNode.dispose(); + if (!kIsWeb && !(Platform.isAndroid || Platform.isIOS)) hotKeyManager.unregister(_pasteHotKey); super.dispose(); } @@ -420,7 +447,9 @@ class _StickerPicker extends StatelessWidget { child: Tooltip( richMessage: TextSpan( children: [ - TextSpan(text: ':${element.pack.prefix}${element.alias}:\n', style: GoogleFonts.robotoMono()), + TextSpan( + text: ':${element.pack.prefix}${element.alias}:\n', + style: GoogleFonts.robotoMono()), TextSpan(text: element.name).bold(), ], ),