import 'dart:async'; 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/talk/room/get_room_response.dart'; import '../../../api/marianumcloud/talk/share_files_to_chat.dart'; import '../../../api/marianumcloud/webdav/webdav_api.dart'; import '../../../routing/app_routes.dart'; import '../../../share_intent/pending_share.dart'; import '../../../share_intent/share_intent_listener.dart'; import '../../../state/app/infrastructure/loadable_state/view/loadable_state_consumer.dart'; import '../../../state/app/modules/chat_list/bloc/chat_list_bloc.dart'; import '../../../state/app/modules/chat_list/bloc/chat_list_state.dart'; import '../../../state/app/modules/settings/bloc/settings_cubit.dart'; import '../../../widget/info_dialog.dart'; import '../../../widget/placeholder_view.dart'; import '../files/files_upload_dialog.dart'; import '../talk/search_chat.dart'; import '../talk/widgets/chat_tile.dart'; class ShareChatPicker extends StatelessWidget { final PendingShare share; const ShareChatPicker({super.key, required this.share}); @override Widget build(BuildContext context) { final talkSettings = context.watch().val().talkSettings; return Scaffold( appBar: AppBar( title: const Text('Chat auswählen'), actions: [ Builder( builder: (ctx) => IconButton( icon: const Icon(Icons.search), onPressed: () { final rooms = ctx.read().state.data?.rooms; if (rooms == null) return; showSearch( context: ctx, delegate: SearchChat( rooms.data.where((r) => r.readOnly == 0).toList(), onTapOverride: (room) { Navigator.of(ctx).pop(); _onChatPicked(ctx, room); }, ), ); }, ), ), ], ), body: LoadableStateConsumer( child: (state, _) { final rooms = state.rooms; if (rooms == null) return const SizedBox.shrink(); final sorted = rooms .sortBy( lastActivity: true, favoritesToTop: talkSettings.sortFavoritesToTop, unreadToTop: talkSettings.sortUnreadToTop, ) // Hide chats the user can't write to (announcement channels, // archived rooms, …) — uploading there would only fail at the // share-API call with 403. .where((r) => r.readOnly == 0) .toList(); if (sorted.isEmpty) { return const PlaceholderView( icon: Icons.chat_bubble_outline, text: 'Keine schreibbaren Chats verfügbar', ); } return ListView.builder( padding: EdgeInsets.zero, itemCount: sorted.length, itemBuilder: (context, i) => ChatTile( data: sorted[i], disableContextActions: true, onTapOverride: (room) => _onChatPicked(context, room), ), ); }, ), ); } Future _onChatPicked( BuildContext context, GetRoomResponseObject room, ) async { if (share.hasFiles) { try { final webdav = await WebdavApi.webdav; await webdav.mkcol(PathUri.parse('/$talkShareFolder')); } catch (_) { // mkcol throws when the folder already exists; ignore. } if (!context.mounted) return; await pushScreen( context, withNavBar: false, screen: FilesUploadDialog( filePaths: share.filePaths, remotePath: talkShareFolder, uniqueNames: true, onUploadFinished: (uploaded) => _afterFilesUploaded(context, room, uploaded), ), ); return; } if (share.hasText) { _setDraftAndOpenChat(context, room); } } Future _afterFilesUploaded( BuildContext context, GetRoomResponseObject room, List uploadedRemotePaths, ) async { // Block the picker UI while the share-API roundtrips run, otherwise the // user can re-tap a chat and double-share the same files. unawaited( showDialog( context: context, barrierDismissible: false, builder: (_) => const PopScope( canPop: false, child: Center(child: CircularProgressIndicator()), ), ), ); try { await shareFilesToChat( token: room.token, remoteFilePaths: uploadedRemotePaths, ); } catch (e) { if (context.mounted) Navigator.of(context).pop(); if (context.mounted) { InfoDialog.show( context, 'Datei konnte nicht im Chat geteilt werden: $e', title: 'Fehler', copyable: true, ); } return; } if (!context.mounted) return; // The blocking dialog is popped together with the picker by // _setDraftAndOpenChat's popUntil(isFirst) below. _setDraftAndOpenChat(context, room); } void _setDraftAndOpenChat(BuildContext context, GetRoomResponseObject room) { if (share.hasText) { final settings = context.read(); settings.val(write: true).talkSettings.drafts[room.token] = share.text!; } ShareIntentListener.instance.clear(); Navigator.of(context).popUntil((route) => route.isFirst); AppRoutes.openChatByToken(context, room.token); } }