cofounderella/lib/pages/liked_users_page.dart

307 lines
10 KiB
Dart

import 'package:flutter/material.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import '../components/user_tile_likes.dart';
import '../constants.dart';
import '../services/auth/auth_service.dart';
import '../utils/helper.dart';
enum MenuSort { nameAsc, nameDesc, timestampAsc, timestampDesc }
enum ViewOrder { swipedFirst, matchedFirst }
class LikedUsersPage extends StatefulWidget {
const LikedUsersPage({super.key});
@override
LikedUsersPageState createState() => LikedUsersPageState();
}
class LikedUsersPageState extends State<LikedUsersPage> {
final String currentUserId = AuthService().getCurrentUser()!.uid;
ViewOrder _orderPreference = ViewOrder.swipedFirst;
MenuSort _sortPreference = MenuSort.nameAsc;
Future<List<DocumentSnapshot>> _fetchLikedUsers() async {
QuerySnapshot likedUsersSnapshot = await FirebaseFirestore.instance
.collection(Constants.dbCollectionUsers)
.doc(currentUserId)
.collection(Constants.dbCollectionSwipes)
.where('liked', isEqualTo: true)
.get();
List<String> likedUserIds =
likedUsersSnapshot.docs.map((doc) => doc.id).toList();
List<DocumentSnapshot> likedUsers = [];
for (String userId in likedUserIds) {
DocumentSnapshot userDoc = await FirebaseFirestore.instance
.collection(Constants.dbCollectionUsers)
.doc(userId)
.get();
likedUsers.add(userDoc);
}
return likedUsers;
}
Future<bool> _hasMatch(String userId) async {
DocumentSnapshot matchDoc = await FirebaseFirestore.instance
.collection(Constants.dbCollectionUsers)
.doc(currentUserId)
.collection(Constants.dbCollectionMatches)
.doc(userId)
.get();
return matchDoc.exists;
}
Future<void> _unlikeUser(String userId) async {
try {
await FirebaseFirestore.instance
.collection(Constants.dbCollectionUsers)
.doc(currentUserId)
.collection(Constants.dbCollectionSwipes)
.doc(userId)
.delete(); //.update({'liked': false});
setState(() {}); // Refresh the UI
} catch (e) {
showMsg(context, 'Error unlike', e.toString());
}
}
void _showMatchMessage() {
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: const Text('Match Exists'),
content: const Text(
'You cannot unlike a user with whom you have a match.',
),
actions: [
TextButton(
onPressed: () => Navigator.of(context).pop(),
child: const Text('Close'),
),
],
);
},
);
}
Future<void> _showConfirmationDialog(String userId, String userName) async {
bool? confirm = await showDialog<bool>(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: const Text('Confirm Unlike'),
content: Text('Are you sure you want to unlike $userName?'),
actions: [
TextButton(
onPressed: () => Navigator.of(context).pop(false),
child: const Text('Cancel'),
),
TextButton(
onPressed: () => Navigator.of(context).pop(true),
child: const Text('Confirm'),
),
],
);
},
);
if (confirm == true) {
await _unlikeUser(userId);
}
}
void _showUserInfo(DocumentSnapshot user) {
Map<String, dynamic> userMap = user.data() as Map<String, dynamic>;
bool hasName = userMap.containsKey(Constants.dbFieldUsersName);
bool hasBio = userMap.containsKey(Constants.dbFieldUsersBio);
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: hasName
? Text(user[Constants.dbFieldUsersName])
: const Text('Name: n/a'),
content: hasBio
? Text(user[Constants.dbFieldUsersBio])
: const Text('Bio: n/a'),
actions: [
TextButton(
onPressed: () => Navigator.of(context).pop(),
child: const Text('Close'),
),
],
);
},
);
}
Future<List<DocumentSnapshot>> _fetchSortedLikedUsers() async {
List<DocumentSnapshot> likedUsers = await _fetchLikedUsers();
List<DocumentSnapshot> likedOnlyUsers = [];
List<DocumentSnapshot> matchedUsers = [];
for (DocumentSnapshot user in likedUsers) {
bool hasMatch = await _hasMatch(user.id);
if (hasMatch) {
matchedUsers.add(user);
} else {
likedOnlyUsers.add(user);
}
}
if (_sortPreference == MenuSort.nameAsc) {
likedOnlyUsers.sort((a, b) => (a[Constants.dbFieldUsersName] as String)
.compareTo(b[Constants.dbFieldUsersName] as String));
matchedUsers.sort((a, b) => (a[Constants.dbFieldUsersName] as String)
.compareTo(b[Constants.dbFieldUsersName] as String));
} else if (_sortPreference == MenuSort.nameDesc) {
likedOnlyUsers.sort((a, b) => (b[Constants.dbFieldUsersName] as String)
.compareTo(a[Constants.dbFieldUsersName] as String));
matchedUsers.sort((a, b) => (b[Constants.dbFieldUsersName] as String)
.compareTo(a[Constants.dbFieldUsersName] as String));
}
if (_orderPreference == ViewOrder.swipedFirst) {
return [...likedOnlyUsers, ...matchedUsers];
} else {
return [...matchedUsers, ...likedOnlyUsers];
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Liked Users'),
),
body: Column(
children: [
Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
DropdownButton<ViewOrder>(
value: _orderPreference,
items: const [
DropdownMenuItem(
value: ViewOrder.swipedFirst,
child: Text('Swiped First')),
DropdownMenuItem(
value: ViewOrder.matchedFirst,
child: Text('Matched First')),
],
onChanged: (value) {
// update UI on change only
if (_orderPreference != value) {
setState(() {
_orderPreference = value!;
});
}
},
),
Align(
alignment: Alignment.centerRight,
child: PopupMenuButton<MenuSort>(
icon: const Icon(Icons.sort),
onSelected: (MenuSort item) {
// update UI on change only
if (_sortPreference != item) {
setState(() {
_sortPreference = item;
});
}
},
itemBuilder: (BuildContext context) =>
<PopupMenuEntry<MenuSort>>[
PopupMenuItem<MenuSort>(
value: MenuSort.nameAsc,
child: ListTile(
leading: _sortPreference == MenuSort.nameAsc
? const Icon(Icons.check)
: const Icon(null),
title: const Text('Name Ascending'),
),
),
PopupMenuItem<MenuSort>(
value: MenuSort.nameDesc,
child: ListTile(
leading: _sortPreference == MenuSort.nameDesc
? const Icon(Icons.check)
: const Icon(null),
title: const Text('Name Descending'),
),
),
],
),
),
],
),
),
buildLikedUserList(),
],
),
);
}
Widget buildLikedUserList() {
return Expanded(
child: FutureBuilder<List<DocumentSnapshot>>(
future: _fetchSortedLikedUsers(),
builder: (BuildContext context,
AsyncSnapshot<List<DocumentSnapshot>> snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return const Center(child: CircularProgressIndicator());
} else if (snapshot.hasError) {
return Center(child: Text('Error: ${snapshot.error}'));
} else if (!snapshot.hasData || snapshot.data!.isEmpty) {
return const Center(child: Text('No liked users found.'));
} else {
return ListView.builder(
itemCount: snapshot.data!.length,
itemBuilder: (BuildContext context, int index) {
DocumentSnapshot user = snapshot.data![index];
return FutureBuilder<bool>(
future: _hasMatch(user.id),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return const CircularProgressIndicator();
}
bool hasMatch = snapshot.data ?? false;
return UserTileLikes(
user: user,
hasMatch: hasMatch,
onUnlike: () {
Map<String, dynamic> userMap =
user.data() as Map<String, dynamic>;
bool hasName =
userMap.containsKey(Constants.dbFieldUsersName);
_showConfirmationDialog(
user.id,
(hasName
? user[Constants.dbFieldUsersName]
: 'Name: n/a'),
);
}, //_unlikeUser(user.id),
onShowMatchMessage: _showMatchMessage,
onViewInfo: () => _showUserInfo(user),
);
},
);
},
);
}
},
),
);
}
}