Skip to content

Commit 4be707d

Browse files
feat: ✨ Add Menu Option for ChatViewList
1 parent 4eddfb9 commit 4be707d

File tree

8 files changed

+155
-20
lines changed

8 files changed

+155
-20
lines changed

example/lib/chat_view_list_screen.dart

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,31 @@ class _ChatViewListScreenState extends State<ChatViewListScreen> {
4848
await Future.delayed(const Duration(seconds: 2)),
4949
pinIconConfig: const PinIconConfig(),
5050
muteIconConfig: const MuteIconConfig(),
51+
menuConfig: ChatMenuConfig(
52+
enabled: true,
53+
muteStatusCallback: (result) {
54+
controller?.updateChat(
55+
result.chat.id,
56+
(previousChat) => previousChat.copyWith(
57+
settings: previousChat.settings.copyWith(
58+
muteStatus: result.status,
59+
),
60+
),
61+
);
62+
Navigator.of(context).pop();
63+
},
64+
pinStatusCallback: (result) {
65+
controller?.updateChat(
66+
result.chat.id,
67+
(previousChat) => previousChat.copyWith(
68+
settings: previousChat.settings.copyWith(
69+
pinStatus: result.status,
70+
),
71+
),
72+
);
73+
Navigator.of(context).pop();
74+
},
75+
),
5176
config: ChatViewListConfig(
5277
enablePagination: true,
5378
loadMoreConfig: const LoadMoreConfig(),
@@ -74,9 +99,6 @@ class _ChatViewListScreenState extends State<ChatViewListScreen> {
7499
),
75100
);
76101
},
77-
onLongPress: (chat) {
78-
debugPrint('Long pressed on chat: ${chat.name}');
79-
},
80102
),
81103
searchConfig: ChatViewListSearchConfig(
82104
textEditingController: TextEditingController(),
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import 'package:flutter/cupertino.dart';
2+
3+
import '../../../values/enumeration.dart';
4+
import '../../../values/typedefs.dart';
5+
6+
class ChatMenuConfig {
7+
const ChatMenuConfig({
8+
this.enabled = true,
9+
this.actions,
10+
this.textStyle,
11+
this.menuBuilder,
12+
this.muteStatusCallback,
13+
this.pinStatusCallback,
14+
this.muteStatusTrailingIcon,
15+
this.pinStatusTrailingIcon,
16+
});
17+
18+
final bool enabled;
19+
final TextStyle? textStyle;
20+
final List<Widget>? actions;
21+
final MenuBuilderCallback? menuBuilder;
22+
final ChatStatusCallback<MuteStatus>? muteStatusCallback;
23+
final ChatStatusCallback<PinStatus>? pinStatusCallback;
24+
final StatusTrailingIcon<MuteStatus>? muteStatusTrailingIcon;
25+
final StatusTrailingIcon<PinStatus>? pinStatusTrailingIcon;
26+
}

lib/src/models/config_models/chat_view_list/chat_view_list_tile_config.dart

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,6 @@ class ChatViewListTileConfig {
4848
this.userNameTextStyle,
4949
this.lastMessageTextStyle,
5050
this.onTap,
51-
this.onLongPress,
5251
this.lastMessageTileBuilder,
5352
});
5453

@@ -97,9 +96,6 @@ class ChatViewListTileConfig {
9796
/// Callback function that is called when a user taps on a chat item.
9897
final ValueSetter<ChatViewListItem>? onTap;
9998

100-
/// Callback function that is called when the user long presses on a chat item.
101-
final ValueSetter<ChatViewListItem>? onLongPress;
102-
10399
/// Configuration for the user avatar in the chat list.
104100
final UserAvatarConfig userAvatarConfig;
105101

lib/src/models/config_models/chat_view_list/models.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
* SOFTWARE.
2121
*/
2222
export 'chat_settings.dart';
23+
export 'chat_menu_config.dart';
2324
export 'chat_view_list_config.dart';
2425
export 'chat_view_list_tile_config.dart';
2526
export 'last_message_time_config.dart';

lib/src/values/typedefs.dart

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,3 +129,8 @@ typedef ChatSorter = int Function(
129129
ChatViewListItem chat1,
130130
ChatViewListItem chat2,
131131
);
132+
typedef MenuWidgetCallback = Widget Function(ChatViewListItem chat);
133+
typedef MenuBuilderCallback = Widget Function(
134+
BuildContext context,
135+
ChatViewListItem chat,
136+
);
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
import 'package:flutter/cupertino.dart';
2+
import 'package:flutter/material.dart';
3+
4+
import '../../models/models.dart';
5+
import '../../values/enumeration.dart';
6+
7+
class ChatListTileContextMenu extends StatelessWidget {
8+
const ChatListTileContextMenu({
9+
required this.chat,
10+
required this.child,
11+
required this.config,
12+
required this.chatTileColor,
13+
super.key,
14+
});
15+
16+
final Widget child;
17+
final ChatViewListItem chat;
18+
final ChatMenuConfig config;
19+
final Color chatTileColor;
20+
21+
@override
22+
Widget build(BuildContext context) {
23+
if (!config.enabled) return child;
24+
final newMuteStatus = switch (chat.settings.muteStatus) {
25+
MuteStatus.muted => MuteStatus.unmute,
26+
MuteStatus.unmute => MuteStatus.muted,
27+
};
28+
final newPinStatus = switch (chat.settings.pinStatus) {
29+
PinStatus.pinned => PinStatus.unpinned,
30+
PinStatus.unpinned => PinStatus.pinned,
31+
};
32+
return config.menuBuilder?.call(context, chat) ??
33+
CupertinoContextMenu.builder(
34+
builder: (_, __) => Material(
35+
color: chatTileColor,
36+
child: child,
37+
),
38+
actions: [
39+
...?config.actions,
40+
if (config.muteStatusCallback != null)
41+
CupertinoContextMenuAction(
42+
trailingIcon: config.muteStatusTrailingIcon?.call(
43+
newMuteStatus,
44+
) ??
45+
newMuteStatus.iconData,
46+
child: Text(
47+
newMuteStatus.menuName,
48+
style: config.textStyle,
49+
),
50+
onPressed: () => config.muteStatusCallback?.call((
51+
chat: chat,
52+
status: newMuteStatus,
53+
)),
54+
),
55+
if (config.pinStatusCallback != null)
56+
CupertinoContextMenuAction(
57+
trailingIcon: config.pinStatusTrailingIcon?.call(
58+
newPinStatus,
59+
) ??
60+
newPinStatus.iconData,
61+
child: Text(
62+
newPinStatus.menuName,
63+
style: config.textStyle,
64+
),
65+
onPressed: () => config.pinStatusCallback?.call((
66+
chat: chat,
67+
status: newPinStatus,
68+
)),
69+
),
70+
],
71+
);
72+
}
73+
}

lib/src/widgets/chat_view_list/chat_view_list.dart

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -24,17 +24,20 @@ import 'package:flutter/material.dart';
2424

2525
import '../../controller/chat_list_view_controller.dart';
2626
import '../../models/chat_view_list_item.dart';
27+
import '../../models/config_models/chat_view_list/chat_menu_config.dart';
2728
import '../../models/config_models/chat_view_list/chat_view_list_config.dart';
2829
import '../../models/config_models/chat_view_list/load_more_config.dart';
2930
import '../../models/config_models/chat_view_list/mute_icon_config.dart';
3031
import '../../models/config_models/chat_view_list/pin_icon_config.dart';
32+
import 'chat_list_tile_context_menu.dart';
3133
import 'chat_view_list_item_tile.dart';
3234
import 'search_text_field.dart';
3335

3436
class ChatViewList extends StatefulWidget {
3537
const ChatViewList({
3638
required this.controller,
3739
this.config = const ChatViewListConfig(),
40+
this.menuConfig = const ChatMenuConfig(),
3841
this.scrollViewKeyboardDismissBehavior =
3942
ScrollViewKeyboardDismissBehavior.onDrag,
4043
this.muteIconConfig = const MuteIconConfig(),
@@ -98,6 +101,9 @@ class ChatViewList extends StatefulWidget {
98101
/// Provides configurations related to pin icon appearance.
99102
final PinIconConfig pinIconConfig;
100103

104+
/// Callback to provide a widget for the menu in the chat list.
105+
final ChatMenuConfig menuConfig;
106+
101107
@override
102108
State<ChatViewList> createState() => _ChatViewListState();
103109
}
@@ -150,18 +156,25 @@ class _ChatViewListState extends State<ChatViewList> {
150156
return widget.config.separator;
151157
}
152158

153-
return widget.chatListUserWidgetBuilder
154-
?.call(context, itemIndex) ??
155-
ChatViewListItemTile(
156-
chat: chats[itemIndex],
157-
profile: widget.profile,
158-
trailing: widget.trailing,
159-
userName: widget.userName,
160-
lastMessageTime: widget.lastMessageTime,
161-
tileConfig: widget.config.tileConfig,
162-
muteIconConfig: widget.muteIconConfig,
163-
pinIconConfig: widget.pinIconConfig,
164-
);
159+
final chat = chats[itemIndex];
160+
return ChatListTileContextMenu(
161+
key: ValueKey(chat.id),
162+
chat: chat,
163+
config: widget.menuConfig,
164+
chatTileColor: widget.config.backgroundColor,
165+
child: widget.chatListUserWidgetBuilder
166+
?.call(context, itemIndex) ??
167+
ChatViewListItemTile(
168+
chat: chat,
169+
profile: widget.profile,
170+
trailing: widget.trailing,
171+
userName: widget.userName,
172+
lastMessageTime: widget.lastMessageTime,
173+
tileConfig: widget.config.tileConfig,
174+
muteIconConfig: widget.muteIconConfig,
175+
pinIconConfig: widget.pinIconConfig,
176+
),
177+
);
165178
},
166179
),
167180
);

lib/src/widgets/chat_view_list/chat_view_list_item_tile.dart

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,6 @@ class ChatViewListItemTile extends StatelessWidget {
8080
final lastMessage = chat.lastMessage;
8181
return GestureDetector(
8282
behavior: HitTestBehavior.opaque,
83-
onLongPress: () => tileConfig.onLongPress?.call(chat),
8483
onTap: () {
8584
FocusManager.instance.primaryFocus?.unfocus();
8685
tileConfig.onTap?.call(chat);

0 commit comments

Comments
 (0)