Skip to content

Commit 6578672

Browse files
Merge pull request #57 from ChandruWritesCode/37-group-chat-create-manage-send-messages-frontend
37 group chat create manage send messages frontend
2 parents 9352e41 + f80c1c5 commit 6578672

7 files changed

Lines changed: 827 additions & 377 deletions

File tree

mobile/lib/controllers/chat.dart

Lines changed: 59 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ class ChatController extends ChangeNotifier {
1212
List<Conversation> inbox = [];
1313
List<Message> activeChat = [];
1414
List<dynamic> contactSearchResults = [];
15+
1516
String? currentChatUserId;
1617
bool isPeerTyping = false;
1718
bool isPeerOnline = false;
@@ -22,9 +23,12 @@ class ChatController extends ChangeNotifier {
2223
_ws.stream?.listen(
2324
(rawFrame) {
2425
try {
25-
_handleIncomingWebSocketEvent(jsonDecode(rawFrame));
26+
final decoded = jsonDecode(rawFrame);
27+
if (decoded is Map<String, dynamic>) {
28+
_handleIncomingWebSocketEvent(decoded);
29+
}
2630
} catch (e) {
27-
debugPrint("WebSocket stream payload error: $e");
31+
debugPrint("WebSocket payload error: $e");
2832
}
2933
},
3034
onError: (err) => debugPrint("WS Pipeline Error: $err"),
@@ -36,18 +40,10 @@ class ChatController extends ChangeNotifier {
3640
Future<void> loadInbox() async {
3741
try {
3842
final res = await _api.getConversations();
39-
dynamic targetData;
40-
41-
if (res.data is List) {
42-
targetData = res.data;
43-
} else if (res.data is Map) {
44-
targetData = res.data['data'] ?? res.data['conversations'] ?? res.data;
45-
}
43+
final targetList = _extractDataList(res.data, ['conversations']);
4644

47-
if (targetData is List) {
48-
inbox = targetData.map((json) => Conversation.fromJson(json)).toList();
49-
notifyListeners();
50-
}
45+
inbox = targetList.map((json) => Conversation.fromJson(json)).toList();
46+
notifyListeners();
5147
} catch (e) {
5248
debugPrint("Inbox read error: $e");
5349
}
@@ -62,29 +58,23 @@ class ChatController extends ChangeNotifier {
6258

6359
try {
6460
final res = await _api.getChatHistory(targetUid);
65-
dynamic targetData;
66-
67-
if (res.data is List) {
68-
targetData = res.data;
69-
} else if (res.data is Map) {
70-
targetData = res.data['data'] ?? res.data['messages'] ?? res.data;
71-
}
61+
final targetList = _extractDataList(res.data, ['messages']);
7262

73-
if (targetData is List) {
74-
activeChat = targetData
75-
.map((json) => Message.fromJson(json))
76-
.toList()
77-
.reversed
78-
.toList();
79-
}
63+
activeChat = targetList
64+
.map((json) => Message.fromJson(json))
65+
.toList()
66+
.reversed
67+
.toList();
8068

8169
_ws.sendReadReceipt(targetId: targetUid);
8270
_ws.sendRequestStatus(targetId: targetUid);
71+
72+
notifyListeners();
8373
await loadInbox();
8474
} catch (e) {
8575
debugPrint("Timeline tracking fail: $e");
76+
notifyListeners();
8677
}
87-
notifyListeners();
8878
}
8979

9080
Future<void> queryUsers(String term) async {
@@ -101,26 +91,15 @@ class ChatController extends ChangeNotifier {
10191
notifyListeners();
10292
return;
10393
}
94+
10495
isSearchLoading = true;
10596
notifyListeners();
10697

10798
try {
108-
final res = await _api.searchUsers(cleanTerm);
109-
if (res.data == null) {
110-
contactSearchResults = [];
111-
} else if (res.data is List) {
112-
contactSearchResults = res.data;
113-
} else if (res.data is Map) {
114-
if (res.data['data'] != null && res.data['data'] is List) {
115-
contactSearchResults = res.data['data'];
116-
} else if (res.data['users'] != null && res.data['users'] is List) {
117-
contactSearchResults = res.data['users'];
118-
} else {
119-
contactSearchResults = [];
120-
}
121-
}
99+
final res = await _api.searchUsers(term);
100+
contactSearchResults = _extractDataList(res.data, ['users']);
122101
} catch (e) {
123-
debugPrint("User query pipeline failure: $e");
102+
debugPrint("User query failure: $e");
124103
contactSearchResults.clear();
125104
} finally {
126105
isSearchLoading = false;
@@ -137,16 +116,15 @@ class ChatController extends ChangeNotifier {
137116
}
138117

139118
void sendTextMessage(String text) {
140-
if (currentChatUserId == null || text.trim().isEmpty) return;
119+
final cleanContent = text.trim();
120+
if (currentChatUserId == null || cleanContent.isEmpty) return;
141121

142-
final String clientMessageId =
143-
"cli_${DateTime.now().millisecondsSinceEpoch}";
144-
final String targetId = currentChatUserId!;
145-
final String cleanContent = text.trim();
122+
final targetId = currentChatUserId!;
123+
final clientMessageId = "cli_${DateTime.now().millisecondsSinceEpoch}";
146124

147125
_ws.sendChat(messageId: "", targetId: targetId, content: cleanContent);
148126

149-
final Message optimisticMsg = Message(
127+
final optimisticMsg = Message(
150128
id: clientMessageId,
151129
senderId: "me",
152130
receiverId: targetId,
@@ -157,6 +135,7 @@ class ChatController extends ChangeNotifier {
157135

158136
activeChat.add(optimisticMsg);
159137
notifyListeners();
138+
160139
loadInbox();
161140
}
162141

@@ -168,13 +147,14 @@ class ChatController extends ChangeNotifier {
168147

169148
void _handleIncomingWebSocketEvent(Map<String, dynamic> data) {
170149
final String? type = data['type'];
171-
final String? senderId =
172-
data['sender_id'] ?? data['sender'] ?? data['receiver_id'];
173-
174150
if (type == null) return;
175151

152+
final String? senderId =
153+
data['sender_id'] ?? data['sender'] ?? data['receiver_id'];
176154
final String? cleanSender = senderId?.trim().toLowerCase();
177155
final String? cleanCurrentChat = currentChatUserId?.trim().toLowerCase();
156+
final bool isCurrentChat =
157+
cleanSender != null && cleanSender == cleanCurrentChat;
178158

179159
switch (type) {
180160
case 'user_status':
@@ -188,35 +168,54 @@ class ChatController extends ChangeNotifier {
188168
notifyListeners();
189169
}
190170
break;
171+
191172
case 'chat':
192173
case 'message':
193-
if (cleanSender != null && cleanSender == cleanCurrentChat) {
174+
if (isCurrentChat) {
194175
activeChat.add(Message.fromJson(data));
195176
_ws.sendReadReceipt(targetId: currentChatUserId!);
196177
notifyListeners();
197-
} else {
198-
loadInbox();
199178
}
179+
loadInbox();
200180
break;
181+
201182
case 'typing':
202-
if (cleanSender != null && cleanSender == cleanCurrentChat) {
183+
if (isCurrentChat) {
203184
isPeerTyping = data['content'] == 'true';
204185
notifyListeners();
205186
}
206187
break;
188+
207189
case 'read_receipt':
208-
if (cleanSender != null && cleanSender == cleanCurrentChat) {
190+
if (isCurrentChat) {
191+
bool updated = false;
209192
activeChat = activeChat.map((msg) {
210193
final String sId = msg.senderId.trim().toLowerCase();
211-
if (sId == 'me' || sId != cleanCurrentChat) {
194+
if (!msg.isRead && (sId == 'me' || sId != cleanCurrentChat)) {
195+
updated = true;
212196
return msg.copyWith(isRead: true);
213197
}
214198
return msg;
215199
}).toList();
216-
notifyListeners();
217-
loadInbox();
200+
201+
if (updated) {
202+
notifyListeners();
203+
loadInbox();
204+
}
218205
}
219206
break;
220207
}
221208
}
209+
210+
List<dynamic> _extractDataList(dynamic data, List<String> fallbackKeys) {
211+
if (data == null) return [];
212+
if (data is List) return data;
213+
if (data is Map) {
214+
if (data['data'] is List) return data['data'];
215+
for (final key in fallbackKeys) {
216+
if (data[key] is List) return data[key];
217+
}
218+
}
219+
return [];
220+
}
222221
}

0 commit comments

Comments
 (0)