import 'dart:io'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:nextcloud/nextcloud.dart'; import 'package:persistent_bottom_nav_bar_v2/persistent_bottom_nav_bar_v2.dart'; import '../../../../api/marianumcloud/files-sharing/fileSharingApi.dart'; import '../../../../api/marianumcloud/files-sharing/fileSharingApiParams.dart'; import '../../../../api/marianumcloud/talk/sendMessage/sendMessage.dart'; import '../../../../api/marianumcloud/talk/sendMessage/sendMessageParams.dart'; import '../../../../api/marianumcloud/webdav/webdavApi.dart'; import '../../../../state/app/modules/chat/bloc/chat_bloc.dart'; import '../../../../state/app/modules/settings/bloc/settings_cubit.dart'; import '../../../../widget/file_pick.dart'; import '../../../../widget/focus_behaviour.dart'; import '../../files/files_upload_dialog.dart'; import 'answer_reference.dart'; class ChatTextfield extends StatefulWidget { final String sendToToken; final String? selfId; const ChatTextfield(this.sendToToken, {this.selfId, super.key}); @override State createState() => _ChatTextfieldState(); } class _ChatTextfieldState extends State { late SettingsCubit settings; final TextEditingController _textBoxController = TextEditingController(); bool isLoading = false; void share(String shareFolder, List filePaths) { for (final element in filePaths) { final fileName = element.split(Platform.pathSeparator).last; FileSharingApi().share(FileSharingApiParams( shareType: 10, shareWith: widget.sendToToken, path: '$shareFolder/$fileName', )).then((_) { if (mounted) context.read().refresh(); }); } } Future mediaUpload(List? paths) async { if (paths == null) return; const shareFolder = 'MarianumMobile'; WebdavApi.webdav.then((webdav) => webdav.mkcol(PathUri.parse('/$shareFolder'))); if (!mounted) return; pushScreen( context, withNavBar: false, screen: FilesUploadDialog( filePaths: paths, remotePath: shareFolder, onUploadFinished: (uploaded) => share(shareFolder, uploaded), uniqueNames: true, ), ); } void _setDraft(String text) { final talkSettings = settings.val(write: true).talkSettings; if (text.isNotEmpty) { talkSettings.drafts[widget.sendToToken] = text; } else { talkSettings.drafts.removeWhere((key, _) => key == widget.sendToToken); } } void _setDraftReply(int? messageId) { final talkSettings = settings.val(write: true).talkSettings; if (messageId != null) { talkSettings.draftReplies[widget.sendToToken] = messageId; } else { talkSettings.draftReplies.removeWhere((key, _) => key == widget.sendToToken); } } @override void initState() { super.initState(); settings = context.read(); final draftReply = settings.val().talkSettings.draftReplies[widget.sendToToken]; if (draftReply != null) { context.read().setReferenceMessageId(draftReply); } } @override Widget build(BuildContext context) { _textBoxController.text = settings.val().talkSettings.drafts[widget.sendToToken] ?? ''; final chatBloc = context.watch(); final chatState = chatBloc.state.data; Widget replyBanner = const SizedBox.shrink(); if (chatState != null && chatState.referenceMessageId != null && chatState.chatResponse != null) { try { final referenceMessage = chatState.chatResponse!.sortByTimestamp().firstWhere( (e) => e.id == chatState.referenceMessageId, ); replyBanner = Row( children: [ Expanded( child: AnswerReference( context: context, referenceMessage: referenceMessage, selfId: widget.selfId, ), ), IconButton( onPressed: () { chatBloc.setReferenceMessageId(null); _setDraftReply(null); }, icon: const Icon(Icons.close_outlined), padding: const EdgeInsets.only(left: 0), ), ], ); } catch (_) {/* reference no longer in current chat data */} } return Stack(children: [ Align( alignment: Alignment.bottomLeft, child: Container( padding: const EdgeInsets.only(left: 10, bottom: 3, top: 3, right: 10), width: double.infinity, child: Column( children: [ replyBanner, Row(children: [ GestureDetector( onTap: () { showDialog(context: context, builder: (dialogCtx) => SimpleDialog(children: [ ListTile( leading: const Icon(Icons.file_open), title: const Text('Aus Dateien auswählen'), onTap: () { FilePick.documentPick().then(mediaUpload); Navigator.of(dialogCtx).pop(); }, ), Visibility( visible: !Platform.isIOS, child: ListTile( leading: const Icon(Icons.image), title: const Text('Aus Gallerie auswählen'), onTap: () { FilePick.multipleGalleryPick().then((value) { if (value != null) mediaUpload(value.map((e) => e.path).toList()); }); Navigator.of(dialogCtx).pop(); }, ), ), ])); }, child: Material( elevation: 5, shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(30)), child: Container( height: 30, width: 30, decoration: BoxDecoration( color: Theme.of(context).primaryColor, borderRadius: BorderRadius.circular(30), ), child: const Icon(Icons.attach_file_outlined, color: Colors.white, size: 20), ), ), ), const SizedBox(width: 15), Expanded( child: TextField( autocorrect: true, textCapitalization: TextCapitalization.sentences, controller: _textBoxController, maxLines: 7, minLines: 1, decoration: const InputDecoration( hintText: 'Nachricht schreiben...', border: InputBorder.none, ), onChanged: (text) { if (text.trim().toLowerCase() == 'marbot marbot marbot') { const newText = 'Roboter sind cool und so, aber Marbots sind besser!'; _textBoxController.text = newText; text = newText; } _setDraft(text); }, onTapOutside: (_) => FocusBehaviour.textFieldTapOutside(context), ), ), const SizedBox(width: 15), FloatingActionButton( mini: true, onPressed: () { if (_textBoxController.text.isEmpty || isLoading) return; setState(() => isLoading = true); SendMessage( widget.sendToToken, SendMessageParams( _textBoxController.text, replyTo: chatBloc.state.data?.referenceMessageId?.toString(), ), ).run().then((_) { if (!mounted) return; chatBloc.refresh(); setState(() => isLoading = false); _textBoxController.text = ''; _setDraft(''); chatBloc.setReferenceMessageId(null); _setDraftReply(null); }); }, backgroundColor: Theme.of(context).primaryColor, elevation: 5, child: isLoading ? Container( padding: const EdgeInsets.all(10), child: const CircularProgressIndicator(color: Colors.white, strokeWidth: 2), ) : const Icon(Icons.send, color: Colors.white, size: 18), ), ]), ], ), ), ), ]); } }