From c686540306ce96252a7c2a01b9f7daa0d80d2c43 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Tue, 3 Mar 2020 18:01:55 +0100 Subject: [PATCH] fix edit message --- example/ios/Podfile.lock | 28 +++++ lib/src/message_input.dart | 236 ++++++++++++++++++++---------------- lib/src/message_widget.dart | 130 ++++++++++---------- 3 files changed, 226 insertions(+), 168 deletions(-) diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index 134db5c4..e848b8ff 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -1,10 +1,20 @@ PODS: + - file_picker (0.0.1): + - Flutter - Flutter (1.0.0) + - flutter_plugin_android_lifecycle (0.0.1): + - Flutter - FMDB (2.7.5): - FMDB/standard (= 2.7.5) - FMDB/standard (2.7.5) + - image_picker (0.0.1): + - Flutter + - keyboard_visibility (0.5.0): + - Flutter + - Reachability - path_provider (0.0.1): - Flutter + - Reachability (3.2) - screen (0.0.1): - Flutter - sqflite (0.0.1): @@ -22,7 +32,11 @@ PODS: - Flutter DEPENDENCIES: + - file_picker (from `.symlinks/plugins/file_picker/ios`) - Flutter (from `Flutter`) + - flutter_plugin_android_lifecycle (from `.symlinks/plugins/flutter_plugin_android_lifecycle/ios`) + - image_picker (from `.symlinks/plugins/image_picker/ios`) + - keyboard_visibility (from `.symlinks/plugins/keyboard_visibility/ios`) - path_provider (from `.symlinks/plugins/path_provider/ios`) - screen (from `.symlinks/plugins/screen/ios`) - sqflite (from `.symlinks/plugins/sqflite/ios`) @@ -35,10 +49,19 @@ DEPENDENCIES: SPEC REPOS: trunk: - FMDB + - Reachability EXTERNAL SOURCES: + file_picker: + :path: ".symlinks/plugins/file_picker/ios" Flutter: :path: Flutter + flutter_plugin_android_lifecycle: + :path: ".symlinks/plugins/flutter_plugin_android_lifecycle/ios" + image_picker: + :path: ".symlinks/plugins/image_picker/ios" + keyboard_visibility: + :path: ".symlinks/plugins/keyboard_visibility/ios" path_provider: :path: ".symlinks/plugins/path_provider/ios" screen: @@ -57,9 +80,14 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/video_player_web/ios" SPEC CHECKSUMS: + file_picker: 408623be2125b79a4539cf703be3d4b3abe5e245 Flutter: 0e3d915762c693b495b44d77113d4970485de6ec + flutter_plugin_android_lifecycle: 47de533a02850f070f5696a623995e93eddcdb9b FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a + image_picker: e3eacd46b94694dde7cf2705955cece853aa1a8f + keyboard_visibility: 96a24de806fe6823c3ad956c01ba2ec6d056616f path_provider: fb74bd0465e96b594bb3b5088ee4a4e7bb1f2a9d + Reachability: 33e18b67625424e47b6cde6d202dce689ad7af96 screen: abd91ca7bf3426e1cc3646d27e9b2358d6bf07b0 sqflite: 4001a31ff81d210346b500c55b17f4d6c7589dd0 url_launcher: a1c0cc845906122c4784c542523d8cacbded5626 diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 90d4306d..79c9f55f 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -76,15 +76,12 @@ class MessageInput extends StatefulWidget { } class _MessageInputState extends State { + final List<_SendingAttachment> _attachments = []; + final _focusNode = FocusNode(); + TextEditingController _textController; bool _messageIsPresent = false; bool _typingStarted = false; - final List<_SendingAttachment> _attachments = []; - - final _focusNode = FocusNode(); - - bool _modalOn = false; - OverlayEntry _commandsOverlay; @override @@ -95,96 +92,12 @@ class _MessageInputState extends State { child: Stack( overflow: Overflow.visible, children: [ - Positioned.fill( - child: Container( - width: MediaQuery.of(context).size.width, - padding: EdgeInsets.all(2), - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(10.0), - gradient: _getGradient(context), - ), - child: Container( - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(10.0), - ), - child: Container( - decoration: BoxDecoration( - color: StreamChatTheme.of(context) - .channelTheme - .inputBackground, - borderRadius: BorderRadius.circular(10.0), - border: Border.all( - color: _typingStarted - ? Colors.transparent - : Colors.black.withOpacity(.2)), - ), - ), - ), - ), - ), + _buildBorder(context), Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ _buildAttachments(), - Flex( - direction: Axis.horizontal, - children: [ - _buildAttachmentButton(), - Expanded( - child: TextField( - minLines: null, - maxLines: null, - onSubmitted: (_) { - _sendMessage(context); - }, - controller: _textController, - focusNode: _focusNode, - onChanged: (s) { - StreamChannel.of(context).channel.keyStroke(); - setState(() { - _messageIsPresent = s.trim().isNotEmpty; - }); - - if (s.startsWith('/')) { - _modalOn = true; - - _commandsOverlay?.remove(); - _commandsOverlay = null; - _commandsOverlay = _buildOverlayEntry(); - Overlay.of(context).insert(_commandsOverlay); - } else if (!s.startsWith('/') && _modalOn) { - _modalOn = false; - _commandsOverlay?.remove(); - _commandsOverlay = null; - } - }, - onTap: () { - setState(() { - _typingStarted = true; - }); - }, - style: Theme.of(context).textTheme.body1, - autofocus: false, - decoration: InputDecoration( - hintText: 'Write a message', - prefixText: ' ', - border: InputBorder.none, - ), - ), - ), - AnimatedCrossFade( - crossFadeState: - (_messageIsPresent || _attachments.isNotEmpty) - ? CrossFadeState.showFirst - : CrossFadeState.showSecond, - firstChild: _buildSendButton(context), - secondChild: SizedBox(), - duration: Duration(milliseconds: 300), - alignment: Alignment.center, - ), - ], - ), + _buildTextField(context), ], ), ], @@ -193,13 +106,110 @@ class _MessageInputState extends State { ); } + Flex _buildTextField(BuildContext context) { + return Flex( + direction: Axis.horizontal, + children: [ + _buildAttachmentButton(), + _buildTextInput(context), + _animateSendButton(context), + ], + ); + } + + AnimatedCrossFade _animateSendButton(BuildContext context) { + print( + '_messageIsPresent || _attachments.isNotEmpty: ${_messageIsPresent || _attachments.isNotEmpty}'); + print('_attachments.isNotEmpty: ${_attachments.isNotEmpty}'); + print('_messageIsPresent: ${_messageIsPresent}'); + return AnimatedCrossFade( + crossFadeState: (_messageIsPresent || _attachments.isNotEmpty) + ? CrossFadeState.showFirst + : CrossFadeState.showSecond, + firstChild: _buildSendButton(context), + secondChild: SizedBox(), + duration: Duration(milliseconds: 300), + alignment: Alignment.center, + ); + } + + Expanded _buildTextInput(BuildContext context) { + return Expanded( + child: TextField( + minLines: null, + maxLines: null, + onSubmitted: (_) { + _sendMessage(context); + }, + controller: _textController, + focusNode: _focusNode, + onChanged: (s) { + StreamChannel.of(context).channel.keyStroke(); + + setState(() { + _messageIsPresent = s.trim().isNotEmpty; + }); + + _commandsOverlay?.remove(); + _commandsOverlay = null; + + if (s.startsWith('/')) { + _commandsOverlay = _buildOverlayEntry(); + Overlay.of(context).insert(_commandsOverlay); + } + }, + onTap: () { + setState(() { + _typingStarted = true; + }); + }, + style: Theme.of(context).textTheme.body1, + autofocus: false, + decoration: InputDecoration( + hintText: 'Write a message', + prefixText: ' ', + border: InputBorder.none, + ), + ), + ); + } + + Positioned _buildBorder(BuildContext context) { + return Positioned.fill( + child: Container( + width: MediaQuery.of(context).size.width, + padding: EdgeInsets.all(2), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(10.0), + gradient: _getGradient(context), + ), + child: Container( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(10.0), + ), + child: Container( + decoration: BoxDecoration( + color: StreamChatTheme.of(context).channelTheme.inputBackground, + borderRadius: BorderRadius.circular(10.0), + border: Border.all( + color: _typingStarted + ? Colors.transparent + : Colors.black.withOpacity(.2)), + ), + ), + ), + ), + ); + } + OverlayEntry _buildOverlayEntry() { final text = _textController.text; final commands = StreamChannel.of(context) .channel .config .commands - .where((c) => c.name.startsWith(text.substring(1))) + .where((c) => c.name.startsWith(text.replaceFirst('/', ''))) .toList(); RenderBox renderBox = context.findRenderObject(); @@ -253,15 +263,14 @@ class _MessageInputState extends State { void _setCommand(Command c) { setState(() { _textController.value = TextEditingValue( - text: '/${c.name}', + text: '/${c.name} ', selection: TextSelection.fromPosition( TextPosition( - offset: c.name.length + 1, + offset: c.name.length + 2, ), ), ); }); - _modalOn = false; _commandsOverlay?.remove(); _commandsOverlay = null; } @@ -530,8 +539,6 @@ class _MessageInputState extends State { _typingStarted = false; }); - _modalOn = false; - _commandsOverlay?.remove(); _commandsOverlay = null; @@ -541,7 +548,10 @@ class _MessageInputState extends State { final message = widget.editMessage.copyWith( parentId: widget.parentMessage?.id, text: text, - attachments: _getAttachments(attachments).toList(), + attachments: widget.editMessage.attachments + .where((attachment) => attachment.type == 'giphy') + .toList() + + _getAttachments(attachments).toList(), ); StreamChat.of(context).client.updateMessage(message).then((_) { if (widget.onMessageSent != null) { @@ -589,17 +599,21 @@ class _MessageInputState extends State { void initState() { super.initState(); - _keyboardListener = KeyboardVisibilityNotification().addNewListener( - onChange: (_) { - if (_modalOn) { - _commandsOverlay?.remove(); + _keyboardListener = + KeyboardVisibilityNotification().addNewListener(onHide: () { + if (_commandsOverlay != null) { + _commandsOverlay.remove(); + } + }, onShow: () { + if (_commandsOverlay != null) { + if (_textController.text.startsWith('/')) { WidgetsBinding.instance.addPostFrameCallback((_) { _commandsOverlay = _buildOverlayEntry(); Overlay.of(context).insert(_commandsOverlay); }); } - }, - ); + } + }); if (widget.editMessage != null) { _textController = TextEditingController(text: widget.editMessage.text); @@ -614,6 +628,18 @@ class _MessageInputState extends State { url: attachment.imageUrl, uploaded: true, )); + } else if (attachment.type == 'video') { + _attachments.add(_SendingAttachment( + type: FileType.VIDEO, + url: attachment.assetUrl, + uploaded: true, + )); + } else if (attachment.type != 'giphy') { + _attachments.add(_SendingAttachment( + type: FileType.ANY, + url: attachment.assetUrl, + uploaded: true, + )); } }); } else { diff --git a/lib/src/message_widget.dart b/lib/src/message_widget.dart index f8b58398..1e3d7d02 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -574,74 +574,77 @@ class _MessageWidgetState extends State ), ), builder: (context) { - return Flex( - direction: Axis.vertical, - mainAxisAlignment: MainAxisAlignment.end, - mainAxisSize: MainAxisSize.min, - children: [ - Padding( - padding: const EdgeInsets.only( - top: 16.0, - left: 16.0, - right: 16.0, - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - 'Edit message', - style: Theme.of(context).textTheme.title, - ), - Container( - height: 30, - padding: const EdgeInsets.all(2.0), - child: AspectRatio( - aspectRatio: 1, - child: RawMaterialButton( - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(4), - ), - elevation: 0, - highlightElevation: 0, - focusElevation: 0, - disabledElevation: 0, - hoverElevation: 0, - onPressed: () { - Navigator.of(context).pop(); - }, - fillColor: Colors.black.withOpacity(.1), - padding: EdgeInsets.all(4), - child: Icon( - Icons.close, - size: 15, - color: Colors.black, + return StreamChannel( + channel: streamChannel.channel, + child: Flex( + direction: Axis.vertical, + mainAxisAlignment: MainAxisAlignment.end, + mainAxisSize: MainAxisSize.min, + children: [ + Padding( + padding: const EdgeInsets.only( + top: 16.0, + left: 16.0, + right: 16.0, + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + 'Edit message', + style: Theme.of(context).textTheme.title, + ), + Container( + height: 30, + padding: const EdgeInsets.all(2.0), + child: AspectRatio( + aspectRatio: 1, + child: RawMaterialButton( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(4), + ), + elevation: 0, + highlightElevation: 0, + focusElevation: 0, + disabledElevation: 0, + hoverElevation: 0, + onPressed: () { + Navigator.of(context).pop(); + }, + fillColor: Colors.black.withOpacity(.1), + padding: EdgeInsets.all(4), + child: Icon( + Icons.close, + size: 15, + color: Colors.black, + ), ), ), ), - ), - ], + ], + ), ), - ), - Padding( - padding: EdgeInsets.only( - bottom: MediaQuery.of(context).viewInsets.bottom, + Padding( + padding: EdgeInsets.only( + bottom: MediaQuery.of(context).viewInsets.bottom, + ), + child: MessageInput( + editMessage: widget.message, + parentMessage: widget.isParent + ? StreamChannel.of(context) + .channel + .state + .messages + .firstWhere((message) => + message.id == widget.message.parentId) + : null, + onMessageSent: (_) { + Navigator.pop(context); + }, + ), ), - child: MessageInput( - editMessage: widget.message, - parentMessage: widget.isParent - ? StreamChannel.of(context) - .channel - .state - .messages - .firstWhere( - (message) => message.id == widget.message.parentId) - : null, - onMessageSent: (_) { - Navigator.pop(context); - }, - ), - ), - ], + ], + ), ); }, ); @@ -719,6 +722,7 @@ class _MessageWidgetState extends State imageUrl: attachment.thumbUrl ?? attachment.imageUrl ?? attachment.assetUrl, fit: BoxFit.cover, + placeholderFadeInDuration: Duration(milliseconds: 300), placeholder: (_, __) { return SizedBox( height: 200,