Compare commits

..

2 Commits

Author SHA1 Message Date
3818328afe Cmd/Ctrl-V to paste image 2025-02-06 15:04:04 +08:00
11627e2455 💄 Clear tray number when click from it 2025-02-06 14:48:41 +08:00
4 changed files with 71 additions and 1 deletions

View File

@@ -369,6 +369,7 @@ class _AppSplashScreenState extends State<_AppSplashScreen> with TrayListener {
@override @override
void onTrayIconMouseDown() { void onTrayIconMouseDown() {
if (Platform.isWindows) { if (Platform.isWindows) {
context.read<NotificationProvider>().clearTray();
appWindow.show(); appWindow.show();
} else { } else {
trayManager.popUpContextMenu(); trayManager.popUpContextMenu();
@@ -380,6 +381,7 @@ class _AppSplashScreenState extends State<_AppSplashScreen> with TrayListener {
if (Platform.isWindows) { if (Platform.isWindows) {
trayManager.popUpContextMenu(); trayManager.popUpContextMenu();
} else { } else {
context.read<NotificationProvider>().clearTray();
appWindow.show(); appWindow.show();
} }
} }

View File

@@ -73,6 +73,7 @@ class NotificationProvider extends ChangeNotifier {
} }
int showingCount = 0; int showingCount = 0;
int showingTrayCount = 0;
List<SnNotification> notifications = List.empty(growable: true); List<SnNotification> notifications = List.empty(growable: true);
void listen() { void listen() {
@@ -81,6 +82,7 @@ class NotificationProvider extends ChangeNotifier {
final notification = SnNotification.fromJson(event.payload!); final notification = SnNotification.fromJson(event.payload!);
if (showingCount < 0) showingCount = 0; if (showingCount < 0) showingCount = 0;
showingCount++; showingCount++;
showingTrayCount++;
notifications.add(notification); notifications.add(notification);
Future.delayed(const Duration(seconds: 3), () { Future.delayed(const Duration(seconds: 3), () {
if (showingCount >= 0) showingCount--; if (showingCount >= 0) showingCount--;
@@ -94,6 +96,11 @@ class NotificationProvider extends ChangeNotifier {
}); });
} }
void clearTray() {
showingTrayCount = 0;
updateTray();
}
void updateTray() { void updateTray() {
if (kIsWeb || Platform.isAndroid || Platform.isIOS) return; if (kIsWeb || Platform.isAndroid || Platform.isIOS) return;
if (notifications.isEmpty) { if (notifications.isEmpty) {

View File

@@ -1,11 +1,17 @@
import 'dart:io';
import 'package:collection/collection.dart'; import 'package:collection/collection.dart';
import 'package:dropdown_button2/dropdown_button2.dart'; import 'package:dropdown_button2/dropdown_button2.dart';
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/gestures.dart'; import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:gap/gap.dart'; import 'package:gap/gap.dart';
import 'package:go_router/go_router.dart'; import 'package:go_router/go_router.dart';
import 'package:hotkey_manager/hotkey_manager.dart';
import 'package:material_symbols_icons/symbols.dart'; import 'package:material_symbols_icons/symbols.dart';
import 'package:pasteboard/pasteboard.dart';
import 'package:styled_widget/styled_widget.dart'; import 'package:styled_widget/styled_widget.dart';
import 'package:surface/controllers/post_write_controller.dart'; import 'package:surface/controllers/post_write_controller.dart';
import 'package:surface/providers/config.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:surface/widgets/dialog.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import '../../types/attachment.dart';
class PostEditorExtra { class PostEditorExtra {
final String? text; final String? text;
final String? title; final String? title;
@@ -94,15 +102,39 @@ class _PostEditorScreenState extends State<PostEditorScreen> {
); );
} }
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 @override
void dispose() { void dispose() {
_writeController.dispose(); _writeController.dispose();
if (!kIsWeb && !(Platform.isAndroid || Platform.isIOS)) hotKeyManager.unregister(_pasteHotKey);
super.dispose(); super.dispose();
} }
@override @override
void initState() { void initState() {
super.initState(); super.initState();
_registerHotKey();
if (!PostWriteController.kTitleMap.keys.contains(widget.mode)) { if (!PostWriteController.kTitleMap.keys.contains(widget.mode)) {
context.showErrorDialog('Unknown post type'); context.showErrorDialog('Unknown post type');
Navigator.pop(context); Navigator.pop(context);

View File

@@ -1,10 +1,15 @@
import 'dart:io';
import 'dart:math' show min; import 'dart:math' show min;
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:gap/gap.dart'; import 'package:gap/gap.dart';
import 'package:google_fonts/google_fonts.dart'; import 'package:google_fonts/google_fonts.dart';
import 'package:hotkey_manager/hotkey_manager.dart';
import 'package:material_symbols_icons/symbols.dart'; import 'package:material_symbols_icons/symbols.dart';
import 'package:pasteboard/pasteboard.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:styled_widget/styled_widget.dart'; import 'package:styled_widget/styled_widget.dart';
import 'package:surface/controllers/chat_message_controller.dart'; import 'package:surface/controllers/chat_message_controller.dart';
@@ -38,9 +43,30 @@ class ChatMessageInputState extends State<ChatMessageInput> {
final TextEditingController _contentController = TextEditingController(); final TextEditingController _contentController = TextEditingController();
final FocusNode _focusNode = FocusNode(); 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 @override
void initState() { void initState() {
super.initState(); super.initState();
_registerHotKey();
_contentController.addListener(() { _contentController.addListener(() {
if (_contentController.text.isNotEmpty) { if (_contentController.text.isNotEmpty) {
widget.controller.pingTypingStatus(); widget.controller.pingTypingStatus();
@@ -177,6 +203,7 @@ class ChatMessageInputState extends State<ChatMessageInput> {
void dispose() { void dispose() {
_contentController.dispose(); _contentController.dispose();
_focusNode.dispose(); _focusNode.dispose();
if (!kIsWeb && !(Platform.isAndroid || Platform.isIOS)) hotKeyManager.unregister(_pasteHotKey);
super.dispose(); super.dispose();
} }
@@ -420,7 +447,9 @@ class _StickerPicker extends StatelessWidget {
child: Tooltip( child: Tooltip(
richMessage: TextSpan( richMessage: TextSpan(
children: [ 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(), TextSpan(text: element.name).bold(),
], ],
), ),