232 lines
7.5 KiB
Dart
232 lines
7.5 KiB
Dart
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<UniversalFile> attachments;
|
|
final Map<String, Map<int, double?>> attachmentProgress;
|
|
final SnChatMessage? messageEditingTo;
|
|
final SnChatMessage? messageReplyingTo;
|
|
final SnChatMessage? messageForwardingTo;
|
|
final SnPoll? selectedPoll;
|
|
final SnWalletFund? selectedFund;
|
|
final void Function(List<UniversalFile>) 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<void> 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<List<UniversalFile>>([]);
|
|
final attachmentProgress = useState<Map<String, Map<int, double?>>>({});
|
|
final messageEditingTo = useState<SnChatMessage?>(null);
|
|
final messageReplyingTo = useState<SnChatMessage?>(null);
|
|
final messageForwardingTo = useState<SnChatMessage?>(null);
|
|
final selectedPoll = useState<SnPoll?>(null);
|
|
final selectedFund = useState<SnWalletFund?>(null);
|
|
|
|
final chatSubscribeNotifier = ref.read(
|
|
chatSubscribeProvider(roomId).notifier,
|
|
);
|
|
final messagesNotifier = ref.read(messagesProvider(roomId).notifier);
|
|
|
|
void updateAttachments(List<UniversalFile> 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<void> 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,
|
|
);
|
|
}
|