🐛 Fixes on enter to send

This commit is contained in:
LittleSheep 2025-06-07 23:31:02 +08:00
parent 3dd7c8a5b2
commit b2a118bbd0
3 changed files with 80 additions and 51 deletions

View File

@ -3,7 +3,7 @@
archiveVersion = 1; archiveVersion = 1;
classes = { classes = {
}; };
objectVersion = 77; objectVersion = 54;
objects = { objects = {
/* Begin PBXBuildFile section */ /* Begin PBXBuildFile section */
@ -448,14 +448,10 @@
inputFileListPaths = ( inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-input-files.xcfilelist", "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-input-files.xcfilelist",
); );
inputPaths = (
);
name = "[CP] Copy Pods Resources"; name = "[CP] Copy Pods Resources";
outputFileListPaths = ( outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-output-files.xcfilelist", "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-output-files.xcfilelist",
); );
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh; shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n"; shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n";
@ -491,14 +487,10 @@
inputFileListPaths = ( inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist",
); );
inputPaths = (
);
name = "[CP] Embed Pods Frameworks"; name = "[CP] Embed Pods Frameworks";
outputFileListPaths = ( outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist",
); );
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh; shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";

View File

@ -309,7 +309,7 @@ class MessageRepository {
} }
Future<LocalChatMessage> retryMessage(String pendingMessageId) async { Future<LocalChatMessage> retryMessage(String pendingMessageId) async {
final message = pendingMessages[pendingMessageId]; final message = await getMessageById(pendingMessageId);
if (message == null) { if (message == null) {
throw Exception('Message not found'); throw Exception('Message not found');
} }

View File

@ -1,7 +1,9 @@
import 'dart:async'; import 'dart:async';
import 'dart:convert'; import 'dart:convert';
import 'dart:io';
import 'package:auto_route/auto_route.dart'; import 'package:auto_route/auto_route.dart';
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:flutter/services.dart';
import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:flutter_hooks/flutter_hooks.dart';
@ -319,6 +321,15 @@ class ChatRoomScreen extends HookConsumerWidget {
); );
} }
void sendTypingStatus() async {
final wsState = ref.read(websocketStateProvider.notifier);
wsState.sendMessage(
jsonEncode(
WebSocketPacket(type: 'messages.typing', data: {'chat_room_id': id}),
),
);
}
var isLoading = false; var isLoading = false;
// Add scroll listener for pagination // Add scroll listener for pagination
@ -414,6 +425,8 @@ class ChatRoomScreen extends HookConsumerWidget {
} }
} }
useEffect(() {});
final compactHeader = isWideScreen(context); final compactHeader = isWideScreen(context);
final listController = useMemoized(() => ListController(), []); final listController = useMemoized(() => ListController(), []);
@ -720,7 +733,7 @@ class ChatRoomScreen extends HookConsumerWidget {
} }
} }
class _ChatInput extends ConsumerWidget { class _ChatInput extends HookConsumerWidget {
final TextEditingController messageController; final TextEditingController messageController;
final SnChatRoom chatRoom; final SnChatRoom chatRoom;
final VoidCallback onSend; final VoidCallback onSend;
@ -751,46 +764,59 @@ class _ChatInput extends ConsumerWidget {
required this.onAttachmentsChanged, required this.onAttachmentsChanged,
}); });
void _handleKeyPress(BuildContext context, WidgetRef ref, RawKeyEvent event) {
if (event is! RawKeyDownEvent) return;
final isPaste = event.logicalKey == LogicalKeyboardKey.keyV;
final isModifierPressed = event.isMetaPressed || event.isControlPressed;
if (isPaste && isModifierPressed) {
_handlePaste();
return;
}
final enterToSend = ref.read(appSettingsNotifierProvider).enterToSend;
final isEnter = event.logicalKey == LogicalKeyboardKey.enter;
if (isEnter) {
if (enterToSend && !isModifierPressed) {
onSend();
} else if (!enterToSend && isModifierPressed) {
onSend();
}
}
}
Future<void> _handlePaste() async {
final clipboard = await Pasteboard.image;
if (clipboard == null) return;
onAttachmentsChanged([
...attachments,
UniversalFile(
data: XFile.fromData(clipboard, mimeType: "image/jpeg"),
type: UniversalFileType.image,
),
]);
}
@override @override
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
final inputFocusNode = useFocusNode();
final enterToSend = ref.watch(appSettingsNotifierProvider).enterToSend; final enterToSend = ref.watch(appSettingsNotifierProvider).enterToSend;
final isMobile = !kIsWeb && (Platform.isAndroid || Platform.isIOS);
void send() {
inputFocusNode.requestFocus();
onSend.call();
}
Future<void> handlePaste() async {
final clipboard = await Pasteboard.image;
if (clipboard == null) return;
onAttachmentsChanged([
...attachments,
UniversalFile(
data: XFile.fromData(clipboard, mimeType: "image/jpeg"),
type: UniversalFileType.image,
),
]);
}
void handleKeyPress(
BuildContext context,
WidgetRef ref,
RawKeyEvent event,
) {
if (event is! RawKeyDownEvent) return;
final isPaste = event.logicalKey == LogicalKeyboardKey.keyV;
final isModifierPressed = event.isMetaPressed || event.isControlPressed;
if (isPaste && isModifierPressed) {
handlePaste();
return;
}
final enterToSend = ref.read(appSettingsNotifierProvider).enterToSend;
final isEnter = event.logicalKey == LogicalKeyboardKey.enter;
if (isEnter) {
if (enterToSend && !isModifierPressed) {
send();
} else if (!enterToSend && isModifierPressed) {
send();
}
}
}
return Material( return Material(
elevation: 8, elevation: 8,
color: Theme.of(context).colorScheme.surface, color: Theme.of(context).colorScheme.surface,
@ -892,12 +918,23 @@ class _ChatInput extends ConsumerWidget {
Expanded( Expanded(
child: RawKeyboardListener( child: RawKeyboardListener(
focusNode: FocusNode(), focusNode: FocusNode(),
onKey: (event) => _handleKeyPress(context, ref, event), onKey: (event) => handleKeyPress(context, ref, event),
child: TextField( child: TextField(
focusNode: inputFocusNode,
controller: messageController, controller: messageController,
onSubmitted: enterToSend ? (_) => onSend() : null, onSubmitted:
(enterToSend && isMobile)
? (_) {
send();
}
: null,
keyboardType:
(enterToSend && isMobile)
? TextInputType.text
: TextInputType.multiline,
textInputAction: TextInputAction.send,
inputFormatters: [ inputFormatters: [
if (enterToSend) if (enterToSend && !isMobile)
TextInputFormatter.withFunction((oldValue, newValue) { TextInputFormatter.withFunction((oldValue, newValue) {
if (newValue.text.endsWith('\n')) { if (newValue.text.endsWith('\n')) {
return oldValue; return oldValue;
@ -932,7 +969,7 @@ class _ChatInput extends ConsumerWidget {
IconButton( IconButton(
icon: const Icon(Icons.send), icon: const Icon(Icons.send),
color: Theme.of(context).colorScheme.primary, color: Theme.of(context).colorScheme.primary,
onPressed: onSend, onPressed: send,
), ),
], ],
).padding(bottom: MediaQuery.of(context).padding.bottom), ).padding(bottom: MediaQuery.of(context).padding.bottom),