-
Notifications
You must be signed in to change notification settings - Fork 184
feat: ✨ Add support for plus icon and action items in chat text field #340
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
1e7b83e
to
8d78667
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR adds support for a plus icon and additional action items in the chat text field, introducing overlay functionality and new configuration options. Key changes include:
- Implementation of an animated overlay for action items triggered by the plus icon.
- Introduction of new configuration fields (actionItems, plusIcon, plusIconColor, actionWidgetList, onPressedPlusIcon) in the text field configuration.
- Addition of the ActionItems enum and ActionWidget class to support these new features.
Reviewed Changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated no comments.
File | Description |
---|---|
lib/src/widgets/chatui_textfield.dart | Added overlay, animation, and plus icon logic to support extra action items. |
lib/src/values/enumeration.dart | Introduced the ActionItems enum with helper getters. |
lib/src/models/config_models/send_message_configuration.dart | Updated TextFieldConfiguration with new fields and added the ActionWidget class. |
CHANGELOG.md | Updated changelog to document the new feature. |
Comments suppressed due to low confidence (2)
lib/src/widgets/chatui_textfield.dart:90
- [nitpick] Consider adding unit tests to cover the overlay display logic and animation transitions to ensure robust behavior.
void _showOverlay(List<ActionWidget> plusOptions, {GlobalKey? plusIconKey}) {
lib/src/widgets/chatui_textfield.dart:157
- Verify that 'withValues' is the intended method for adjusting color opacity; if it is not part of the updated API, consider using 'withOpacity' for clarity and consistency.
color: Colors.black.withValues(alpha: 0.08),
final List<ActionItems> actionItems; | ||
|
||
/// Color of plus icon in text field | ||
final Color? plusIconColor; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of Plus Icon let's call it Custom Action, so user can add whatever icon they want, like we have seen in whatsapp for attachments
acd28cf
to
8ecfa00
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please add migration guide in readme and also add a separate section that shows how to add icons next to textfield and the overlay one.
} | ||
|
||
/// Represents a widget that can be used in the plus/attach modal sheet. | ||
class ActionWidget { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please move this to a separate file for this.
lib/src/utils/helper.dart
Outdated
import 'package:chatview/chatview.dart'; | ||
import 'package:image_picker/image_picker.dart'; | ||
|
||
Future<String?> onIconPressed( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please rename this.
lib/src/utils/helper.dart
Outdated
imageQuality: config?.imageQuality, | ||
preferredCameraDevice: config?.preferredCameraDevice ?? CameraDevice.rear, | ||
); | ||
String? imagePath = image?.path; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
String? imagePath = image?.path; | |
var imagePath = image?.path; |
lib/src/utils/helper.dart
Outdated
preferredCameraDevice: config?.preferredCameraDevice ?? CameraDevice.rear, | ||
); | ||
String? imagePath = image?.path; | ||
if (config?.onImagePicked != null) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems like an unnecessary check. Please remove it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is a callback for image picked.
lib/src/utils/helper.dart
Outdated
if (config?.onImagePicked != null) { | ||
String? updatedImagePath = await config?.onImagePicked!(imagePath); | ||
if (updatedImagePath != null) imagePath = updatedImagePath; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can rewrite the lines from 16 to 21 as:
final imagePath = await config?.onImagePicked?.call(imagePath);
return imagePath ?? image?.path;
if ((sendMessageConfig?.allowRecordingVoice ?? false) && | ||
!kIsWeb && | ||
(Platform.isIOS || Platform.isAndroid)) | ||
(Platform.isIOS || Platform.isAndroid)) ...{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The bracket seems unnecessary.
lib/src/widgets/message_view.dart
Outdated
import 'package:chatview/chatview.dart'; | ||
import 'package:chatview/src/extensions/extensions.dart'; | ||
import 'package:chatview/src/widgets/chat_view_inherited_widget.dart'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please use relative import.
@@ -168,6 +160,11 @@ class TextFieldConfiguration { | |||
/// Default is [true]. | |||
final bool enabled; | |||
|
|||
/// List of options to show in the plus/attach modal sheet | |||
final List<ActionWidget> actionWidgetList; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe you can remove this.
import 'package:flutter/material.dart'; | ||
|
||
/// Custom action button that displays a plus icon and shows a horizontal row of options when pressed. | ||
class CustomActionButton extends TextFieldActionButton { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please rename this to OverlayActionButton.
required this.actionWidgets, | ||
}); | ||
|
||
final List<ActionWidget> actionWidgets; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
final List<ActionWidget> actionWidgets; | |
final List<OverlayActionWidget> actions; |
01c4d8c
to
9238657
Compare
15e0665
to
46c62cf
Compare
doc/documentation.md
Outdated
- Now, you can add overlay action button to show overlay action items in the text field. | ||
- With multiple action items |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please check this.
@@ -0,0 +1,15 @@ | |||
import 'package:chatview/chatview.dart'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems unnecessary.
lib/src/utils/helper.dart
Outdated
@@ -0,0 +1,21 @@ | |||
import 'package:chatview/chatview.dart'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please use relative import.
lib/src/values/typedefs.dart
Outdated
@@ -67,3 +67,11 @@ typedef CustomViewForReplyMessage = Widget Function( | |||
ReplyMessage state, | |||
); | |||
typedef GetMessageSeparator = (Map<int, DateTime>, DateTime); | |||
typedef TextFieldLeadingActionWidgetBuilder = List<Widget> Function( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can keep just a single typedef for both leading and trailing.
@@ -0,0 +1,35 @@ | |||
import 'package:chatview/chatview.dart'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please use relative import.
@@ -0,0 +1,62 @@ | |||
import 'package:chatview/chatview.dart'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Relative import.
var overlayBottom = 0.0; | ||
var overlayLeft = 0.0; | ||
|
||
final screenHeight = MediaQuery.sizeOf(context).height; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please cache the size once.
|
||
if (plusIconKey?.currentContext case final context?) { | ||
final renderObject = context.findRenderObject(); | ||
if (renderObject != null && renderObject is RenderBox) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can avoid renderObject != null
check here.
98e7f01
to
9d2ef45
Compare
context, | ||
widget.textEditingController, | ||
) ?? | ||
[], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please avoid having row with empty list.
onPressed: (value) { | ||
(textFieldConfig?.enabled ?? true) | ||
? widget.onImageSelected( | ||
value ?? '', | ||
'', | ||
) | ||
: null; | ||
}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please assign null to the parameter directly.
@@ -309,6 +301,14 @@ class SendMessageWidgetState extends State<SendMessageWidget> { | |||
_assignRepliedMessage(); | |||
} | |||
|
|||
void _onImageSelected(String imagePath, String error) { | |||
debugPrint('Call in Send Message Widget'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please remove this.
@@ -309,6 +301,14 @@ class SendMessageWidgetState extends State<SendMessageWidget> { | |||
_assignRepliedMessage(); | |||
} | |||
|
|||
void _onImageSelected(String imagePath, String error) { | |||
debugPrint('Call in Send Message Widget'); | |||
if (imagePath.isNotEmpty) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please invert this condition.
overlayWidth -= overlayLeft - horizontalPadding * 2; | ||
} else { | ||
// For trailing, keep plus icon at right edge of overlay, but don't overflow left | ||
overlayLeft = (iconRight - overlayWidth); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Brackets seems unnecessary.
final double? height; | ||
|
||
/// Shows the emoji picker as a modal bottom sheet and returns the selected emoji. | ||
static Future<String?> pickEmoji({ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe you can make this private.
9d2ef45
to
ba98f1a
Compare
ba98f1a
to
ef2c096
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Need to use breaking convention in commit message (feat!:) and update the changelog to version 3.0.0.
Description
Trailing action widgets (Camera, Image, Overlay)
https://github.com/user-attachments/assets/be603f7d-12fb-44f3-8aff-d9eb64ba5987
Leading action widget (Emoji)
ScreenRecording_06-18-2025.20-05-59_1.MP4
Checklist
fix:
,feat:
,docs:
etc).docs
and added dartdoc comments with///
.examples
ordocs
.Breaking Change?
Related Issues
Closes #301, #318 and #222