Skip to content

Commit a80bf73

Browse files
feat: ✨ Add Pin/Mute Chat Support
1 parent b8ff666 commit a80bf73

File tree

6 files changed

+145
-3
lines changed

6 files changed

+145
-3
lines changed

doc/documentation.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,8 @@ Widget build(BuildContext context) {
172172
| createChat | Creates a one-to-one chat room by specifying the other user's ID and it returns the `chatRoomID`. | `Future<String?>` |
173173
| createGroupChat | Creates a group chat by providing a group name, an optional profile picture, and a list of participants with their assigned roles and it returns the `chatRoomID`. | `Future<String?>` |
174174
| deleteChat | Deletes a chat room by its ID, removing it from the database, all users' chat lists, and deleting associated media from storage. | `Future<bool>` |
175+
| muteChat | Mutes or unmutes a chat room by passing the desired state (e.g., muted for mute, unmuted for unmute). | `Future<void>` |
176+
| pinChat | Pins or unpins a chat room by passing the desired state (e.g., pinned for pin, unpinned for unpin). | `Future<void>` |
175177
| updateUserActiveStatus | Updates a user’s activity status by passing the desired state (e.g., online or offline). | `Future<bool>` |
176178
| resetCurrentUserId | Resets the current user ID | `void` |
177179

@@ -309,6 +311,9 @@ The `chats` collection contains chat room details.
309311
├── membership_status_timestamp: Timestamp (Timestamp of when the membership status changed)
310312
├── role: string (Role of the user in the chat ie: admin/user)
311313
├── typing_status: string (Indicates whether the user is typing ie: typed/typing)
314+
├── pin_status: string (Indicates whether the chat is pinned or not ie: pinned/unpinned)
315+
├── pin_status_timestamp: Timestamp (Timestamp of when the chat is pinned)
316+
├── mute_status: string (Indicates whether the chat is muted or not ie: muted/unmuted)
312317
```
313318

314319
#### User Chats Collection:

lib/src/database/database_service.dart

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -344,6 +344,8 @@ abstract interface class DatabaseService {
344344
/// (e.g., `typing`, `typed`).
345345
/// - (optional): [membershipStatus] The user's membership status in the
346346
/// chat room (e.g., `member`, `removed`, `left`).
347+
/// - (optional): [pinStatus] The pin status of the user in the chat room.
348+
/// - (optional): [muteStatus] The mute status of the user in the chat room.
347349
/// - (optional): [chatRoomUserData] A map containing user data updates.
348350
/// If provided, this data is used to update the document instead of the
349351
/// other individual parameters.
@@ -356,6 +358,8 @@ abstract interface class DatabaseService {
356358
required String userId,
357359
TypeWriterStatus? typingStatus,
358360
MembershipStatus? membershipStatus,
361+
PinStatus? pinStatus,
362+
MuteStatus? muteStatus,
359363
Map<String, dynamic>? chatRoomUserData,
360364
ValueGetter<ChatRoomParticipant>? ifDataNotFound,
361365
});

lib/src/database/firebase/chatview_firestore_database.dart

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,9 @@ final class ChatViewFireStoreDatabase implements DatabaseService {
3838
static const String _membershipStatus = 'membership_status';
3939
static const String _membershipStatusTimestamp =
4040
'membership_status_timestamp';
41+
static const String _pinStatusTimestamp = 'pin_status_timestamp';
42+
static const String _pinStatus = 'pin_status';
43+
static const String _muteStatus = 'mute_status';
4144

4245
FirestoreChatDatabasePathConfig? get _chatDatabasePathConfig =>
4346
ChatViewConnect.instance.getFirestoreChatDatabasePathConfig;
@@ -498,6 +501,8 @@ final class ChatViewFireStoreDatabase implements DatabaseService {
498501
required String userId,
499502
TypeWriterStatus? typingStatus,
500503
MembershipStatus? membershipStatus,
504+
PinStatus? pinStatus,
505+
MuteStatus? muteStatus,
501506
Map<String, dynamic>? chatRoomUserData,
502507
ValueGetter<ChatRoomParticipant>? ifDataNotFound,
503508
}) async {
@@ -509,6 +514,12 @@ final class ChatViewFireStoreDatabase implements DatabaseService {
509514
_membershipStatus: status.name,
510515
_membershipStatusTimestamp: FieldValue.serverTimestamp(),
511516
},
517+
if (pinStatus case final status?) ...{
518+
_pinStatus: status.name,
519+
_pinStatusTimestamp:
520+
pinStatus.isPinned ? FieldValue.serverTimestamp() : null,
521+
},
522+
if (muteStatus case final status?) _muteStatus: status.name,
512523
};
513524

514525
if (data.isEmpty) return;
@@ -1007,6 +1018,9 @@ final class ChatViewFireStoreDatabase implements DatabaseService {
10071018
return unreadMessagesCountStream.map(
10081019
(unreadMessagesCount) => chatRoom.copyWith(
10091020
forceNullValue: true,
1021+
pinnedAt: currentUser?.pinStatusTimestamp,
1022+
muteStatus: currentUser?.muteStatus,
1023+
pinStatus: currentUser?.pinStatus,
10101024
users: otherUsers,
10111025
chatId: chatRoom.chatId,
10121026
groupName: chatRoom.groupName,
@@ -1210,6 +1224,7 @@ final class ChatViewFireStoreDatabase implements DatabaseService {
12101224
role: Role.admin,
12111225
membershipStatusTimestamp: null,
12121226
membershipStatus: membershipStatus,
1227+
pinStatusTimestamp: null,
12131228
),
12141229
);
12151230

@@ -1235,6 +1250,7 @@ final class ChatViewFireStoreDatabase implements DatabaseService {
12351250
membershipStatusTimestamp: null,
12361251
membershipStatus: membershipStatus,
12371252
role: participants[userId] ?? Role.admin,
1253+
pinStatusTimestamp: null,
12381254
),
12391255
),
12401256
],
@@ -1490,6 +1506,7 @@ final class ChatViewFireStoreDatabase implements DatabaseService {
14901506
userId: userId,
14911507
membershipStatus: MembershipStatus.member,
14921508
membershipStatusTimestamp: membershipStatusTime,
1509+
pinStatusTimestamp: null,
14931510
),
14941511
);
14951512

lib/src/manager/chat/chat_manager.dart

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -420,6 +420,40 @@ final class ChatManager extends ChatController {
420420
);
421421
}
422422

423+
/// Pins or unpins a chat in the user's chat list.
424+
/// This method updates the pin status of a chat room
425+
/// for the current user.
426+
///
427+
/// **Parameters:**
428+
/// - (required): [status] The pin status to set for the chat room.
429+
/// - (required): [chatRoomId] The unique identifier of the chat room
430+
/// to pin or unpin.
431+
Future<void> pinChat(PinStatus status, String chatRoomId) {
432+
return _database.updateChatRoomUserMetadata(
433+
userId: _currentUserId,
434+
chatId: chatRoomId,
435+
pinStatus: status,
436+
retry: ChatViewConnectConstants.defaultRetry,
437+
);
438+
}
439+
440+
/// Mutes or unmutes a chat room for the current user.
441+
/// This method updates the mute status of a chat room
442+
/// for the current user.
443+
///
444+
/// **Parameters:**
445+
/// - (required): [status] The mute status to set for the chat room.
446+
/// - (required): [chatRoomId] The unique identifier of the chat room
447+
/// to mute or unmute.
448+
Future<void> muteChat(MuteStatus status, String chatRoomId) {
449+
return _database.updateChatRoomUserMetadata(
450+
userId: _currentUserId,
451+
chatId: chatRoomId,
452+
muteStatus: status,
453+
retry: ChatViewConnectConstants.defaultRetry,
454+
);
455+
}
456+
423457
/// Updates the status of a message to "read" or any other provided status.
424458
///
425459
/// **Parameters:**

lib/src/models/chat_room.dart

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,11 +43,14 @@ class ChatRoom {
4343
required this.chatId,
4444
required this.chatRoomType,
4545
this.unreadMessagesCount = 0,
46+
this.pinStatus = PinStatus.unpinned,
47+
this.muteStatus = MuteStatus.unmuted,
4648
this.groupPhotoUrl,
4749
this.chatRoomCreateBy,
4850
this.lastMessage,
4951
this.groupName,
5052
this.users,
53+
this.pinnedAt,
5154
});
5255

5356
/// Converts a JSON object to a [ChatRoom] instance.
@@ -99,6 +102,15 @@ class ChatRoom {
99102
/// is unavailable.
100103
final String? chatRoomCreateBy;
101104

105+
/// The status of the pin in the chat room for the current user.
106+
final PinStatus pinStatus;
107+
108+
/// The date and time when the chat room was pinned.
109+
final DateTime? pinnedAt;
110+
111+
/// The mute status of the chat room for the current user.
112+
final MuteStatus muteStatus;
113+
102114
/// The number of unread messages in the chat room for the current user.
103115
///
104116
/// **Note:** In the below example,
@@ -222,6 +234,9 @@ class ChatRoom {
222234
List<ChatRoomParticipant>? users,
223235
int? unreadMessagesCount,
224236
String? chatRoomCreateBy,
237+
PinStatus? pinStatus,
238+
DateTime? pinnedAt,
239+
MuteStatus? muteStatus,
225240
bool forceNullValue = false,
226241
}) {
227242
return ChatRoom(
@@ -237,6 +252,9 @@ class ChatRoom {
237252
chatRoomCreateBy: forceNullValue
238253
? chatRoomCreateBy
239254
: chatRoomCreateBy ?? this.chatRoomCreateBy,
255+
pinStatus: pinStatus ?? this.pinStatus,
256+
pinnedAt: forceNullValue ? pinnedAt : pinnedAt ?? this.pinnedAt,
257+
muteStatus: muteStatus ?? this.muteStatus,
240258
);
241259
}
242260

@@ -252,7 +270,10 @@ class ChatRoom {
252270
lastMessage == other.lastMessage &&
253271
users == other.users &&
254272
unreadMessagesCount == other.unreadMessagesCount &&
255-
chatRoomCreateBy == other.chatRoomCreateBy;
273+
chatRoomCreateBy == other.chatRoomCreateBy &&
274+
pinStatus == other.pinStatus &&
275+
pinnedAt == other.pinnedAt &&
276+
muteStatus == other.muteStatus;
256277
}
257278

258279
@override
@@ -266,6 +287,9 @@ class ChatRoom {
266287
users,
267288
unreadMessagesCount,
268289
chatRoomCreateBy,
290+
pinStatus,
291+
pinnedAt,
292+
muteStatus,
269293
);
270294
}
271295

@@ -280,6 +304,9 @@ class ChatRoom {
280304
lastMessage: $lastMessage,
281305
groupName: $groupName,
282306
users: ${users?.map((e) => e.toString()).toList()},
307+
pinStatus: $pinStatus,
308+
pinnedAt: $pinnedAt,
309+
muteStatus: $muteStatus,
283310
)''';
284311
}
285312
}

lib/src/models/chat_room_participant.dart

Lines changed: 57 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,11 @@ class ChatRoomParticipant {
2828
required this.chatUser,
2929
required this.membershipStatus,
3030
required this.membershipStatusTimestamp,
31+
required this.pinStatusTimestamp,
3132
this.userActiveStatus = UserActiveStatus.offline,
3233
this.typingStatus = TypeWriterStatus.typed,
34+
this.pinStatus = PinStatus.unpinned,
35+
this.muteStatus = MuteStatus.unmuted,
3336
});
3437

3538
/// Creates a [ChatRoomParticipant] instance from a JSON map.
@@ -47,6 +50,13 @@ class ChatRoomParticipant {
4750
: createAtJson;
4851
json[_membershipStatusTimestamp] = createAt;
4952

53+
final pinStatusTimestampJson = json[_pinStatusTimestamp];
54+
final pinStatusTimestamp = pinStatusTimestampJson is Timestamp
55+
? pinStatusTimestampJson.toDate().toLocal().toIso8601String()
56+
: pinStatusTimestampJson;
57+
58+
json[_pinStatusTimestamp] = pinStatusTimestamp;
59+
5060
return ChatRoomParticipant(
5161
chatUser: chatUserData is Map<String, dynamic>
5262
? ChatUser.fromJson(
@@ -68,12 +78,23 @@ class ChatRoomParticipant {
6878
membershipStatusTimestamp: DateTime.tryParse(
6979
json[_membershipStatusTimestamp].toString(),
7080
),
81+
pinStatus: PinStatusExtension.parse(
82+
json['pin_status'].toString(),
83+
),
84+
pinStatusTimestamp: DateTime.tryParse(
85+
json[_pinStatusTimestamp].toString(),
86+
),
87+
muteStatus: MuteStatusExtension.parse(
88+
json['mute_status'].toString(),
89+
),
7190
);
7291
}
7392

7493
static const String _membershipStatusTimestamp =
7594
'membership_status_timestamp';
7695

96+
static const String _pinStatusTimestamp = 'pin_status_timestamp';
97+
7798
/// Detailed information about the user in the chat room.
7899
///
79100
/// This can be `null` if no data is available for the user.
@@ -108,6 +129,15 @@ class ChatRoomParticipant {
108129
/// If `null`, the exact time of the status change is unknown.
109130
final DateTime? membershipStatusTimestamp;
110131

132+
/// The status of the pin for the chat room participant.
133+
final PinStatus pinStatus;
134+
135+
/// The timestamp of the last pin status change.
136+
final DateTime? pinStatusTimestamp;
137+
138+
/// The mute status of the chat room participant.
139+
final MuteStatus muteStatus;
140+
111141
/// Converts the [ChatRoomParticipant] instance to a JSON map.
112142
///
113143
/// **Note**: The [chatUser], [userActiveStatus] field is not included in
@@ -133,12 +163,20 @@ class ChatRoomParticipant {
133163
'typing_status': typingStatus.name,
134164
'membership_status': membershipStatus?.name,
135165
_membershipStatusTimestamp: membershipStatusTimestamp?.toIso8601String(),
166+
'pin_status': pinStatus.name,
167+
_pinStatusTimestamp: pinStatusTimestamp?.toIso8601String(),
168+
'mute_status': muteStatus.name,
136169
};
137170
if (membershipStatusTimestamp case final membershipStatusTimestamp?) {
138171
data[_membershipStatusTimestamp] = membershipStatusTimestamp.isNow
139172
? FieldValue.serverTimestamp()
140173
: Timestamp.fromDate(membershipStatusTimestamp);
141174
}
175+
if (pinStatusTimestamp case final pinStatusTimestamp?) {
176+
data[_pinStatusTimestamp] = pinStatusTimestamp.isNow
177+
? FieldValue.serverTimestamp()
178+
: Timestamp.fromDate(pinStatusTimestamp);
179+
}
142180
return data;
143181
}
144182

@@ -153,7 +191,10 @@ class ChatRoomParticipant {
153191
typingStatus == other.typingStatus &&
154192
role == other.role &&
155193
membershipStatus == other.membershipStatus &&
156-
membershipStatusTimestamp == other.membershipStatusTimestamp;
194+
membershipStatusTimestamp == other.membershipStatusTimestamp &&
195+
pinStatus == other.pinStatus &&
196+
pinStatusTimestamp == other.pinStatusTimestamp &&
197+
muteStatus == other.muteStatus;
157198
}
158199

159200
@override
@@ -166,6 +207,9 @@ class ChatRoomParticipant {
166207
userActiveStatus,
167208
membershipStatus,
168209
membershipStatusTimestamp,
210+
pinStatus,
211+
pinStatusTimestamp,
212+
muteStatus,
169213
);
170214
}
171215

@@ -195,6 +239,9 @@ class ChatRoomParticipant {
195239
TypeWriterStatus? typingStatus,
196240
MembershipStatus? membershipStatus,
197241
DateTime? membershipStatusTimestamp,
242+
PinStatus? pinStatus,
243+
DateTime? pinStatusTimestamp,
244+
MuteStatus? muteStatus,
198245
bool forceNullValue = false,
199246
}) {
200247
return ChatRoomParticipant(
@@ -209,6 +256,11 @@ class ChatRoomParticipant {
209256
membershipStatusTimestamp: forceNullValue
210257
? membershipStatusTimestamp
211258
: membershipStatusTimestamp ?? this.membershipStatusTimestamp,
259+
pinStatus: pinStatus ?? this.pinStatus,
260+
pinStatusTimestamp: forceNullValue
261+
? pinStatusTimestamp
262+
: pinStatusTimestamp ?? this.pinStatusTimestamp,
263+
muteStatus: muteStatus ?? this.muteStatus,
212264
);
213265
}
214266

@@ -220,6 +272,9 @@ class ChatRoomParticipant {
220272
'typingStatus: $typingStatus, '
221273
'role: $role, '
222274
'membershipStatus: $membershipStatus, '
223-
'membershipStatusTimestamp: $membershipStatusTimestamp'
275+
'membershipStatusTimestamp: $membershipStatusTimestamp, '
276+
'pinStatus: $pinStatus, '
277+
'pinStatusTimestamp: $pinStatusTimestamp, '
278+
'muteStatus: $muteStatus'
224279
')';
225280
}

0 commit comments

Comments
 (0)