2024-05-30 01:10:53 +02:00
|
|
|
import 'package:flutter/material.dart';
|
|
|
|
import 'package:cloud_firestore/cloud_firestore.dart';
|
|
|
|
import 'package:firebase_auth/firebase_auth.dart';
|
|
|
|
import 'package:firebase_storage/firebase_storage.dart';
|
|
|
|
import 'package:image_picker/image_picker.dart';
|
|
|
|
import 'dart:io';
|
|
|
|
|
|
|
|
import '../constants.dart';
|
2024-05-30 16:37:34 +02:00
|
|
|
import '../models/user_profile.dart';
|
2024-05-30 01:10:53 +02:00
|
|
|
|
|
|
|
class EditProfilePage extends StatefulWidget {
|
2024-05-30 16:37:34 +02:00
|
|
|
final UserProfile userData;
|
2024-05-30 01:10:53 +02:00
|
|
|
|
|
|
|
const EditProfilePage({super.key, required this.userData});
|
|
|
|
|
|
|
|
@override
|
|
|
|
EditProfilePageState createState() => EditProfilePageState();
|
|
|
|
}
|
|
|
|
|
|
|
|
class EditProfilePageState extends State<EditProfilePage> {
|
|
|
|
final _formKey = GlobalKey<FormState>();
|
|
|
|
late TextEditingController _nameController;
|
|
|
|
late TextEditingController _bioController;
|
|
|
|
late String? profileImageUrl;
|
|
|
|
File? _profileImage;
|
|
|
|
|
|
|
|
@override
|
|
|
|
void initState() {
|
|
|
|
super.initState();
|
2024-05-30 16:37:34 +02:00
|
|
|
_nameController = TextEditingController(text: widget.userData.name);
|
|
|
|
_bioController = TextEditingController(text: widget.userData.bio);
|
|
|
|
if (widget.userData.profilePictureUrl != null) {
|
|
|
|
profileImageUrl = widget.userData.profilePictureUrl;
|
2024-05-30 01:10:53 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Future<void> _pickImage() async {
|
|
|
|
final pickedFile =
|
|
|
|
await ImagePicker().pickImage(source: ImageSource.gallery);
|
|
|
|
if (pickedFile != null) {
|
|
|
|
setState(() {
|
|
|
|
_profileImage = File(pickedFile.path);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void _clearProfileImage() {
|
|
|
|
setState(() {
|
|
|
|
_profileImage = null;
|
2024-05-30 16:37:34 +02:00
|
|
|
profileImageUrl = null;
|
|
|
|
widget.userData.profilePictureUrl = null;
|
2024-05-30 01:10:53 +02:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
Future<void> _saveProfile() async {
|
2024-05-30 16:37:34 +02:00
|
|
|
String nameTrim = _nameController.text.trim();
|
|
|
|
String bioTrim = _bioController.text.trim();
|
|
|
|
|
2024-05-30 01:10:53 +02:00
|
|
|
if (_formKey.currentState!.validate()) {
|
|
|
|
String uid = FirebaseAuth.instance.currentUser!.uid;
|
|
|
|
|
|
|
|
if (_profileImage != null) {
|
|
|
|
final storageRef = FirebaseStorage.instance
|
|
|
|
.ref()
|
|
|
|
.child(Constants.dbStoragePathProfiles)
|
|
|
|
.child(uid); // filename = userid
|
|
|
|
await storageRef.putFile(_profileImage!);
|
|
|
|
profileImageUrl = await storageRef.getDownloadURL();
|
|
|
|
}
|
|
|
|
|
2024-05-30 16:37:34 +02:00
|
|
|
Map<String, dynamic> resultValues = {
|
|
|
|
Constants.dbFieldUsersName: nameTrim,
|
|
|
|
Constants.dbFieldUsersBio: bioTrim,
|
|
|
|
Constants.dbFieldUsersProfilePic: profileImageUrl,
|
|
|
|
};
|
2024-05-30 01:10:53 +02:00
|
|
|
|
|
|
|
await FirebaseFirestore.instance
|
|
|
|
.collection(Constants.dbCollectionUsers)
|
|
|
|
.doc(uid)
|
2024-05-30 16:37:34 +02:00
|
|
|
.update(resultValues);
|
2024-05-30 01:10:53 +02:00
|
|
|
|
2024-05-30 16:37:34 +02:00
|
|
|
_close(resultValues);
|
2024-05-30 01:10:53 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-05-30 16:37:34 +02:00
|
|
|
/// close this page and return selected values
|
|
|
|
void _close(Map<String, dynamic> map) {
|
|
|
|
Navigator.pop(context, {
|
|
|
|
Constants.dbFieldUsersProfilePic: map[Constants.dbFieldUsersProfilePic],
|
|
|
|
Constants.dbFieldUsersName: map[Constants.dbFieldUsersName],
|
|
|
|
Constants.dbFieldUsersBio: map[Constants.dbFieldUsersBio],
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2024-05-30 01:10:53 +02:00
|
|
|
@override
|
|
|
|
Widget build(BuildContext context) {
|
|
|
|
return Scaffold(
|
|
|
|
appBar: AppBar(
|
|
|
|
title: const Text('Edit Profile'),
|
|
|
|
),
|
|
|
|
body: Padding(
|
|
|
|
padding: const EdgeInsets.all(16.0),
|
|
|
|
child: Form(
|
|
|
|
key: _formKey,
|
|
|
|
child: ListView(
|
|
|
|
children: [
|
|
|
|
Center(
|
|
|
|
child: Row(
|
|
|
|
mainAxisAlignment: MainAxisAlignment.center,
|
|
|
|
crossAxisAlignment: CrossAxisAlignment.end,
|
|
|
|
children: [
|
2024-05-30 16:37:34 +02:00
|
|
|
buildAvatar(context),
|
|
|
|
if (_profileImage != null ||
|
|
|
|
widget.userData.profilePictureUrl != null)
|
2024-05-30 01:10:53 +02:00
|
|
|
IconButton(
|
|
|
|
icon: Ink(
|
|
|
|
decoration: const ShapeDecoration(
|
|
|
|
shape: CircleBorder(),
|
|
|
|
),
|
|
|
|
child: const Icon(
|
|
|
|
Icons.delete,
|
|
|
|
color: Colors.red,
|
|
|
|
size: 32,
|
|
|
|
),
|
|
|
|
),
|
|
|
|
onPressed: _clearProfileImage,
|
|
|
|
),
|
|
|
|
],
|
|
|
|
),
|
|
|
|
),
|
|
|
|
const SizedBox(height: 16),
|
|
|
|
TextFormField(
|
|
|
|
controller: _nameController,
|
|
|
|
decoration: const InputDecoration(labelText: 'Name'),
|
|
|
|
validator: (value) {
|
2024-05-30 16:37:34 +02:00
|
|
|
if (value == null || value.trim().isEmpty) {
|
2024-05-30 01:10:53 +02:00
|
|
|
return 'Please enter a name';
|
|
|
|
}
|
|
|
|
return null;
|
|
|
|
},
|
|
|
|
),
|
|
|
|
const SizedBox(height: 16),
|
|
|
|
TextFormField(
|
|
|
|
controller: _bioController,
|
|
|
|
decoration: const InputDecoration(labelText: 'Bio'),
|
|
|
|
maxLines: 3,
|
2024-05-30 16:37:34 +02:00
|
|
|
maxLength: 4096,
|
2024-05-30 01:10:53 +02:00
|
|
|
),
|
|
|
|
const SizedBox(height: 16),
|
|
|
|
ElevatedButton(
|
|
|
|
onPressed: _saveProfile,
|
|
|
|
child: const Text('Save'),
|
|
|
|
),
|
|
|
|
],
|
|
|
|
),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
);
|
|
|
|
}
|
2024-05-30 16:37:34 +02:00
|
|
|
|
|
|
|
Widget buildAvatar(BuildContext context) {
|
|
|
|
return GestureDetector(
|
|
|
|
onTap: _pickImage,
|
|
|
|
child: Stack(
|
|
|
|
children: [
|
|
|
|
CircleAvatar(
|
|
|
|
radius: 50,
|
|
|
|
backgroundImage: _profileImage != null
|
|
|
|
? FileImage(_profileImage!) as ImageProvider
|
|
|
|
: (widget.userData.profilePictureUrl != null
|
|
|
|
? NetworkImage(widget.userData.profilePictureUrl!)
|
|
|
|
as ImageProvider
|
|
|
|
: null),
|
|
|
|
child: ClipOval(
|
|
|
|
child: _profileImage == null &&
|
|
|
|
widget.userData.profilePictureUrl == null
|
|
|
|
? const Icon(Icons.person, size: 50)
|
|
|
|
: SizedBox(
|
|
|
|
width: 100,
|
|
|
|
height: 100,
|
|
|
|
child: _profileImage != null
|
|
|
|
? Image.file(
|
|
|
|
_profileImage!,
|
|
|
|
fit: BoxFit.cover,
|
|
|
|
)
|
|
|
|
: (widget.userData.profilePictureUrl != null
|
|
|
|
? Image.network(
|
|
|
|
widget.userData.profilePictureUrl!,
|
|
|
|
fit: BoxFit.cover,
|
|
|
|
)
|
|
|
|
: null),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
Positioned(
|
|
|
|
bottom: 0,
|
|
|
|
right: 0,
|
|
|
|
child: IconButton(
|
|
|
|
icon: Ink(
|
|
|
|
decoration: ShapeDecoration(
|
|
|
|
color: Theme.of(context).colorScheme.primary,
|
|
|
|
shape: const CircleBorder(),
|
|
|
|
),
|
|
|
|
child: const Icon(Icons.edit)),
|
|
|
|
onPressed: _pickImage,
|
|
|
|
),
|
|
|
|
),
|
|
|
|
],
|
|
|
|
),
|
|
|
|
);
|
|
|
|
}
|
2024-05-30 01:10:53 +02:00
|
|
|
}
|