我正在构建一个 Flutter 应用程序,用户可以在其中互相聊天。我已经实现了用户身份验证,并且可以在 Firestore 中存储用户个人资料信息,例如个人资料图像链接和名称。现在,我想在聊天屏幕的AppBar中显示用户的个人资料图片和姓名。要求:
存储个人资料数据:我已将用户个人资料信息(图像链接和名称)存储在 Firestore 中。 检索个人资料数据:我需要检索此数据并将其显示在聊天屏幕的应用栏中。
聊天屏幕 此页面应该在应用栏中显示所选用户的个人资料图片和姓名。
import 'package:flutter/material.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
class ChatScreen extends StatefulWidget {
static const String screenRoute = "ChatScreen";
const ChatScreen({Key? key}) : super(key: key);
@override
State<ChatScreen> createState() => _ChatScreenState();
}
class _ChatScreenState extends State<ChatScreen> {
late User? signedInUser;
TextEditingController _messageController = TextEditingController();
@override
void initState() {
super.initState();
getSignedInUser();
}
void getSignedInUser() {
final user = FirebaseAuth.instance.currentUser;
setState(() {
signedInUser = user;
});
}
Future<void> sendMessage(String message, String receiverEmail) async {
try {
if (signedInUser != null) {
final messageData = {
'message': message,
'senderId': signedInUser!.uid,
'senderEmail': signedInUser!.email,
'receiverEmail': receiverEmail,
'timestamp': Timestamp.now(),
};
await FirebaseFirestore.instance.collection('messages').add(messageData);
_messageController.clear();
}
} catch (e) {
print('Error sending message: $e');
}
}
@override
Widget build(BuildContext context) {
final routeArguments = ModalRoute.of(context)?.settings.arguments as Map<String, String>;
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.blue,
leading: CircleAvatar(
backgroundImage: NetworkImage(routeArguments['imageLink'] ?? ''),
),
title: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(routeArguments['title'] ?? ''),
Text(
'Last seen: ${routeArguments['lastSeen'] ?? ''}',
style: TextStyle(fontSize: 12),
),
],
),
),
body: Column(
children: [
Expanded(
child: StreamBuilder<QuerySnapshot>(
stream: FirebaseFirestore.instance.collection('messages').snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return Center(
child: CircularProgressIndicator(backgroundColor: Colors.blue),
);
}
final messages = snapshot.data!.docs;
return ListView.builder(
itemCount: messages.length,
itemBuilder: (context, index) {
final message = messages[index];
final messageText = message['message'];
final senderId = message['senderId'];
final isMe = signedInUser?.uid == senderId;
return MessageReplay(
sendMessage: messageText,
isMe: isMe,
);
},
);
},
),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
children: [
Expanded(
child: TextField(
controller: _messageController,
decoration: InputDecoration(
hintText: 'Type a message...',
),
),
),
IconButton(
icon: Icon(Icons.send),
onPressed: () {
final message = _messageController.text.trim();
final receiverEmail = routeArguments['email'] ?? '';
if (message.isNotEmpty && receiverEmail.isNotEmpty) {
sendMessage(message, receiverEmail);
}
},
),
],
),
),
],
),
);
}
}
class MessageReplay extends StatelessWidget {
final String sendMessage;
final bool isMe;
const MessageReplay({Key? key, required this.sendMessage, required this.isMe}) : super(key: key);
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(10.0),
child: Column(
crossAxisAlignment: isMe ? CrossAxisAlignment.end : CrossAxisAlignment.start,
children: [
Material(
elevation: 5,
borderRadius: BorderRadius.only(
topLeft: Radius.circular(30),
bottomLeft: isMe ? Radius.circular(30) : Radius.circular(0),
bottomRight: isMe ? Radius.circular(0) : Radius.circular(30),
topRight: Radius.circular(30),
),
color: isMe ? Colors.blue : Colors.white,
child: Padding(
padding: const EdgeInsets.all(12.0),
child: Text(
sendMessage,
style: TextStyle(
fontSize: 15,
color: isMe ? Colors.white : Colors.black,
),
),
),
),
],
),
);
}
}
用户资料页面
import 'dart:io';
import 'package:path/path.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:firebase_storage/firebase_storage.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
import 'package:proguard_86/screens/home_screen.dart'; // Ensure this import is correct
class UserProfile extends StatefulWidget {
static const String screenRoute = "userProfile";
final String email;
const UserProfile({Key? key, required this.email}) : super(key: key);
@override
State<UserProfile> createState() => _UserProfileState();
}
class _UserProfileState extends State<UserProfile> {
File? file;
String? url;
final TextEditingController _nameController = TextEditingController();
var emailcontroller = TextEditingController();
final FirebaseAuth _auth = FirebaseAuth.instance;
Future<void> getImage() async {
final ImagePicker picker = ImagePicker();
final XFile? image = await picker.pickImage(source: ImageSource.gallery);
if (image != null) {
file = File(image.path);
var imageName = basename(image.path);
var refStorage = FirebaseStorage.instance.ref(imageName);
await refStorage.putFile(file!);
url = await refStorage.getDownloadURL();
setState(() {});
}
}
Future<void> saveUserProfile(BuildContext context) async {
String uid = _auth.currentUser!.uid;
if (url != null && _nameController.text.isNotEmpty) {
await FirebaseFirestore.instance
.collection('signup')
.doc(widget.email)
.collection('user_profile')
.doc(uid) // You can use another identifier if needed
.set({
'name': _nameController.text,
'image_link': url,
});
// Navigate to the home screen after saving the profile
Navigator.pushNamed(context, Homescreen.screenroute); // Ensure the correct reference to HomeScreen
} else {
// Handle error, either url or name is not provided
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text("Please provide both name and image."),
backgroundColor: Colors.red,
),
);
}
}
@override
Widget build(BuildContext context) {
//String email=widget.email!;
return Scaffold(
backgroundColor: Colors.red,
appBar: AppBar(
backgroundColor: Colors.red,
title: const Text(
"Profile Info",
style: TextStyle(color: Colors.white),
),
centerTitle: true,
),
body: SingleChildScrollView(
padding: const EdgeInsets.symmetric(horizontal: 20),
child: Column(
children: [
const Text(
"Please provide your name and an optional profile photo",
style: TextStyle(color: Colors.white, fontSize: 12.5),
textAlign: TextAlign.center,
),
const SizedBox(height: 40),
Container(
padding: const EdgeInsets.all(26),
decoration: const BoxDecoration(
shape: BoxShape.circle,
color: Colors.white,
),
child: const Icon(Icons.add_a_photo_rounded),
),
const SizedBox(height: 40),
ElevatedButton(
onPressed: getImage,
child: const Text("Upload Image"),
),
if (url != null)
Image.network(
url!,
width: 100,
height: 100,
fit: BoxFit.fill,
),
Row(
children: [
Expanded(
child: TextFormField(
controller: _nameController,
decoration: const InputDecoration(
hintText: "Type your name here",
),
),
),
const Icon(
Icons.emoji_emotions_outlined,
color: Colors.white,
)
],
),
const SizedBox(height: 20),
ElevatedButton(
onPressed: () => saveUserProfile(context),
child: const Text("Save Profile"),
),
],
),
),
);
}
}
问题:
高效获取数据:是否有更有效的方法来获取用户的个人资料数据并将其显示在AppBar中? 处理错误:我应该如何处理用户数据可能不可用或图像 URL 无效的情况? 更新个人资料:如果用户的个人资料数据发生变化,AppBar 是否会自动更新,还是需要实现额外的逻辑来处理实时更新? UI/UX 最佳实践:是否有我应该考虑在 AppBar 中显示用户个人资料信息的最佳实践?
我需要检索此数据并将其显示在聊天屏幕的 AppBar 中
您可以将虚拟图像上传到 firebase Firestore,然后在聊天屏幕上您可以通过您在 firebase 上上传的虚拟图像的 url 检查用户图像是否为空。
要在 AppBar 中显示用户的个人资料图片和姓名,请创建一行,其中包含用于照片的 CircleAvatar 和用于名称的文本小部件。从数据源(例如 Firebase)检索用户数据并将其传递到 AppBar。这种个性化的触摸改善了用户体验并增强了聊天应用程序的身份。