2024-09-06 14:13:30 +01:00
|
|
|
|
|
|
|
import 'dart:io';
|
|
|
|
import 'package:flutter_image_compress/flutter_image_compress.dart';
|
2024-08-26 14:49:06 +01:00
|
|
|
import 'package:flutter/material.dart';
|
2024-09-06 14:13:30 +01:00
|
|
|
import 'package:image_picker/image_picker.dart';
|
2024-08-26 14:49:06 +01:00
|
|
|
import 'package:mobile/models.dart';
|
|
|
|
import 'package:shared_preferences/shared_preferences.dart';
|
|
|
|
import 'api.dart' as api;
|
|
|
|
import 'base/variables.dart';
|
|
|
|
|
|
|
|
class EditProfilePage extends StatefulWidget {
|
|
|
|
final User? userData;
|
2024-09-06 14:13:30 +01:00
|
|
|
|
2024-08-26 14:49:06 +01:00
|
|
|
const EditProfilePage({super.key, required this.userData});
|
|
|
|
|
|
|
|
|
|
|
|
@override
|
|
|
|
State<EditProfilePage> createState() => _ProfilePageState();
|
|
|
|
}
|
|
|
|
|
|
|
|
class _ProfilePageState extends State<EditProfilePage> {
|
|
|
|
TextEditingController usernameInput = TextEditingController();
|
|
|
|
TextEditingController emailInput = TextEditingController();
|
|
|
|
TextEditingController passwordInput = TextEditingController();
|
|
|
|
TextEditingController confirmPasswordInput = TextEditingController();
|
2024-09-06 14:13:30 +01:00
|
|
|
File? _selectedImage;
|
|
|
|
|
2024-08-27 12:06:31 +01:00
|
|
|
set userData(User userData) {}
|
2024-08-26 14:49:06 +01:00
|
|
|
|
|
|
|
|
|
|
|
@override
|
|
|
|
void initState() {
|
|
|
|
super.initState();
|
|
|
|
// Initialize the controllers with existing data
|
|
|
|
usernameInput.text = widget.userData!.username;
|
|
|
|
emailInput.text = widget.userData!.email;
|
|
|
|
}
|
|
|
|
|
|
|
|
@override
|
|
|
|
void dispose() {
|
|
|
|
// Dispose of the controllers when the widget is disposed
|
|
|
|
usernameInput.dispose();
|
|
|
|
emailInput.dispose();
|
|
|
|
passwordInput.dispose();
|
|
|
|
confirmPasswordInput.dispose();
|
|
|
|
super.dispose();
|
|
|
|
}
|
|
|
|
|
2024-09-06 14:13:30 +01:00
|
|
|
Future _pickImageFromGallery() async{
|
|
|
|
final picker = ImagePicker();
|
|
|
|
final XFile? image = await picker.pickImage(source: ImageSource.gallery);
|
|
|
|
|
|
|
|
if(image == null) {return;}
|
|
|
|
else{
|
|
|
|
File compressedFile = await _compressImage(File(image.path));
|
|
|
|
setState(() {
|
|
|
|
_selectedImage = compressedFile;
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
Future _pickImageFromCamera() async{
|
|
|
|
final picker = ImagePicker();
|
|
|
|
final XFile? image = await picker.pickImage(source: ImageSource.camera);
|
|
|
|
|
|
|
|
if(image == null) {return;}
|
|
|
|
else{
|
|
|
|
File compressedFile = await _compressImage(File(image.path));
|
|
|
|
setState(() {
|
|
|
|
_selectedImage = compressedFile;
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Future<File> _compressImage(File file) async {
|
|
|
|
final filePath = file.absolute.path;
|
|
|
|
final lastIndex = filePath.lastIndexOf(RegExp(r'.jp'));
|
|
|
|
final splitted = filePath.substring(0, lastIndex);
|
|
|
|
final outPath = "${splitted}_compressed.jpg";
|
|
|
|
|
|
|
|
var result = await FlutterImageCompress.compressAndGetFile(
|
|
|
|
file.absolute.path,
|
|
|
|
outPath,
|
|
|
|
quality: 80,
|
|
|
|
minWidth: 1024,
|
|
|
|
minHeight: 1024,
|
|
|
|
);
|
|
|
|
|
|
|
|
return File(result!.path);
|
|
|
|
}
|
|
|
|
|
2024-08-26 14:49:06 +01:00
|
|
|
void _saveProfile() async {
|
|
|
|
if (passwordInput.text != confirmPasswordInput.text) {
|
|
|
|
ScaffoldMessenger.of(context).showSnackBar(
|
|
|
|
const SnackBar(content: Text('Passwords do not match')));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2024-08-27 07:40:54 +01:00
|
|
|
final prefs = await SharedPreferences.getInstance();
|
|
|
|
String? id = prefs.getString('id');
|
|
|
|
|
|
|
|
if (!mounted) {
|
|
|
|
return;
|
|
|
|
}
|
2024-09-06 14:13:30 +01:00
|
|
|
if (id != null){
|
|
|
|
final response = await api.request(context, api.ApiService.auth, 'PUT', '/api/users', {
|
2024-08-26 14:49:06 +01:00
|
|
|
'id' : id,
|
|
|
|
'username': usernameInput.text,
|
|
|
|
'email': emailInput.text,
|
|
|
|
'password': passwordInput.text,
|
2024-09-06 14:13:30 +01:00
|
|
|
'profilePicture': _selectedImage,
|
2024-08-26 14:49:06 +01:00
|
|
|
});
|
|
|
|
|
2024-08-27 07:40:54 +01:00
|
|
|
if (!mounted) {
|
|
|
|
return;
|
|
|
|
}
|
2024-08-26 14:49:06 +01:00
|
|
|
|
2024-08-27 07:40:54 +01:00
|
|
|
if (response != null) {
|
2024-08-27 12:06:31 +01:00
|
|
|
User updatedUser = User(
|
2024-09-06 14:13:30 +01:00
|
|
|
id,
|
2024-08-27 07:40:54 +01:00
|
|
|
emailInput.text,
|
|
|
|
usernameInput.text,
|
2024-09-06 14:13:30 +01:00
|
|
|
_selectedImage,
|
2024-08-27 07:40:54 +01:00
|
|
|
DateTime.now(),
|
|
|
|
);
|
2024-08-27 12:06:31 +01:00
|
|
|
setState(() {
|
|
|
|
user = updatedUser;
|
|
|
|
});
|
2024-08-26 14:49:06 +01:00
|
|
|
|
2024-08-27 07:40:54 +01:00
|
|
|
Navigator.of(context).pop(); // Close the dialog
|
2024-08-27 12:06:31 +01:00
|
|
|
Navigator.pushReplacementNamed(context, '/profile');
|
|
|
|
|
2024-08-27 07:40:54 +01:00
|
|
|
} else {
|
|
|
|
ScaffoldMessenger.of(context).showSnackBar(
|
|
|
|
const SnackBar(content: Text('Something went wrong! Please contact an admin.')),
|
|
|
|
);
|
2024-09-06 14:13:30 +01:00
|
|
|
}
|
|
|
|
}
|
2024-08-26 14:49:06 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void _deleteProfile(BuildContext context) {
|
|
|
|
showDialog(
|
|
|
|
context: context,
|
|
|
|
builder: (BuildContext context) {
|
|
|
|
return AlertDialog(
|
|
|
|
title: Text('Confirm Deletion'),
|
|
|
|
content: Text('Are you sure you want to delete your profile?'),
|
|
|
|
actions: <Widget>[
|
|
|
|
TextButton(
|
|
|
|
child: Text('Cancel'),
|
|
|
|
onPressed: () {
|
|
|
|
Navigator.of(context).pop(); // Close the dialog
|
|
|
|
},
|
|
|
|
),
|
|
|
|
TextButton(
|
|
|
|
child: Text('Delete'),
|
|
|
|
style: TextButton.styleFrom(foregroundColor: Colors.red),
|
|
|
|
onPressed: () async {
|
|
|
|
final prefs = await SharedPreferences.getInstance();
|
|
|
|
String? id = prefs.getString('id');
|
|
|
|
|
2024-08-27 07:40:54 +01:00
|
|
|
final response = await api.request(context, api.ApiService.auth, 'DELETE', '/api/users/$id', null);
|
2024-08-26 14:49:06 +01:00
|
|
|
|
2024-08-27 07:40:54 +01:00
|
|
|
if (response != null) {
|
2024-08-26 14:49:06 +01:00
|
|
|
prefs.remove('token');
|
2024-08-27 07:40:54 +01:00
|
|
|
prefs.remove('id');
|
|
|
|
|
|
|
|
setState(() {
|
|
|
|
user = null;
|
2024-08-26 14:49:06 +01:00
|
|
|
});
|
2024-08-27 07:40:54 +01:00
|
|
|
|
|
|
|
Navigator.of(context).pop(); // Close the dialog
|
|
|
|
Navigator.of(context).pop();
|
|
|
|
|
|
|
|
Navigator.pushReplacementNamed(context, '/register');
|
|
|
|
} else {
|
2024-08-26 14:49:06 +01:00
|
|
|
ScaffoldMessenger.of(context).showSnackBar(
|
|
|
|
const SnackBar(content: Text('Something went wrong! Please contact an admin.')),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
),
|
|
|
|
],
|
|
|
|
);
|
|
|
|
},
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
@override
|
|
|
|
Widget build(BuildContext context) {
|
2024-08-27 07:40:54 +01:00
|
|
|
return Scaffold(
|
2024-08-26 14:49:06 +01:00
|
|
|
appBar: AppBar(
|
|
|
|
title: Text('Edit Profile'),
|
|
|
|
leading: IconButton(
|
|
|
|
icon: Icon(Icons.arrow_back),
|
|
|
|
onPressed: () {
|
|
|
|
Navigator.pop(context); // Navigates back when the back button is pressed
|
|
|
|
},
|
|
|
|
),
|
|
|
|
),
|
|
|
|
body: Padding(
|
|
|
|
padding: const EdgeInsets.all(16.0),
|
|
|
|
child: Column(
|
|
|
|
children: [
|
|
|
|
TextField(
|
|
|
|
controller: usernameInput,
|
|
|
|
decoration: InputDecoration(labelText: 'Name'),
|
|
|
|
),
|
|
|
|
TextField(
|
|
|
|
controller: emailInput,
|
|
|
|
decoration: InputDecoration(labelText: 'Email'),
|
|
|
|
),
|
|
|
|
TextField(
|
|
|
|
controller: passwordInput,
|
|
|
|
decoration: InputDecoration(labelText: 'New password'),
|
|
|
|
),
|
|
|
|
TextField(
|
|
|
|
controller: confirmPasswordInput,
|
|
|
|
decoration: InputDecoration(labelText: 'Repeat new password'),
|
|
|
|
),
|
2024-09-06 14:13:30 +01:00
|
|
|
Row(
|
|
|
|
children: [
|
|
|
|
ElevatedButton(onPressed: _pickImageFromGallery, child: Text('Gallery')),
|
|
|
|
ElevatedButton(onPressed: _pickImageFromCamera, child: Text('Camera'))
|
|
|
|
],
|
|
|
|
),
|
2024-08-26 14:49:06 +01:00
|
|
|
SizedBox(height: 20),
|
2024-09-06 14:13:30 +01:00
|
|
|
Text('ProfilePicture:'),
|
|
|
|
if(_selectedImage != null)
|
|
|
|
Text(_selectedImage!.path.toString()),
|
2024-08-26 14:49:06 +01:00
|
|
|
Row(
|
|
|
|
mainAxisAlignment: MainAxisAlignment.center,
|
|
|
|
children: [
|
|
|
|
ElevatedButton(
|
|
|
|
onPressed: _saveProfile, // Save and pop
|
|
|
|
child: Text('Save'),
|
|
|
|
),
|
|
|
|
SizedBox(width: 10),
|
|
|
|
ElevatedButton(
|
|
|
|
onPressed: () => _deleteProfile(context),
|
|
|
|
child: Text('Delete'),
|
|
|
|
style: ElevatedButton.styleFrom(
|
|
|
|
foregroundColor: Colors.red, // Red text
|
|
|
|
),
|
|
|
|
),
|
|
|
|
],
|
|
|
|
)
|
|
|
|
],
|
|
|
|
),
|
|
|
|
),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|