Skip to content

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

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

apurva010
Copy link
Collaborator

@apurva010 apurva010 commented Jun 5, 2025

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

  • The title of my PR starts with a Conventional Commit prefix (fix:, feat:, docs: etc).
  • I have followed the Contributor Guide when preparing my PR.
  • I have updated/added tests for ALL new/updated/fixed functionality.
  • I have updated/added relevant documentation in docs and added dartdoc comments with ///.
  • I have updated/added relevant examples in examples or docs.

Breaking Change?

  • Yes, this PR is a breaking change.
  • No, this PR is not a breaking change.

Related Issues

Closes #301, #318 and #222

@apurva010 apurva010 force-pushed the feat/add_plus_icon_beside_textfield branch from 1e7b83e to 8d78667 Compare June 5, 2025 05:28
@apurva010 apurva010 requested a review from aditya-css June 5, 2025 05:29
Copy link

@Copilot Copilot AI left a 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;
Copy link
Collaborator

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

@apurva010 apurva010 force-pushed the feat/add_plus_icon_beside_textfield branch 2 times, most recently from acd28cf to 8ecfa00 Compare June 5, 2025 13:59
Copy link
Collaborator

@aditya-css aditya-css left a 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 {
Copy link
Collaborator

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.

import 'package:chatview/chatview.dart';
import 'package:image_picker/image_picker.dart';

Future<String?> onIconPressed(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please rename this.

imageQuality: config?.imageQuality,
preferredCameraDevice: config?.preferredCameraDevice ?? CameraDevice.rear,
);
String? imagePath = image?.path;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
String? imagePath = image?.path;
var imagePath = image?.path;

preferredCameraDevice: config?.preferredCameraDevice ?? CameraDevice.rear,
);
String? imagePath = image?.path;
if (config?.onImagePicked != null) {
Copy link
Collaborator

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.

Copy link
Collaborator Author

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.

if (config?.onImagePicked != null) {
String? updatedImagePath = await config?.onImagePicked!(imagePath);
if (updatedImagePath != null) imagePath = updatedImagePath;
}
Copy link
Collaborator

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)) ...{
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The bracket seems unnecessary.

Comment on lines 22 to 23
import 'package:chatview/chatview.dart';
import 'package:chatview/src/extensions/extensions.dart';
import 'package:chatview/src/widgets/chat_view_inherited_widget.dart';
Copy link
Collaborator

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;
Copy link
Collaborator

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 {
Copy link
Collaborator

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;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
final List<ActionWidget> actionWidgets;
final List<OverlayActionWidget> actions;

@apurva010 apurva010 force-pushed the feat/add_plus_icon_beside_textfield branch 4 times, most recently from 01c4d8c to 9238657 Compare June 12, 2025 12:53
@apurva010 apurva010 force-pushed the feat/add_plus_icon_beside_textfield branch 2 times, most recently from 15e0665 to 46c62cf Compare June 17, 2025 05:57
Comment on lines 545 to 546
- Now, you can add overlay action button to show overlay action items in the text field.
- With multiple action items
Copy link
Collaborator

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';
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems unnecessary.

@@ -0,0 +1,21 @@
import 'package:chatview/chatview.dart';
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use relative import.

@@ -67,3 +67,11 @@ typedef CustomViewForReplyMessage = Widget Function(
ReplyMessage state,
);
typedef GetMessageSeparator = (Map<int, DateTime>, DateTime);
typedef TextFieldLeadingActionWidgetBuilder = List<Widget> Function(
Copy link
Collaborator

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';
Copy link
Collaborator

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';
Copy link
Collaborator

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;
Copy link
Collaborator

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) {
Copy link
Collaborator

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.

@apurva010 apurva010 force-pushed the feat/add_plus_icon_beside_textfield branch 2 times, most recently from 98e7f01 to 9d2ef45 Compare June 17, 2025 09:53
context,
widget.textEditingController,
) ??
[],
Copy link
Collaborator

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.

Comment on lines 334 to 341
onPressed: (value) {
(textFieldConfig?.enabled ?? true)
? widget.onImageSelected(
value ?? '',
'',
)
: null;
},
Copy link
Collaborator

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');
Copy link
Collaborator

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) {
Copy link
Collaborator

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);
Copy link
Collaborator

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({
Copy link
Collaborator

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.

@apurva010 apurva010 force-pushed the feat/add_plus_icon_beside_textfield branch from 9d2ef45 to ba98f1a Compare June 18, 2025 12:42
@apurva010 apurva010 force-pushed the feat/add_plus_icon_beside_textfield branch from ba98f1a to ef2c096 Compare June 18, 2025 14:33
Copy link
Collaborator

@aditya-css aditya-css left a 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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Request to add file sharing support
4 participants