Enhanced UserProfilePage to showcase either own or another user's profile

master
Rafael 2024-06-09 03:01:52 +02:00
parent 98920a4e61
commit 8120ebda3d
7 changed files with 189 additions and 143 deletions

View File

@ -130,6 +130,7 @@ class UserTileChats extends StatelessWidget {
size: 16,
),
const SizedBox(width: 4),
if (msgDateString.isNotEmpty)
Flexible(
child: Text(
msgDateString,

View File

@ -3,17 +3,20 @@ import 'package:flutter/material.dart';
import '../components/chat_bubble.dart';
import '../components/my_textfield.dart';
import '../constants.dart';
import '../services/auth/auth_service.dart';
import '../services/chat/chat_service.dart';
class ChatPage extends StatefulWidget {
final String receiverEmail;
final String receiverID;
final String chatTitle;
const ChatPage({
super.key,
required this.receiverEmail,
required this.receiverID,
required this.chatTitle,
});
@override
@ -88,7 +91,7 @@ class _ChatPageState extends State<ChatPage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text(widget.receiverEmail)),
appBar: AppBar(title: Text(widget.chatTitle)),
body: Column(
children: [
// display all messages
@ -132,12 +135,16 @@ class _ChatPageState extends State<ChatPage> {
Map<String, dynamic> data = doc.data() as Map<String, dynamic>;
// align message to the right if sender is current user, otherwise left
bool isCurrentUser = data['senderID'] == _authService.getCurrentUser()!.uid;
bool isCurrentUser = data[Constants.dbFieldMessageSenderId] ==
_authService.getCurrentUser()!.uid;
var alignment =
isCurrentUser ? Alignment.centerRight : Alignment.centerLeft;
List<String> msgDate =
(data['timestamp'] as Timestamp).toDate().toIso8601String().split("T");
(data[Constants.dbFieldMessageTimestamp] as Timestamp)
.toDate()
.toIso8601String()
.split("T");
return Container(
alignment: alignment,
@ -153,7 +160,7 @@ class _ChatPageState extends State<ChatPage> {
),
),
ChatBubble(
message: data['message'],
message: data[Constants.dbFieldMessageText],
isCurrentUser: isCurrentUser,
),
],

View File

@ -78,6 +78,7 @@ class ConversationsPage extends StatelessWidget {
builder: (context) => ChatPage(
receiverEmail: userData[Constants.dbFieldUsersEmail],
receiverID: userData[Constants.dbFieldUsersID],
chatTitle: userData[Constants.dbFieldUsersName],
),
),
);

View File

@ -7,6 +7,7 @@ import '../enumerations.dart';
import '../models/swipe.dart';
import '../services/auth/auth_service.dart';
import '../utils/helper.dart';
import 'user_profile_page.dart';
class LikedUsersPage extends StatefulWidget {
const LikedUsersPage({super.key});
@ -143,32 +144,6 @@ class LikedUsersPageState extends State<LikedUsersPage> {
return confirm;
}
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'),
),
],
);
},
);
}
List<MapEntry<Swipe, DocumentSnapshot>> _getSortedLikedUsersWithSwipes() {
List<MapEntry<Swipe, DocumentSnapshot>> likedOnlyUsers = [];
List<MapEntry<Swipe, DocumentSnapshot>> matchedUsers = [];
@ -376,7 +351,16 @@ class LikedUsersPageState extends State<LikedUsersPage> {
}
}, //_unlikeUser(user.id),
onShowMatchMessage: _showMatchMessage,
onViewInfo: () => _showUserInfo(user),
onViewInfo: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (BuildContext context) => UserProfilePage(
userId: user.id,
),
),
);
},
);
},
),

View File

@ -257,6 +257,7 @@ class UserMatchingPageState extends State<UserMatchingPage> {
builder: (context) => ChatPage(
receiverEmail: swipedUser.email,
receiverID: swipedUser.uid,
chatTitle: swipedUser.name,
),
),
);
@ -390,9 +391,6 @@ class UserMatchingPageState extends State<UserMatchingPage> {
Widget _buildUserCard(UserProfile userProfile) {
String? profileImageUrl = userProfile.profilePictureUrl;
int age = calcAge(userProfile.born);
String ageInfo = age > 0 ? ' ($age)' : '';
// Sort the languages according to the given order below
List<Language> sortedLanguages = List.from(userProfile.languages);
sortedLanguages.sort((a, b) {
@ -437,7 +435,8 @@ class UserMatchingPageState extends State<UserMatchingPage> {
),
const SizedBox(height: 8),
Center(
child: Text('${userProfile.name}$ageInfo',
child: Text(
'${userProfile.name} ${ageInfo(userProfile.born)}'.trim(),
style: const TextStyle(fontSize: 24)),
),
const SizedBox(height: 8),

View File

@ -15,7 +15,9 @@ import 'user_data_page.dart';
import 'user_vision_page.dart';
class UserProfilePage extends StatefulWidget {
const UserProfilePage({super.key});
const UserProfilePage({super.key, this.userId});
final String? userId;
@override
State<UserProfilePage> createState() => _UserProfilePageState();
@ -25,17 +27,23 @@ class _UserProfilePageState extends State<UserProfilePage> {
String? profileImageUrl; // Track the profile image URL
late UserProfile myData;
bool isLoading = true;
late bool isOwner;
late String _userId;
@override
void initState() {
super.initState();
// Determine the userId to use, then check if user is the current user
_userId = widget.userId ?? FirebaseAuth.instance.currentUser!.uid;
isOwner = (_userId == FirebaseAuth.instance.currentUser!.uid);
// Load user data on initialization
_loadUserData();
}
Future<void> _loadUserData() async {
myData = await UserService.getUserProfileById(
FirebaseAuth.instance.currentUser!.uid);
myData = await UserService.getUserProfileById(_userId);
setState(() {
// Initialize the profile image URL
@ -193,7 +201,7 @@ class _UserProfilePageState extends State<UserProfilePage> {
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('My Profile Information'),
title: Text(isOwner ? 'My Profile Information' : 'Profile Information'),
),
body: isLoading
? const Center(child: CircularProgressIndicator())
@ -204,28 +212,34 @@ class _UserProfilePageState extends State<UserProfilePage> {
children: [
_buildAvatar(context),
const SizedBox(height: 16),
if (isOwner)
Divider(color: Theme.of(context).colorScheme.primary),
const SizedBox(height: 16),
if (isOwner) const SizedBox(height: 16),
_buildLocation(context),
const SizedBox(height: 16),
if (isOwner)
Divider(color: Theme.of(context).colorScheme.primary),
const SizedBox(height: 16),
if (isOwner) const SizedBox(height: 16),
_buildSkills(context),
const SizedBox(height: 16),
if (isOwner)
Divider(color: Theme.of(context).colorScheme.primary),
const SizedBox(height: 16),
if (isOwner) const SizedBox(height: 16),
_buildVision(context),
const SizedBox(height: 16),
if (isOwner)
Divider(color: Theme.of(context).colorScheme.primary),
const SizedBox(height: 16),
if (isOwner) const SizedBox(height: 16),
_buildWorkCulture(context),
const SizedBox(height: 16),
if (isOwner)
Divider(color: Theme.of(context).colorScheme.primary),
const SizedBox(height: 16),
if (isOwner) const SizedBox(height: 16),
_buildRisks(context),
const SizedBox(height: 16),
if (isOwner)
Divider(color: Theme.of(context).colorScheme.primary),
const SizedBox(height: 16),
if (isOwner) const SizedBox(height: 16),
],
),
),
@ -259,6 +273,7 @@ class _UserProfilePageState extends State<UserProfilePage> {
],
),
),
if (isOwner)
Padding(
padding: const EdgeInsets.only(left: 8.0),
child: Align(
@ -326,6 +341,7 @@ class _UserProfilePageState extends State<UserProfilePage> {
],
),
),
if (isOwner)
Padding(
padding: const EdgeInsets.only(left: 8.0),
child: Align(
@ -396,6 +412,7 @@ class _UserProfilePageState extends State<UserProfilePage> {
],
),
),
if (isOwner)
Align(
alignment: Alignment.topRight,
child: OutlinedButton.icon(
@ -463,6 +480,7 @@ class _UserProfilePageState extends State<UserProfilePage> {
],
),
),
if (isOwner)
Align(
alignment: Alignment.topRight,
child: OutlinedButton.icon(
@ -495,6 +513,7 @@ class _UserProfilePageState extends State<UserProfilePage> {
],
),
),
if (isOwner)
Align(
alignment: Alignment.topRight,
child: OutlinedButton.icon(
@ -521,6 +540,7 @@ class _UserProfilePageState extends State<UserProfilePage> {
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (isOwner)
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
@ -550,13 +570,15 @@ class _UserProfilePageState extends State<UserProfilePage> {
),
],
),
const SizedBox(height: 16),
if (isOwner) const SizedBox(height: 16),
if (isOwner)
Text(
'Gender',
style: TextStyle(
color: Theme.of(context).colorScheme.primary,
),
),
if (isOwner)
Text(getDisplayText(myData.gender),
style: const TextStyle(fontSize: 16)),
const SizedBox(height: 16),
@ -597,8 +619,19 @@ class _UserProfilePageState extends State<UserProfilePage> {
}
Widget _buildAvatar(BuildContext context) {
Widget genderIcon = const Icon(null);
if (myData.gender == Gender.male) {
genderIcon = const Padding(
padding: EdgeInsets.only(left: 4.0),
child: Icon(Icons.male, color: Colors.blue),
);
} else if (myData.gender == Gender.female) {
genderIcon = const Icon(Icons.female, color: Colors.pink);
}
return Column(
children: [
if (isOwner)
Align(
alignment: Alignment.bottomRight,
child: OutlinedButton.icon(
@ -618,8 +651,19 @@ class _UserProfilePageState extends State<UserProfilePage> {
: null,
),
const SizedBox(height: 16),
Text(myData.name, style: const TextStyle(fontSize: 24)),
Text(myData.email, style: const TextStyle(fontSize: 16)),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
isOwner
? myData.name
: '${myData.name} ${ageInfo(myData.born)}'.trim(),
style: const TextStyle(fontSize: 24),
),
genderIcon,
],
),
if (isOwner) Text(myData.email, style: const TextStyle(fontSize: 16)),
const SizedBox(height: 32),
Align(
alignment: Alignment.centerLeft,
@ -627,7 +671,7 @@ class _UserProfilePageState extends State<UserProfilePage> {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Short description of yourself',
isOwner ? 'Short description of yourself' : 'Short description',
style: TextStyle(
color: Theme.of(context).colorScheme.primary,
),

View File

@ -10,6 +10,14 @@ int calcAge(int? birthYear) {
return 0;
}
/// Returns the approximate age in parentheses,
/// or an empty string if [birthYear] is the current year or null.
String ageInfo(int? birthYear) {
int age = calcAge(birthYear);
String ageInfo = age > 0 ? '($age)' : '';
return ageInfo;
}
///
/// Convert decimal coordinate to degrees minutes seconds (DMS).
///
@ -45,8 +53,10 @@ double calculateDistance(double lat1, double lon1, double lat2, double lon2) {
final dLon = _degreesToRadians(lon2 - lon1);
final a = sin(dLat / 2) * sin(dLat / 2) +
cos(_degreesToRadians(lat1)) * cos(_degreesToRadians(lat2)) *
sin(dLon / 2) * sin(dLon / 2);
cos(_degreesToRadians(lat1)) *
cos(_degreesToRadians(lat2)) *
sin(dLon / 2) *
sin(dLon / 2);
final c = 2 * atan2(sqrt(a), sqrt(1 - a));
return R * c;