Skip to content

Commit ef2c096

Browse files
committed
feat: ✨ Add support for plus icon and action items in chat text field
1 parent 39d1adf commit ef2c096

21 files changed

+688
-327
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
## [2.4.2] (unreleased)
22

3+
* **Breaking**: [318](https://github.com/SimformSolutionsPvtLtd/flutter_chatview/issues/318)
4+
Provide support for action item widgets on the chat text field with position options leading and trailing.
5+
Also, provide a way to add plus/attach button to open the overlay for action items.
36
* **Fix**: [266](https://github.com/SimformSolutionsPvtLtd/flutter_chatview/issues/266)
47
Fix the keyboard overlapping the text field
58
* **Feat**: [296](https://github.com/SimformSolutionsPvtLtd/flutter_chatview/issues/296)

doc/documentation.md

Lines changed: 50 additions & 166 deletions
Original file line numberDiff line numberDiff line change
@@ -530,183 +530,67 @@ real-time messaging with supporting media uploads.
530530

531531
# Migration Guide
532532

533-
## Migration Guide for ChatView 2.0.0
534-
This guide will help you migrate your code from previous versions of ChatView to version 2.0.0.
533+
## Migration Guide for ChatView 3.0.0
534+
This guide will help you migrate your code from previous versions of ChatView to version 3.0.0.
535535

536536
## Key Changes
537537

538-
### Renamed Properties
538+
### Add action item widgets list for text field
539539

540-
- Renamed `sendBy` field to `sentBy` in `Message` class.
541-
- Renamed `chatUsers` field to `otherUsers` in `ChatController` class.
540+
- In this version, we have introduced a new way to add action items to the text field.
541+
- There are two ways you can add action items at leading and trailing positions of the text field.
542+
- `textFieldLeadingActionWidgetBuilder`: This builder allows you to add list of action widgets at the leading position of the text field.
543+
- `textFieldTrailingActionWidgetBuilder`: This builder allows you to add list of action widgets at the trailing position of the text field.
544+
- Add `CameraActionButton` and `GalleryActionButton` widgets as list to leading and trailing builder fo the text field for camera and gallery actions.
545+
- Now, you can add overlay action button to show overlay action items in the text field. With multiple action items
542546

543-
### Moved Properties
547+
To show camera and gallery action items in the text field at trailing position, you can use `textFieldTrailingActionWidgetBuilder`. Also, to show the action items in the text field at leading position, you can use `textFieldLeadingActionWidgetBuilder`.
548+
You can also add custom overlay action items in the text field. As shown in below example:
544549

545-
- Moved `currentUser` field from `ChatView` widget to `ChatController` class.
546-
547-
### Updated Methods
548-
549-
- Updated `id` value in `copyWith` method of `Message` to have correct value.
550-
- Removed `showTypingIndicator` field from `ChatView` and replaced it with `ChatController.showTypingIndicator`.
551-
552-
### JSON Serialization Changes
553-
554-
The format for `fromJson` and `toJson` methods changed for several classes:
555-
556-
#### ChatUser
557-
558-
**Before (`ChatUser.fromJson`):**
559-
```dart
560-
ChatUser.fromJson(
561-
{
562-
...
563-
'imageType': ImageType.asset,
564-
...
565-
},
566-
),
567-
```
568-
569-
**After (`ChatUser.fromJson`):**
570-
```dart
571-
ChatUser.fromJson(
572-
{
573-
...
574-
'imageType': 'asset',
575-
...
576-
},
577-
),
578-
```
579-
580-
**Before (`ChatUser.toJson`):**
581-
```dart
582-
{
583-
...
584-
imageType: ImageType.asset,
585-
...
586-
}
587-
```
588-
589-
**After (`ChatUser.toJson`):**
590-
```dart
591-
{
592-
...
593-
imageType: asset,
594-
...
595-
}
596-
```
597-
598-
#### Message
599-
600-
**Before (`Message.fromJson`):**
601-
```dart
602-
Message.fromJson(
603-
{
604-
...
605-
'createdAt': DateTime.now(),
606-
'message_type': MessageType.text,
607-
'voice_message_duration': Duration(seconds: 5),
608-
...
609-
}
610-
)
611-
```
612-
613-
**After (`Message.fromJson`):**
614550
```dart
615-
Message.fromJson(
616-
{
617-
...
618-
'createdAt': '2024-06-13T17:32:19.586412',
619-
'message_type': 'text',
620-
'voice_message_duration': '5000000',
621-
...
622-
}
623-
)
624-
```
625-
626-
**Before (`Message.toJson`):**
627-
```dart
628-
{
629-
...
630-
createdAt: 2024-06-13 17:23:19.454789,
631-
message_type: MessageType.text,
632-
voice_message_duration: 0:00:05.000000,
633-
...
634-
}
635-
```
636-
637-
**After (`Message.toJson`):**
638-
```dart
639-
{
640-
...
641-
createdAt: 2024-06-13T17:32:19.586412,
642-
message_type: text,
643-
voice_message_duration: 5000000,
644-
...
645-
}
646-
```
647-
648-
#### ReplyMessage
649-
650-
**Before (`ReplyMessage.fromJson`):**
651-
```dart
652-
ReplyMessage.fromJson(
653-
{
654-
...
655-
'message_type': MessageType.text,
656-
'voiceMessageDuration': Duration(seconds: 5),
657-
...
658-
}
659-
)
660-
```
661-
662-
**After (`ReplyMessage.fromJson`):**
663-
```dart
664-
ReplyMessage.fromJson(
665-
{
666-
...
667-
'message_type': 'text',
668-
'voiceMessageDuration': '5000000',
669-
...
551+
textFieldConfig: TextFieldConfiguration(
552+
textFieldTrailingActionWidgetBuilder: (context, controller) {
553+
return [
554+
CameraActionButton(
555+
icon: const Icon(
556+
Icons.camera_alt,
557+
),
558+
onPressed: (path) {
559+
if (path != null) {
560+
_onSendTap(path, const ReplyMessage(), MessageType.image);
561+
}
562+
},
563+
),
564+
GalleryActionButton(
565+
icon: const Icon(
566+
Icons.photo_library,
567+
),
568+
onPressed: (path) {
569+
if (path != null) {
570+
_onSendTap(path, const ReplyMessage(), MessageType.image);
571+
}
572+
},
573+
),
574+
OverlayActionButton(
575+
icon: const Icon(Icons.add),
576+
actions: [
577+
OverlayActionWidget(
578+
icon: const Icon(Icons.location_pin),
579+
label: 'Location',
580+
onTap: () {},
581+
),
582+
OverlayActionWidget(
583+
icon: const Icon(Icons.person),
584+
label: 'Contact',
585+
onTap: () {},
586+
),
587+
],
588+
),
589+
];
670590
}
671-
)
672-
```
673-
674-
**Before (`ReplyMessage.toJson`):**
675-
```dart
676-
{
677-
...
678-
message_type: MessageType.text,
679-
voiceMessageDuration: 0:00:05.000000,
680-
...
681-
}
682-
```
683-
684-
**After (`ReplyMessage.toJson`):**
685-
```dart
686-
{
687-
...
688-
message_type: text,
689-
voiceMessageDuration: 5000000,
690-
...
691-
}
692-
```
693-
694-
## Typing Indicator Changes
695-
696-
**Before:**
697-
```dart
698-
ChatView(
699-
showTypingIndicator: false,
700591
),
701592
```
702593

703-
**After:**
704-
```dart
705-
// Use it with your ChatController instance
706-
_chatController.setTypingIndicator = true; // for showing indicator
707-
_chatController.setTypingIndicator = false; // for hiding indicator
708-
```
709-
710594
# Contributors
711595

712596
## Main Contributors

example/lib/main.dart

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -43,28 +43,28 @@ class _ChatScreenState extends State<ChatScreen> {
4343
_chatController = ChatController(
4444
initialMessageList: Data.messageList,
4545
scrollController: ScrollController(),
46-
currentUser: ChatUser(
46+
currentUser: const ChatUser(
4747
id: '1',
4848
name: 'Flutter',
4949
profilePhoto: Data.profileImage,
5050
),
5151
otherUsers: [
52-
ChatUser(
52+
const ChatUser(
5353
id: '2',
5454
name: 'Simform',
5555
profilePhoto: Data.profileImage,
5656
),
57-
ChatUser(
57+
const ChatUser(
5858
id: '3',
5959
name: 'Jhon',
6060
profilePhoto: Data.profileImage,
6161
),
62-
ChatUser(
62+
const ChatUser(
6363
id: '4',
6464
name: 'Mike',
6565
profilePhoto: Data.profileImage,
6666
),
67-
ChatUser(
67+
const ChatUser(
6868
id: '5',
6969
name: 'Rich',
7070
profilePhoto: Data.profileImage,

lib/chatview.dart

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,5 +39,10 @@ export 'src/utils/chat_view_locale.dart';
3939
export 'src/utils/package_strings.dart';
4040
export 'src/values/enumeration.dart';
4141
export 'src/values/typedefs.dart';
42+
export 'src/widgets/action_widgets/camera_action_button.dart';
43+
export 'src/widgets/action_widgets/emoji_picker_action_button.dart';
44+
export 'src/widgets/action_widgets/gallery_action_button.dart';
45+
export 'src/widgets/action_widgets/overlay_action_button.dart';
46+
export 'src/widgets/action_widgets/text_field_action_button.dart';
4247
export 'src/widgets/chat_view.dart';
4348
export 'src/widgets/chat_view_appbar.dart';

lib/src/extensions/extensions.dart

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -72,12 +72,9 @@ extension ValidateString on String {
7272
bool get fromMemory => startsWith('data:image');
7373

7474
bool get isAllEmoji {
75-
for (String s in EmojiParser().unemojify(this).split(" ")) {
76-
if (!s.startsWith(":") || !s.endsWith(":")) {
77-
return false;
78-
}
79-
}
80-
return true;
75+
final unEmojified = EmojiParser().unemojify(this);
76+
final regex = RegExp(emojiRegex); // One or more emoji tags only
77+
return regex.hasMatch(unEmojified);
8178
}
8279

8380
bool get isUrl => Uri.tryParse(this)?.isAbsolute ?? false;

lib/src/models/config_models/send_message_configuration.dart

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,9 @@
2121
*/
2222

2323
import 'package:audio_waveforms/audio_waveforms.dart';
24+
import 'package:chatview_utils/chatview_utils.dart';
2425
import 'package:flutter/material.dart';
2526
import 'package:flutter/services.dart';
26-
import 'package:chatview_utils/chatview_utils.dart';
2727
import 'package:image_picker/image_picker.dart';
2828

2929
import '../../values/typedefs.dart';
@@ -62,12 +62,6 @@ class SendMessageConfiguration {
6262
/// Enable/disable voice recording. Enabled by default.
6363
final bool allowRecordingVoice;
6464

65-
/// Enable/disable image picker from gallery. Enabled by default.
66-
final bool enableGalleryImagePicker;
67-
68-
/// Enable/disable send image from camera. Enabled by default.
69-
final bool enableCameraImagePicker;
70-
7165
/// Color of mic icon when replying to some voice message.
7266
final Color? micIconColor;
7367

@@ -89,8 +83,6 @@ class SendMessageConfiguration {
8983
this.replyMessageColor,
9084
this.closeIconColor,
9185
this.allowRecordingVoice = true,
92-
this.enableCameraImagePicker = true,
93-
this.enableGalleryImagePicker = true,
9486
this.voiceRecordingConfiguration,
9587
this.micIconColor,
9688
this.cancelRecordConfiguration,
@@ -168,6 +160,17 @@ class TextFieldConfiguration {
168160
/// Default is [true].
169161
final bool enabled;
170162

163+
/// List of widgets to be shown as action widget in text field.
164+
final TextFieldActionWidgetBuilder? textFieldTrailingActionWidgetBuilder;
165+
166+
/// List of widgets to be shown as leading action widget in text field.
167+
final TextFieldActionWidgetBuilder? textFieldLeadingActionWidgetBuilder;
168+
169+
/// hint text max lines in text field.
170+
final int? hintMaxLines;
171+
172+
final bool hideLeadingActionsOnType;
173+
171174
const TextFieldConfiguration({
172175
this.contentPadding,
173176
this.maxLines,
@@ -184,6 +187,10 @@ class TextFieldConfiguration {
184187
this.inputFormatters,
185188
this.textCapitalization,
186189
this.enabled = true,
190+
this.textFieldTrailingActionWidgetBuilder,
191+
this.textFieldLeadingActionWidgetBuilder,
192+
this.hintMaxLines,
193+
this.hideLeadingActionsOnType = true,
187194
});
188195
}
189196

0 commit comments

Comments
 (0)