Skip to content

Commit 6991895

Browse files
apurva780aditya-css
authored andcommitted
feat: ✨ Implement chat list UI components including app bar, controller, and example page
1 parent 789f594 commit 6991895

23 files changed

+1749
-36
lines changed
Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
import 'package:chatview/chatview.dart';
2+
import 'package:flutter/material.dart';
3+
4+
import 'main.dart';
5+
6+
class ChatViewListScreen extends StatefulWidget {
7+
const ChatViewListScreen({super.key});
8+
9+
@override
10+
State<ChatViewListScreen> createState() => _ChatViewListScreenState();
11+
}
12+
13+
class _ChatViewListScreenState extends State<ChatViewListScreen> {
14+
late final ChatViewListController controller;
15+
16+
@override
17+
void initState() {
18+
final now = DateTime.now().toUtc();
19+
final fiveMinAgo = now.subtract(const Duration(minutes: 5));
20+
final today = DateTime(now.year, now.month, now.day);
21+
final yesterday = DateTime(now.year, now.month, now.day - 1);
22+
final lastMessageTime = DateTime.parse('2025-06-06T13:58:00.000Z');
23+
var initialUsersList = [
24+
ChatViewListModel(
25+
id: '1',
26+
name: 'Breaking Bad',
27+
lastMessage: Message(
28+
message:
29+
'I am not in danger, Skyler. I am the danger. A guy opens his door and gets shot and you think that of me? No. I am the one who knocks!',
30+
createdAt: now,
31+
sentBy: '2',
32+
id: '1',
33+
status: MessageStatus.read,
34+
),
35+
unreadCount: 1,
36+
imageUrl:
37+
'https://m.media-amazon.com/images/M/MV5BMzU5ZGYzNmQtMTdhYy00OGRiLTg0NmQtYjVjNzliZTg1ZGE4XkEyXkFqcGc@._V1_.jpg',
38+
chatType: ChatType.group,
39+
),
40+
ChatViewListModel(
41+
id: '2',
42+
name: 'Heisenberg',
43+
lastMessage: Message(
44+
message: 'Say my name!!',
45+
createdAt: fiveMinAgo,
46+
sentBy: '3',
47+
id: '2',
48+
status: MessageStatus.read,
49+
),
50+
imageUrl:
51+
'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcTzc87OtZ7mZe-kca89Mfi4o1--95dQI7Ne-w&s',
52+
unreadCount: 2,
53+
userActiveStatus: UserActiveStatus.online,
54+
),
55+
ChatViewListModel(
56+
id: '3',
57+
name: 'Jessie Pinkman',
58+
lastMessage: Message(
59+
message: 'Yeah....!!!!',
60+
createdAt: today,
61+
sentBy: '4',
62+
id: '3',
63+
status: MessageStatus.read,
64+
),
65+
imageUrl: 'https://i.insider.com/5d9f454ee94e865e924818da?width=700',
66+
),
67+
ChatViewListModel(
68+
id: '4',
69+
name: 'Walter White',
70+
lastMessage: Message(
71+
message: 'Whats up?',
72+
createdAt: yesterday,
73+
sentBy: '4',
74+
id: '4',
75+
status: MessageStatus.read,
76+
),
77+
imageUrl:
78+
'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcS1Efw6_noLe4BzEsbgsfHIhvZNqWKaDtckdQ&s',
79+
),
80+
ChatViewListModel(
81+
id: '5',
82+
name: 'Hank Schrader',
83+
lastMessage: Message(
84+
message: 'Hello',
85+
createdAt: lastMessageTime,
86+
sentBy: '6',
87+
id: '5',
88+
status: MessageStatus.read,
89+
),
90+
imageUrl:
91+
'https://upload.wikimedia.org/wikipedia/en/d/db/Hank_Schrader_S5B.png',
92+
),
93+
];
94+
95+
controller = ChatViewListController(
96+
initialUsersList: initialUsersList,
97+
scrollController: ScrollController(),
98+
);
99+
super.initState();
100+
}
101+
102+
@override
103+
void dispose() {
104+
controller.dispose();
105+
super.dispose();
106+
}
107+
108+
@override
109+
Widget build(BuildContext context) {
110+
return Scaffold(
111+
body: ChatViewList(
112+
controller: controller,
113+
appbar: const ChatViewListAppBar(
114+
title: 'Breaking Bad',
115+
),
116+
config: ChatViewListConfig(
117+
chatViewListTileConfig: ChatViewListTileConfig(
118+
backgroundColor: Colors.blue,
119+
onTap: (user) {
120+
Navigator.of(context).push(
121+
MaterialPageRoute(
122+
builder: (context) => ChatScreen(
123+
user: user,
124+
),
125+
),
126+
);
127+
},
128+
onLongPress: (user) {
129+
debugPrint('Long pressed on user: ${user.name}');
130+
},
131+
),
132+
searchConfig: SearchConfig(
133+
textEditingController: TextEditingController(),
134+
onSearch: (value) async {
135+
if (value.isEmpty) {
136+
return null;
137+
}
138+
final list = controller.initialUsersList
139+
.where((user) =>
140+
user.name.toLowerCase().contains(value.toLowerCase()))
141+
.toList();
142+
return list;
143+
},
144+
border: const OutlineInputBorder(
145+
borderRadius: BorderRadius.all(
146+
Radius.circular(10),
147+
),
148+
),
149+
),
150+
),
151+
),
152+
);
153+
}
154+
}

example/lib/main.dart

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import 'package:chatview/chatview.dart';
2+
import 'package:example/chat_view_list_screen.dart';
23
import 'package:example/data.dart';
34
import 'package:example/models/theme.dart';
45
import 'package:flutter/material.dart';
@@ -20,13 +21,18 @@ class Example extends StatelessWidget {
2021
colorScheme:
2122
ColorScheme.fromSwatch(accentColor: const Color(0xffEE5366)),
2223
),
23-
home: const ChatScreen(),
24+
home: const ChatViewListScreen(),
2425
);
2526
}
2627
}
2728

2829
class ChatScreen extends StatefulWidget {
29-
const ChatScreen({Key? key}) : super(key: key);
30+
const ChatScreen({
31+
super.key,
32+
required this.user,
33+
});
34+
35+
final ChatViewListModel user;
3036

3137
@override
3238
State<ChatScreen> createState() => _ChatScreenState();
@@ -138,16 +144,17 @@ class _ChatScreenState extends State<ChatScreen> {
138144
appBar: ChatViewAppBar(
139145
elevation: theme.elevation,
140146
backGroundColor: theme.appBarColor,
141-
profilePicture: Data.profileImage,
147+
profilePicture: widget.user.imageUrl,
142148
backArrowColor: theme.backArrowColor,
143-
chatTitle: "Chat view",
149+
chatTitle: widget.user.name,
144150
chatTitleTextStyle: TextStyle(
145151
color: theme.appBarTitleTextStyle,
146152
fontWeight: FontWeight.bold,
147153
fontSize: 18,
148154
letterSpacing: 0.25,
149155
),
150-
userStatus: "online",
156+
userStatus:
157+
widget.user.userActiveStatus.isOnline ? 'Online' : 'Offline',
151158
userStatusTextStyle: const TextStyle(color: Colors.grey),
152159
actions: [
153160
IconButton(

lib/chatview.dart

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,21 @@ export 'package:audio_waveforms/audio_waveforms.dart'
3232
export 'package:chatview_utils/chatview_utils.dart';
3333
export 'package:emoji_picker_flutter/emoji_picker_flutter.dart';
3434

35+
export 'src/chat_list_view_controller.dart';
3536
export 'src/extensions/extensions.dart' show MessageTypes;
37+
export 'src/models/config_models/chat_view_list_config.dart';
38+
export 'src/models/config_models/chat_view_list_time_config.dart';
39+
export 'src/models/config_models/chat_view_list_user_config.dart';
40+
export 'src/models/config_models/load_more_widget_config.dart';
3641
export 'src/models/config_models/receipts_widget_config.dart';
42+
export 'src/models/config_models/search_config.dart';
43+
export 'src/models/config_models/unread_widget_config.dart';
3744
export 'src/models/models.dart';
3845
export 'src/utils/chat_view_locale.dart';
3946
export 'src/utils/package_strings.dart';
4047
export 'src/values/enumeration.dart';
4148
export 'src/values/typedefs.dart';
4249
export 'src/widgets/chat_view.dart';
4350
export 'src/widgets/chat_view_appbar.dart';
51+
export 'src/widgets/chat_view_list.dart';
52+
export 'src/widgets/chat_view_list_appbar.dart';
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
/*
2+
* Copyright (c) 2022 Simform Solutions
3+
*
4+
* Permission is hereby granted, free of charge, to any person obtaining a copy
5+
* of this software and associated documentation files (the "Software"), to deal
6+
* in the Software without restriction, including without limitation the rights
7+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8+
* copies of the Software, and to permit persons to whom the Software is
9+
* furnished to do so, subject to the following conditions:
10+
*
11+
* The above copyright notice and this permission notice shall be
12+
* included in all copies or substantial portions of the Software.
13+
*
14+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20+
* SOFTWARE.
21+
*/
22+
import 'dart:async';
23+
24+
import 'package:flutter/material.dart';
25+
26+
import 'models/chat_view_list_tile.dart';
27+
28+
class ChatViewListController {
29+
ChatViewListController({
30+
required this.initialUsersList,
31+
required this.scrollController,
32+
});
33+
34+
/// Represents initial chat list users.
35+
List<ChatViewListModel> initialUsersList = [];
36+
37+
/// Provides scroll controller for chat list.
38+
ScrollController scrollController;
39+
40+
/// Represents chat list user stream
41+
StreamController<List<ChatViewListModel>> chatListStreamController =
42+
StreamController.broadcast();
43+
44+
/// Used to add user in the chat list.
45+
void addUser(ChatViewListModel user) {
46+
initialUsersList.add(user);
47+
if (chatListStreamController.isClosed) return;
48+
chatListStreamController.sink.add(initialUsersList);
49+
}
50+
51+
/// Function for loading data while pagination.
52+
void loadMoreUsers(List<ChatViewListModel> userList) {
53+
initialUsersList.addAll(userList);
54+
if (chatListStreamController.isClosed) return;
55+
chatListStreamController.sink.add(initialUsersList);
56+
}
57+
58+
/// Function to add search results of the chat list in the stream.
59+
void updateChatList(List<ChatViewListModel> searchResults) {
60+
WidgetsBinding.instance.addPostFrameCallback(
61+
(_) {
62+
if (chatListStreamController.isClosed) return;
63+
chatListStreamController.sink.add(searchResults);
64+
},
65+
);
66+
}
67+
68+
/// Function to clear the search results and show the original chat list.
69+
void clearSearch() {
70+
if (chatListStreamController.isClosed) return;
71+
chatListStreamController.sink.add(initialUsersList);
72+
}
73+
74+
/// Used to dispose ValueNotifiers and Streams.
75+
void dispose() {
76+
scrollController.dispose();
77+
chatListStreamController.close();
78+
}
79+
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
/*
2+
* Copyright (c) 2022 Simform Solutions
3+
*
4+
* Permission is hereby granted, free of charge, to any person obtaining a copy
5+
* of this software and associated documentation files (the "Software"), to deal
6+
* in the Software without restriction, including without limitation the rights
7+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8+
* copies of the Software, and to permit persons to whom the Software is
9+
* furnished to do so, subject to the following conditions:
10+
*
11+
* The above copyright notice and this permission notice shall be
12+
* included in all copies or substantial portions of the Software.
13+
*
14+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20+
* SOFTWARE.
21+
*/
22+
import 'package:chatview_utils/chatview_utils.dart';
23+
24+
import '../values/enumeration.dart';
25+
26+
/// Model class representing a user or group in the chat list.
27+
class ChatViewListModel {
28+
/// Unique identifier for the user or group.
29+
final String id;
30+
31+
/// Provides name of the user or group.
32+
final String name;
33+
34+
/// Provides last message in chat list.
35+
final Message? lastMessage;
36+
37+
/// Provides image URL for user or group profile in chat list.
38+
final String? imageUrl;
39+
40+
/// Provides unread message count for user or group in chat list.
41+
final int? unreadCount;
42+
43+
/// Type of chat: user or group.
44+
final ChatType chatType;
45+
46+
/// User's active status in the chat list.
47+
/// Defaults to [UserActiveStatus.offline].
48+
final UserActiveStatus userActiveStatus;
49+
50+
/// Creates a user or group object for the chat list.
51+
const ChatViewListModel({
52+
required this.id,
53+
required this.name,
54+
this.lastMessage,
55+
this.imageUrl,
56+
this.unreadCount,
57+
this.chatType = ChatType.user,
58+
this.userActiveStatus = UserActiveStatus.offline,
59+
});
60+
}

0 commit comments

Comments
 (0)