From 45f59ced3d6e969dc32533b876a48016e0fdce13 Mon Sep 17 00:00:00 2001 From: bigtaed-sys <234930311+bigtaed-sys@users.noreply.github.com> Date: Fri, 17 Jul 2026 19:44:33 +0300 Subject: [PATCH] =?UTF-8?q?fix(chat):=20=D0=BA=D1=80=D0=B0=D1=88=20=D0=BF?= =?UTF-8?q?=D1=80=D0=B8=20=D1=80=D0=B5=D0=B4=D0=B0=D0=BA=D1=82=D0=B8=D1=80?= =?UTF-8?q?=D0=BE=D0=B2=D0=B0=D0=BD=D0=B8=D0=B8=20=D1=81=D0=BE=D0=BE=D0=B1?= =?UTF-8?q?=D1=89=D0=B5=D0=BD=D0=B8=D1=8F=20=D1=81=20=D1=84=D0=BE=D1=82?= =?UTF-8?q?=D0=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit RichMessageController уничтожался сразу после закрытия шторки редактирования, пока TextField ещё жил во время анимации закрытия. Шторка выделена в _EditMessageSheet, который владеет контроллером и освобождает его в dispose после полного демонтажа роута. --- lib/frontend/screens/chats/chat_screen.dart | 152 +++++++++++++------- 1 file changed, 97 insertions(+), 55 deletions(-) diff --git a/lib/frontend/screens/chats/chat_screen.dart b/lib/frontend/screens/chats/chat_screen.dart index 7cb7f57..9e08e01 100644 --- a/lib/frontend/screens/chats/chat_screen.dart +++ b/lib/frontend/screens/chats/chat_screen.dart @@ -2811,75 +2811,28 @@ class _ChatScreenState extends State Future _startEditMessage(CachedMessage message) async { final cs = Theme.of(context).colorScheme; - final controller = RichMessageController(text: message.text ?? '') - ..setFormatRanges(message.formatRanges); - final saved = await showModalBottomSheet( + final content = await showModalBottomSheet< + ({String text, List> elements}) + >( context: context, isScrollControlled: true, backgroundColor: cs.surfaceContainerHigh, shape: const RoundedRectangleBorder( borderRadius: BorderRadius.vertical(top: Radius.circular(24)), ), - builder: (sheetContext) => Padding( - padding: EdgeInsets.only( - left: 20, - right: 20, - top: 20, - bottom: MediaQuery.viewInsetsOf(sheetContext).bottom + 20, - ), - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - Text( - 'Изменить сообщение', - style: TextStyle( - color: cs.onSurface, - fontSize: 18, - fontWeight: FontWeight.w600, - fontFamily: displayFontOf(context), - ), - ), - const SizedBox(height: 16), - TextField( - controller: controller, - autofocus: true, - minLines: 1, - maxLines: 6, - style: TextStyle(color: cs.onSurface), - contextMenuBuilder: (ctx, state) => - _formatContextMenu(controller, ctx, state), - decoration: InputDecoration( - hintText: 'Текст сообщения', - filled: true, - fillColor: cs.surfaceContainerHighest, - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(14), - borderSide: BorderSide.none, - ), - ), - ), - const SizedBox(height: 20), - FilledButton( - onPressed: () => Navigator.of(sheetContext).pop(true), - child: const Text('Сохранить'), - ), - ], - ), + builder: (sheetContext) => _EditMessageSheet( + text: message.text ?? '', + formatRanges: message.formatRanges, + contextMenuBuilder: _formatContextMenu, ), ); - if (saved != true || !mounted) { - controller.dispose(); - return; - } + if (content == null || !mounted) return; - final content = controller.buildContent(); final rawText = content.text; final newText = rawText.trim(); final elements = _trimmedElements(content.elements, rawText, newText); - controller.dispose(); final oldElements = serializeFormatElements( message.formatRanges.where((r) => composerFormats.contains(r.format)), @@ -7586,3 +7539,92 @@ class _ChatMessageListState extends State<_ChatMessageList> { ); } } + +class _EditMessageSheet extends StatefulWidget { + final String text; + final Iterable formatRanges; + final Widget Function( + RichMessageController controller, + BuildContext context, + EditableTextState editableState, + ) + contextMenuBuilder; + + const _EditMessageSheet({ + required this.text, + required this.formatRanges, + required this.contextMenuBuilder, + }); + + @override + State<_EditMessageSheet> createState() => _EditMessageSheetState(); +} + +class _EditMessageSheetState extends State<_EditMessageSheet> { + late final RichMessageController _controller; + + @override + void initState() { + super.initState(); + _controller = RichMessageController(text: widget.text) + ..setFormatRanges(widget.formatRanges); + } + + @override + void dispose() { + _controller.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + final cs = Theme.of(context).colorScheme; + return Padding( + padding: EdgeInsets.only( + left: 20, + right: 20, + top: 20, + bottom: MediaQuery.viewInsetsOf(context).bottom + 20, + ), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Text( + 'Изменить сообщение', + style: TextStyle( + color: cs.onSurface, + fontSize: 18, + fontWeight: FontWeight.w600, + fontFamily: displayFontOf(context), + ), + ), + const SizedBox(height: 16), + TextField( + controller: _controller, + autofocus: true, + minLines: 1, + maxLines: 6, + style: TextStyle(color: cs.onSurface), + contextMenuBuilder: (ctx, state) => + widget.contextMenuBuilder(_controller, ctx, state), + decoration: InputDecoration( + hintText: 'Текст сообщения', + filled: true, + fillColor: cs.surfaceContainerHighest, + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(14), + borderSide: BorderSide.none, + ), + ), + ), + const SizedBox(height: 20), + FilledButton( + onPressed: () => Navigator.of(context).pop(_controller.buildContent()), + child: const Text('Сохранить'), + ), + ], + ), + ); + } +}