import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:image_picker/image_picker.dart'; import 'package:island/models/file.dart'; import 'package:island/models/chat.dart'; import 'package:island/models/poll.dart'; import 'package:island/models/wallet.dart'; import 'package:island/pods/chat/chat_subscribe.dart'; import 'package:island/database/message.dart'; import 'package:island/pods/chat/messages_notifier.dart'; import 'package:island/widgets/chat/message_item.dart'; import 'package:pasteboard/pasteboard.dart'; class RoomInputManager { final TextEditingController messageController; final List attachments; final Map> attachmentProgress; final SnChatMessage? messageEditingTo; final SnChatMessage? messageReplyingTo; final SnChatMessage? messageForwardingTo; final SnPoll? selectedPoll; final SnWalletFund? selectedFund; final void Function(List) updateAttachments; final void Function(String, double?) updateAttachmentProgress; final void Function(SnChatMessage?) setEditingTo; final void Function(SnChatMessage?) setReplyingTo; final void Function(SnChatMessage?) setForwardingTo; final void Function(SnPoll?) setPoll; final void Function(SnWalletFund?) setFund; final void Function() clear; final void Function() clearAttachmentsOnly; final Future Function() handlePaste; final void Function(WidgetRef ref) sendMessage; final void Function(String action, LocalChatMessage message) onMessageAction; RoomInputManager({ required this.messageController, required this.attachments, required this.attachmentProgress, this.messageEditingTo, this.messageReplyingTo, this.messageForwardingTo, this.selectedPoll, this.selectedFund, required this.updateAttachments, required this.updateAttachmentProgress, required this.setEditingTo, required this.setReplyingTo, required this.setForwardingTo, required this.setPoll, required this.setFund, required this.clear, required this.clearAttachmentsOnly, required this.handlePaste, required this.sendMessage, required this.onMessageAction, }); } RoomInputManager useRoomInputManager(WidgetRef ref, String roomId) { final messageController = useTextEditingController(); final attachments = useState>([]); final attachmentProgress = useState>>({}); final messageEditingTo = useState(null); final messageReplyingTo = useState(null); final messageForwardingTo = useState(null); final selectedPoll = useState(null); final selectedFund = useState(null); final chatSubscribeNotifier = ref.read( chatSubscribeProvider(roomId).notifier, ); final messagesNotifier = ref.read(messagesProvider(roomId).notifier); void updateAttachments(List newAttachments) { attachments.value = newAttachments; } void updateAttachmentProgress(String messageId, double? progress) { attachmentProgress.value = { ...attachmentProgress.value, messageId: {0: progress}, }; } void setEditingTo(SnChatMessage? message) { messageEditingTo.value = message; if (message != null) { messageController.text = message.content ?? ''; attachments.value = message.attachments .map((e) => UniversalFile.fromAttachment(e)) .toList(); } } void setReplyingTo(SnChatMessage? message) { messageReplyingTo.value = message; } void setForwardingTo(SnChatMessage? message) { messageForwardingTo.value = message; } void setPoll(SnPoll? poll) { selectedPoll.value = poll; } void setFund(SnWalletFund? fund) { selectedFund.value = fund; } void clear() { messageController.clear(); messageEditingTo.value = null; messageReplyingTo.value = null; messageForwardingTo.value = null; selectedPoll.value = null; selectedFund.value = null; attachments.value = []; } void clearAttachmentsOnly() { messageController.clear(); attachments.value = []; } void onTextChange() { if (messageController.text.isNotEmpty) { chatSubscribeNotifier.sendTypingStatus(); } } useEffect(() { messageController.addListener(onTextChange); return () => messageController.removeListener(onTextChange); }, [messageController]); Future handlePaste() async { final image = await Pasteboard.image; if (image != null) { final newAttachments = [ ...attachments.value, UniversalFile( data: XFile.fromData(image, mimeType: "image/jpeg"), type: UniversalFileType.image, ), ]; attachments.value = newAttachments; } final textData = await Clipboard.getData(Clipboard.kTextPlain); if (textData != null && textData.text != null) { final text = messageController.text; final selection = messageController.selection; final start = selection.start >= 0 ? selection.start : text.length; final end = selection.end >= 0 ? selection.end : text.length; final newText = text.replaceRange(start, end, textData.text!); messageController.value = TextEditingValue( text: newText, selection: TextSelection.collapsed( offset: start + textData.text!.length, ), ); } } void onMessageAction(String action, LocalChatMessage message) { switch (action) { case MessageItemAction.delete: messagesNotifier.deleteMessage(message.id); case MessageItemAction.edit: setEditingTo(message.toRemoteMessage()); case MessageItemAction.forward: setForwardingTo(message.toRemoteMessage()); case MessageItemAction.reply: setReplyingTo(message.toRemoteMessage()); case MessageItemAction.resend: messagesNotifier.retryMessage(message.id); } } void sendMessage(WidgetRef ref) { if (messageController.text.trim().isNotEmpty || attachments.value.isNotEmpty || selectedPoll.value != null || selectedFund.value != null) { messagesNotifier.sendMessage( ref, messageController.text.trim(), attachments.value, poll: selectedPoll.value, fund: selectedFund.value, editingTo: messageEditingTo.value, forwardingTo: messageForwardingTo.value, replyingTo: messageReplyingTo.value, onProgress: (messageId, progress) { attachmentProgress.value = { ...attachmentProgress.value, messageId: progress, }; }, ); clear(); } } return RoomInputManager( messageController: messageController, attachments: attachments.value, attachmentProgress: attachmentProgress.value, messageEditingTo: messageEditingTo.value, messageReplyingTo: messageReplyingTo.value, messageForwardingTo: messageForwardingTo.value, selectedPoll: selectedPoll.value, selectedFund: selectedFund.value, updateAttachments: updateAttachments, updateAttachmentProgress: updateAttachmentProgress, setEditingTo: setEditingTo, setReplyingTo: setReplyingTo, setForwardingTo: setForwardingTo, setPoll: setPoll, setFund: setFund, clear: clear, clearAttachmentsOnly: clearAttachmentsOnly, handlePaste: handlePaste, sendMessage: sendMessage, onMessageAction: onMessageAction, ); }