Added ConversationsPage
parent
97863bff2d
commit
cad532da0b
|
@ -1,4 +1,5 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import '../pages/conversations_page.dart';
|
||||
import '../pages/home_page.dart';
|
||||
import '../pages/user_data_page.dart';
|
||||
import '../pages/settings_page.dart';
|
||||
|
@ -38,7 +39,7 @@ class MyDrawer extends StatelessWidget {
|
|||
Padding(
|
||||
padding: const EdgeInsets.only(left: 25),
|
||||
child: ListTile(
|
||||
title: const Text("Home"),
|
||||
title: const Text('Home'),
|
||||
leading: const Icon(Icons.home),
|
||||
onTap: () {
|
||||
// pop the drawer
|
||||
|
@ -58,7 +59,7 @@ class MyDrawer extends StatelessWidget {
|
|||
Padding(
|
||||
padding: const EdgeInsets.only(left: 25),
|
||||
child: ListTile(
|
||||
title: const Text("Find Matches"),
|
||||
title: const Text('Find Matches'),
|
||||
leading: const Icon(Icons.person_search),
|
||||
onTap: () {
|
||||
// pop the drawer
|
||||
|
@ -79,9 +80,17 @@ class MyDrawer extends StatelessWidget {
|
|||
Padding(
|
||||
padding: const EdgeInsets.only(left: 25),
|
||||
child: ListTile(
|
||||
title: const Text("Conversations"),
|
||||
title: const Text('Chats'),
|
||||
leading: const Icon(Icons.chat),
|
||||
onTap: () {}, // TODO
|
||||
onTap: () {
|
||||
Navigator.pop(context);
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) => ConversationsPage(),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
|
||||
|
@ -107,7 +116,7 @@ class MyDrawer extends StatelessWidget {
|
|||
Padding(
|
||||
padding: const EdgeInsets.only(left: 25),
|
||||
child: ListTile(
|
||||
title: const Text("My Profile Settings"),
|
||||
title: const Text('My Profile Settings'),
|
||||
leading: const Icon(Icons.edit_note),
|
||||
onTap: () {
|
||||
// pop the drawer first, then navigate to destination
|
||||
|
@ -156,7 +165,7 @@ class MyDrawer extends StatelessWidget {
|
|||
Padding(
|
||||
padding: const EdgeInsets.only(left: 25),
|
||||
child: ListTile(
|
||||
title: const Text("About the app"),
|
||||
title: const Text('About the app'),
|
||||
leading: const Icon(Icons.perm_device_info),
|
||||
onTap: () {
|
||||
Navigator.pop(context);
|
||||
|
@ -171,7 +180,7 @@ class MyDrawer extends StatelessWidget {
|
|||
Padding(
|
||||
padding: const EdgeInsets.only(left: 25),
|
||||
child: ListTile(
|
||||
title: const Text("Send feedback"),
|
||||
title: const Text('Send feedback'),
|
||||
leading: const Icon(Icons.sentiment_satisfied_alt),
|
||||
onTap: () {
|
||||
showDialog(
|
||||
|
@ -187,7 +196,7 @@ class MyDrawer extends StatelessWidget {
|
|||
Padding(
|
||||
padding: const EdgeInsets.only(left: 25, bottom: 25),
|
||||
child: ListTile(
|
||||
title: const Text("L O G O U T"),
|
||||
title: const Text('L O G O U T'),
|
||||
leading: const Icon(Icons.logout),
|
||||
onTap: () {
|
||||
Navigator.of(context).pop();
|
||||
|
|
|
@ -0,0 +1,87 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../components/user_tile.dart';
|
||||
import '../constants.dart';
|
||||
import '../services/auth/auth_service.dart';
|
||||
import '../services/user_service.dart';
|
||||
import 'chat_page.dart';
|
||||
|
||||
class ConversationsPage extends StatelessWidget {
|
||||
ConversationsPage({super.key});
|
||||
|
||||
// auth service
|
||||
final AuthService _authService = AuthService();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: const Text('Conversations'),
|
||||
backgroundColor: Colors.transparent,
|
||||
foregroundColor: Colors.grey.shade800,
|
||||
elevation: 0,
|
||||
),
|
||||
body: _buildUserMatchesList(),
|
||||
);
|
||||
}
|
||||
|
||||
// build the list of matches for the current user
|
||||
Widget _buildUserMatchesList() {
|
||||
final currentUser = _authService.getCurrentUser();
|
||||
|
||||
if (currentUser == null) {
|
||||
return const Center(child: Text('Error: User not logged in'));
|
||||
}
|
||||
|
||||
return StreamBuilder<List<Map<String, dynamic>>>(
|
||||
stream: UserService.getMatchedUsersStream(currentUser.uid),
|
||||
builder: (context, snapshot) {
|
||||
// error
|
||||
if (snapshot.hasError) {
|
||||
return Text('Error: ${snapshot.error.toString()}');
|
||||
}
|
||||
|
||||
// loading
|
||||
if (snapshot.connectionState == ConnectionState.waiting) {
|
||||
return const Center(child: CircularProgressIndicator());
|
||||
}
|
||||
|
||||
// return list view
|
||||
if (snapshot.hasData) {
|
||||
final matchedUsers = snapshot.data!;
|
||||
if (matchedUsers.isEmpty) {
|
||||
return const Center(child: Text('No matches yet'));
|
||||
}
|
||||
return ListView(
|
||||
children: matchedUsers
|
||||
.map<Widget>(
|
||||
(userData) => _buildUserListItem(userData, context))
|
||||
.toList(),
|
||||
);
|
||||
} else {
|
||||
return const Center(child: Text('No matches found'));
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
// build individual user list item
|
||||
Widget _buildUserListItem(
|
||||
Map<String, dynamic> userData, BuildContext context) {
|
||||
return UserTile(
|
||||
text: userData[Constants.dbFieldUsersEmail],
|
||||
onTap: () {
|
||||
// tapped on a user -> go to chat page
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) => ChatPage(
|
||||
receiverEmail: userData[Constants.dbFieldUsersEmail],
|
||||
receiverID: userData[Constants.dbFieldUsersID],
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,23 +1,22 @@
|
|||
import 'package:cofounderella/components/my_drawer.dart';
|
||||
import 'package:cofounderella/components/user_tile.dart';
|
||||
import 'package:cofounderella/services/auth/auth_service.dart';
|
||||
import 'package:cofounderella/services/chat/chat_service.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../components/my_drawer.dart';
|
||||
import '../components/user_tile.dart';
|
||||
import '../constants.dart';
|
||||
import '../services/auth/auth_service.dart';
|
||||
import '../services/user_service.dart';
|
||||
import 'chat_page.dart';
|
||||
|
||||
class HomePage extends StatelessWidget {
|
||||
HomePage({super.key});
|
||||
|
||||
// chat and auth service
|
||||
final ChatService _chatService = ChatService();
|
||||
final AuthService _authService = AuthService();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: const Text("Home"),
|
||||
title: const Text('Home'),
|
||||
// TODO appbar style: remove background and set elevation to 0 ?
|
||||
backgroundColor: Colors.transparent,
|
||||
foregroundColor: Colors.grey.shade800,
|
||||
|
@ -31,16 +30,16 @@ class HomePage extends StatelessWidget {
|
|||
// build a list of users except for the current logged in user
|
||||
Widget _buildUserList() {
|
||||
return StreamBuilder(
|
||||
stream: _chatService.getUsersStream(),
|
||||
stream: UserService.getUsersStream(),
|
||||
builder: (context, snapshot) {
|
||||
// error
|
||||
if (snapshot.hasError) {
|
||||
return const Text("Error");
|
||||
return Text('Error: ${snapshot.error.toString()}');
|
||||
}
|
||||
|
||||
//loading
|
||||
if (snapshot.connectionState == ConnectionState.waiting) {
|
||||
return const Text("Loading..");
|
||||
return const Text('Loading..');
|
||||
}
|
||||
|
||||
// return list view
|
||||
|
@ -57,17 +56,18 @@ class HomePage extends StatelessWidget {
|
|||
Widget _buildUserListItem(
|
||||
Map<String, dynamic> userData, BuildContext context) {
|
||||
// display all users except current user
|
||||
if (userData["email"] != _authService.getCurrentUser()!.email) {
|
||||
if (userData[Constants.dbFieldUsersEmail] !=
|
||||
_authService.getCurrentUser()!.email) {
|
||||
return UserTile(
|
||||
text: userData["email"],
|
||||
text: userData[Constants.dbFieldUsersEmail],
|
||||
onTap: () {
|
||||
// tapped on a user -> go to chat page // TODO
|
||||
// tapped on a user -> go to chat page
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) => ChatPage(
|
||||
receiverEmail: userData["email"],
|
||||
receiverID: userData["uid"],
|
||||
receiverEmail: userData[Constants.dbFieldUsersEmail],
|
||||
receiverID: userData[Constants.dbFieldUsersID],
|
||||
),
|
||||
),
|
||||
);
|
||||
|
|
|
@ -31,8 +31,11 @@ class RegisterPage extends StatelessWidget {
|
|||
.signUpWithEmailPassword(
|
||||
_emailController.text, _passwordController.text)
|
||||
.then((userCredential) {
|
||||
UserService.saveUserData(userCredential, _emailController.text,
|
||||
_nameController.text, _lastnameController.text);
|
||||
UserService.saveUserRegistrationData(
|
||||
userCredential,
|
||||
_emailController.text,
|
||||
_nameController.text,
|
||||
_lastnameController.text);
|
||||
});
|
||||
} on FirebaseAuthException catch (e) {
|
||||
if (context.mounted) {
|
||||
|
|
|
@ -10,22 +10,6 @@ class ChatService {
|
|||
final FirebaseFirestore _firestore = FirebaseFirestore.instance;
|
||||
final FirebaseAuth _auth = FirebaseAuth.instance;
|
||||
|
||||
// get user stream
|
||||
Stream<List<Map<String, dynamic>>> getUsersStream() {
|
||||
return _firestore
|
||||
.collection(Constants.dbCollectionUsers)
|
||||
.snapshots()
|
||||
.map((snapshot) {
|
||||
return snapshot.docs.map((doc) {
|
||||
// iterate each user
|
||||
final user = doc.data();
|
||||
|
||||
//return user
|
||||
return user;
|
||||
}).toList();
|
||||
});
|
||||
}
|
||||
|
||||
// send message
|
||||
Future<void> sendMessage(String receiverID, message) async {
|
||||
// get current user info
|
||||
|
@ -61,7 +45,7 @@ class ChatService {
|
|||
.collection(Constants.dbCollectionChatRooms)
|
||||
.doc(chatRoomID)
|
||||
.collection(Constants.dbCollectionMessages)
|
||||
.orderBy("timestamp", descending: false)
|
||||
.orderBy('timestamp', descending: false)
|
||||
.snapshots();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,8 +9,8 @@ import '../models/user_profile.dart';
|
|||
class UserService {
|
||||
UserService._(); // Private constructor to prevent instantiation
|
||||
|
||||
static Future<void> saveUserData(UserCredential userCredential, String email,
|
||||
String firstname, String lastname) async {
|
||||
static Future<void> saveUserRegistrationData(UserCredential userCredential,
|
||||
String email, String firstname, String lastname) async {
|
||||
// create full name
|
||||
String fullName = (firstname.isNotEmpty && lastname.isNotEmpty)
|
||||
? '$firstname $lastname'
|
||||
|
@ -151,4 +151,71 @@ class UserService {
|
|||
|
||||
return userProfile;
|
||||
}
|
||||
|
||||
// get users stream
|
||||
static Stream<List<Map<String, dynamic>>> getUsersStream() {
|
||||
return FirebaseFirestore.instance
|
||||
.collection(Constants.dbCollectionUsers)
|
||||
.snapshots()
|
||||
.map((snapshot) {
|
||||
return snapshot.docs.map((doc) {
|
||||
// iterate each user
|
||||
final user = doc.data();
|
||||
|
||||
//return user
|
||||
return user;
|
||||
}).toList();
|
||||
});
|
||||
}
|
||||
|
||||
// Get list of matched user ids for a given user
|
||||
static Future<List<String>> getMatchedUserIds(String userId) async {
|
||||
List<String> matchedUserIds = [];
|
||||
|
||||
final snapshot = await FirebaseFirestore.instance
|
||||
.collection(Constants.dbCollectionUsers)
|
||||
.doc(userId)
|
||||
.collection(Constants.dbCollectionMatches)
|
||||
.get();
|
||||
|
||||
for (var doc in snapshot.docs) {
|
||||
final data = doc.data();
|
||||
final otherUserId = data['otherUserId'] as String?;
|
||||
if (otherUserId != null && otherUserId.isNotEmpty) {
|
||||
matchedUserIds.add(otherUserId);
|
||||
}
|
||||
// assuming the match document ID is the matched user's ID
|
||||
// it would just be an one liner:
|
||||
// matchedUserIds.add(doc.id);
|
||||
}
|
||||
|
||||
return matchedUserIds;
|
||||
}
|
||||
|
||||
// Get matched users data for a given user as stream
|
||||
static Stream<List<Map<String, dynamic>>> getMatchedUsersStream(
|
||||
String userId) {
|
||||
return FirebaseFirestore.instance
|
||||
.collection(Constants.dbCollectionUsers)
|
||||
.doc(userId)
|
||||
.collection(Constants.dbCollectionMatches)
|
||||
.snapshots()
|
||||
.asyncMap((snapshot) async {
|
||||
final matchedUserIds = snapshot.docs
|
||||
.map((doc) => doc.data()['otherUserId'] as String?)
|
||||
.where((otherUserId) => otherUserId != null && otherUserId.isNotEmpty)
|
||||
.toList();
|
||||
|
||||
if (matchedUserIds.isEmpty) {
|
||||
return [];
|
||||
}
|
||||
|
||||
final matchedUsersSnapshot = await FirebaseFirestore.instance
|
||||
.collection(Constants.dbCollectionUsers)
|
||||
.where(FieldPath.documentId, whereIn: matchedUserIds)
|
||||
.get();
|
||||
|
||||
return matchedUsersSnapshot.docs.map((doc) => doc.data()).toList();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue