-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #4 from ArslanYousaf12/admin-role
group chat module ADDED
- Loading branch information
Showing
16 changed files
with
367 additions
and
14 deletions.
There are no files selected for viewing
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
import 'package:cloud_firestore/cloud_firestore.dart'; | ||
import 'package:flutter_riverpod/flutter_riverpod.dart'; | ||
import 'package:home_front_pk/src/features/chat_section/domain/chat_model.dart'; | ||
|
||
class ChatRepository { | ||
final FirebaseFirestore _firestore; | ||
|
||
ChatRepository({required FirebaseFirestore firestore}) | ||
: _firestore = firestore; | ||
|
||
Future<void> sendMessage(ChatMessage message) async { | ||
await _firestore.collection('chats').add(message.toMap()); | ||
} | ||
|
||
Stream<List<ChatMessage>> getChatMessages() { | ||
return _firestore | ||
.collection('chats') | ||
.orderBy('timestamp', descending: true) | ||
.snapshots() | ||
.map((snapshot) => | ||
snapshot.docs.map((doc) => ChatMessage.fromDoc(doc)).toList()); | ||
} | ||
} | ||
|
||
// Provider for ChatRepository | ||
final chatRepositoryProvider = Provider<ChatRepository>((ref) { | ||
return ChatRepository(firestore: FirebaseFirestore.instance); | ||
}); | ||
// Provider for sending a chat message | ||
final sendMessageProvider = | ||
FutureProvider.family<void, ChatMessage>((ref, message) async { | ||
final repo = ref.watch(chatRepositoryProvider); | ||
await repo.sendMessage(message); | ||
}); | ||
|
||
// Provider for streaming chat messages | ||
final getMessagesProvider = StreamProvider<List<ChatMessage>>((ref) { | ||
final repo = ref.watch(chatRepositoryProvider); | ||
return repo.getChatMessages(); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
import 'package:cloud_firestore/cloud_firestore.dart'; | ||
|
||
class ChatMessage { | ||
final String id; | ||
final String senderId; // The ID of the user sending the message | ||
final String content; // The message content | ||
final DateTime timestamp; // The timestamp of the message | ||
|
||
ChatMessage({ | ||
required this.id, | ||
required this.senderId, | ||
required this.content, | ||
required this.timestamp, | ||
}); | ||
|
||
Map<String, dynamic> toMap() { | ||
return { | ||
'id': id, | ||
'senderId': senderId, | ||
'content': content, | ||
'timestamp': timestamp, | ||
}; | ||
} | ||
|
||
factory ChatMessage.fromDoc(DocumentSnapshot doc) { | ||
return ChatMessage( | ||
id: doc.id, | ||
senderId: doc['senderId'] as String, | ||
content: doc['content'] as String, | ||
timestamp: (doc['timestamp'] as Timestamp).toDate(), | ||
); | ||
} | ||
} |
37 changes: 37 additions & 0 deletions
37
lib/src/features/chat_section/presentation/chat_controller.dart
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
import 'package:home_front_pk/src/features/chat_section/data/chat_repository.dart'; | ||
import 'package:home_front_pk/src/features/chat_section/domain/chat_model.dart'; | ||
import 'package:riverpod_annotation/riverpod_annotation.dart'; | ||
|
||
import 'package:home_front_pk/src/common_widgets/notifier_mounted.dart'; | ||
|
||
part 'chat_controller.g.dart'; | ||
|
||
@riverpod | ||
class ChatController extends _$ChatController with NotifierMounted { | ||
@override | ||
FutureOr<List<ChatMessage>?> build() { | ||
ref.onDispose(setUnmounted); | ||
return null; | ||
} | ||
|
||
Future<void> sendMessage(ChatMessage message) async { | ||
state = const AsyncLoading(); | ||
final result = await AsyncValue.guard( | ||
() => ref.read(chatRepositoryProvider).sendMessage(message), | ||
); | ||
|
||
if (result.hasError) { | ||
state = AsyncError(result.error!, result.stackTrace!); | ||
return; | ||
} | ||
|
||
if (mounted) { | ||
// Add the new message to the current state | ||
state = AsyncData([...state.value ?? [], message]); | ||
} | ||
} | ||
|
||
Stream<List<ChatMessage>> getChatMessages() { | ||
return ref.read(chatRepositoryProvider).getChatMessages(); | ||
} | ||
} |
26 changes: 26 additions & 0 deletions
26
lib/src/features/chat_section/presentation/chat_controller.g.dart
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
182 changes: 182 additions & 0 deletions
182
lib/src/features/chat_section/presentation/chat_screen.dart
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,182 @@ | ||
import 'package:flutter/material.dart'; | ||
import 'package:flutter_riverpod/flutter_riverpod.dart'; | ||
import 'package:firebase_auth/firebase_auth.dart'; // Add this import to handle Firebase Authentication | ||
import 'package:home_front_pk/src/features/chat_section/data/chat_repository.dart'; | ||
import 'package:home_front_pk/src/features/chat_section/domain/chat_model.dart'; | ||
|
||
class ChatScreen extends ConsumerStatefulWidget { | ||
@override | ||
_ChatScreenState createState() => _ChatScreenState(); | ||
} | ||
|
||
class _ChatScreenState extends ConsumerState<ChatScreen> { | ||
final TextEditingController _messageController = TextEditingController(); | ||
late final String currentUserId; // Correctly handle currentUserId | ||
late final String currentUserName; | ||
|
||
@override | ||
void initState() { | ||
super.initState(); | ||
final user = FirebaseAuth | ||
.instance.currentUser; // Get the current user from FirebaseAuth | ||
if (user != null) { | ||
currentUserId = user.uid; // Set the currentUserId from Firebase Auth | ||
currentUserName = user.email ?? | ||
'Unknown'; // You can use email as the name or fetch a displayName | ||
} else { | ||
// Handle the case where the user is not logged in | ||
currentUserId = 'unknown'; | ||
currentUserName = 'unknown'; | ||
} | ||
} | ||
|
||
@override | ||
Widget build(BuildContext context) { | ||
final chatMessagesAsync = ref.watch(getMessagesProvider); | ||
|
||
return Scaffold( | ||
appBar: AppBar( | ||
title: Text('Group Chat'), | ||
), | ||
body: Column( | ||
children: [ | ||
Expanded( | ||
child: chatMessagesAsync.when( | ||
data: (messages) { | ||
return ListView.builder( | ||
reverse: true, | ||
itemCount: messages.length, | ||
itemBuilder: (context, index) { | ||
final message = messages[index]; | ||
final isCurrentUser = message.senderId == currentUserId; | ||
|
||
return Align( | ||
alignment: isCurrentUser | ||
? Alignment.centerRight | ||
: Alignment.centerLeft, | ||
child: Container( | ||
margin: | ||
EdgeInsets.symmetric(vertical: 8, horizontal: 16), | ||
padding: | ||
EdgeInsets.symmetric(vertical: 12, horizontal: 16), | ||
decoration: BoxDecoration( | ||
color: isCurrentUser | ||
? Color.fromARGB(255, 96, 191, | ||
143) // Use blue for the current user | ||
: Colors | ||
.grey.shade300, // Use grey for other users | ||
borderRadius: BorderRadius.only( | ||
topLeft: Radius.circular(16), | ||
topRight: Radius.circular(16), | ||
bottomLeft: isCurrentUser | ||
? Radius.circular(16) | ||
: Radius.zero, | ||
bottomRight: isCurrentUser | ||
? Radius.zero | ||
: Radius.circular(16), | ||
), | ||
), | ||
child: Column( | ||
crossAxisAlignment: CrossAxisAlignment.start, | ||
children: [ | ||
Text( | ||
isCurrentUser | ||
? 'You' | ||
: 'Anonymous', // Use 'You' or the sender ID/name | ||
style: TextStyle( | ||
fontWeight: FontWeight.bold, | ||
color: | ||
isCurrentUser ? Colors.white : Colors.black, | ||
), | ||
), | ||
SizedBox(height: 5), | ||
Text( | ||
message.content, | ||
style: TextStyle( | ||
color: | ||
isCurrentUser ? Colors.white : Colors.black, | ||
), | ||
), | ||
SizedBox(height: 5), | ||
Align( | ||
alignment: Alignment.bottomRight, | ||
child: Text( | ||
message.timestamp | ||
.toLocal() | ||
.toString() | ||
.split(' ')[1], | ||
style: TextStyle( | ||
color: isCurrentUser | ||
? Colors.white70 | ||
: Colors.black54, | ||
fontSize: 12, | ||
), | ||
), | ||
), | ||
], | ||
), | ||
), | ||
); | ||
}, | ||
); | ||
}, | ||
loading: () => Center(child: CircularProgressIndicator()), | ||
error: (error, stack) => Center(child: Text('Error: $error')), | ||
), | ||
), | ||
Padding( | ||
padding: const EdgeInsets.all(16.0), | ||
child: Row( | ||
children: [ | ||
Expanded( | ||
child: TextField( | ||
controller: _messageController, | ||
decoration: InputDecoration( | ||
hintText: 'Enter message', | ||
border: OutlineInputBorder( | ||
borderRadius: BorderRadius.circular(24), | ||
), | ||
filled: true, | ||
fillColor: Colors.white, | ||
contentPadding: | ||
EdgeInsets.symmetric(vertical: 12, horizontal: 16), | ||
), | ||
), | ||
), | ||
SizedBox(width: 16), | ||
ElevatedButton.icon( | ||
icon: Icon(Icons.send), | ||
label: Text('Send'), | ||
onPressed: () { | ||
if (_messageController.text.trim().isNotEmpty) { | ||
final message = ChatMessage( | ||
id: '', | ||
senderId: currentUserId, // Send correct current user ID | ||
content: _messageController.text.trim(), | ||
timestamp: DateTime.now(), | ||
); | ||
ref.read(sendMessageProvider(message).future); | ||
_messageController.clear(); | ||
} | ||
}, | ||
style: ElevatedButton.styleFrom( | ||
shape: RoundedRectangleBorder( | ||
borderRadius: BorderRadius.circular(24), | ||
), | ||
padding: EdgeInsets.symmetric(vertical: 12, horizontal: 16), | ||
), | ||
), | ||
], | ||
), | ||
), | ||
], | ||
), | ||
); | ||
} | ||
|
||
@override | ||
void dispose() { | ||
_messageController.dispose(); | ||
super.dispose(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.