uploading picture from flutter to webapi implemented
This commit is contained in:
parent
c43144e028
commit
873fd44f1c
@ -26,7 +26,7 @@ namespace API.Application.Users.Queries
|
||||
Id = user.Id,
|
||||
Email = user.Email,
|
||||
Username = user.Username,
|
||||
ProfilePictureURL = user.ProfilePicture,
|
||||
ProfilePicture = user.ProfilePicture,
|
||||
}).ToList();
|
||||
return userDTOs;
|
||||
}
|
||||
|
@ -24,7 +24,7 @@ namespace API.Application.Users.Queries
|
||||
return new ConflictObjectResult(new { message = "No user on given Id" });
|
||||
}
|
||||
|
||||
return new OkObjectResult(new { id = user.Id, email = user.Email, username = user.Username, profilePictureURL = user.ProfilePicture, createdAt = user.CreatedAt });
|
||||
return new OkObjectResult(new { id = user.Id, email = user.Email, username = user.Username, profilePicture = user.ProfilePicture, createdAt = user.CreatedAt });
|
||||
|
||||
}
|
||||
|
||||
|
@ -75,7 +75,7 @@ namespace API.Controllers
|
||||
|
||||
[Authorize]
|
||||
[HttpPut]
|
||||
public async Task<IActionResult> PutUser(UpdateUserDTO UpdateUserDTO)
|
||||
public async Task<IActionResult> PutUser([FromForm ]UpdateUserDTO UpdateUserDTO)
|
||||
{
|
||||
return await _updateUser.Handle(UpdateUserDTO);
|
||||
}
|
||||
|
@ -17,7 +17,7 @@ public class UserDTO
|
||||
public string Id { get; set; }
|
||||
public string Email { get; set; }
|
||||
public string Username { get; set; }
|
||||
public string ProfilePictureURL { get; set; }
|
||||
public string ProfilePicture { get; set; }
|
||||
|
||||
}
|
||||
|
||||
|
@ -29,6 +29,7 @@ namespace API.Persistence.Services
|
||||
var request = new PutObjectRequest
|
||||
{
|
||||
InputStream = fileStream,
|
||||
BucketName = "h4picturebucket",
|
||||
Key = fileName,
|
||||
DisablePayloadSigning = true
|
||||
};
|
||||
@ -40,7 +41,7 @@ namespace API.Persistence.Services
|
||||
throw new AmazonS3Exception($"Error uploading file to S3. HTTP Status Code: {response.HttpStatusCode}");
|
||||
}
|
||||
|
||||
var imageUrl = $"https://pub-bf709b641048489ca70f693673e3e04c.r2.dev/{fileName}";
|
||||
var imageUrl = $"https://pub-bf709b641048489ca70f693673e3e04c.r2.dev/h4picturebucket/{fileName}";
|
||||
return imageUrl;
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,7 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_image_compress/flutter_image_compress.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'dart:convert';
|
||||
@ -63,6 +66,92 @@ Future<String?> request(BuildContext? context, ApiService service, String method
|
||||
return utf8.decode(response.bodyBytes);
|
||||
}
|
||||
|
||||
Future<String?> putUser(
|
||||
BuildContext? context,
|
||||
ApiService service,
|
||||
String method,
|
||||
String path,
|
||||
Map<String, dynamic> body,
|
||||
File? profilePicture // The image file
|
||||
) async {
|
||||
final messenger = context != null ? ScaffoldMessenger.of(context) : null;
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
final host = const String.fromEnvironment('AUTH_SERVICE_HOST');
|
||||
|
||||
final token = prefs.getString('token');
|
||||
final Map<String, String> headers = {};
|
||||
if (token != null) headers.addAll({'Authorization': 'Bearer $token'});
|
||||
|
||||
// Create the Uri
|
||||
var uri = Uri.parse(host + path);
|
||||
|
||||
// Create a MultipartRequest
|
||||
var request = http.MultipartRequest('PUT', uri);
|
||||
request.headers.addAll(headers);
|
||||
|
||||
// Add form fields
|
||||
request.fields['id'] = body['id'];
|
||||
request.fields['username'] = body['username'];
|
||||
request.fields['email'] = body['email'];
|
||||
request.fields['password'] = body['password'];
|
||||
|
||||
// Attach the file to the request (if provided)
|
||||
if (profilePicture != null) {
|
||||
var fileStream = http.ByteStream(profilePicture.openRead());
|
||||
var length = await profilePicture.length();
|
||||
var multipartFile = http.MultipartFile(
|
||||
'ProfilePicture', // field name matches your backend DTO
|
||||
fileStream,
|
||||
length,
|
||||
filename: profilePicture.path.split('/').last,
|
||||
);
|
||||
request.files.add(multipartFile);
|
||||
}
|
||||
|
||||
try {
|
||||
// Send the request
|
||||
var streamedResponse = await request.send();
|
||||
var response = await http.Response.fromStream(streamedResponse);
|
||||
|
||||
// Handle non-success responses
|
||||
if (response.statusCode < 200 || response.statusCode >= 300) {
|
||||
try {
|
||||
final json = jsonDecode(response.body);
|
||||
messenger?.showSnackBar(SnackBar(content: Text(json['message'] ?? json['title'])));
|
||||
debugPrint('API error: ' + json['message']);
|
||||
} catch (e) {
|
||||
debugPrint(e.toString());
|
||||
messenger?.showSnackBar(SnackBar(content: Text('Something went wrong (HTTP ${response.statusCode})')));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
return utf8.decode(response.bodyBytes);
|
||||
} catch (e) {
|
||||
debugPrint(e.toString());
|
||||
messenger?.showSnackBar(const SnackBar(content: Text('Unable to connect to server')));
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
Future<bool> isLoggedIn(BuildContext context) async {
|
||||
final messenger = ScaffoldMessenger.of(context);
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
|
@ -1,6 +1,5 @@
|
||||
|
||||
import 'dart:io';
|
||||
import 'package:flutter_image_compress/flutter_image_compress.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:image_picker/image_picker.dart';
|
||||
import 'package:mobile/models.dart';
|
||||
@ -46,98 +45,68 @@ class _ProfilePageState extends State<EditProfilePage> {
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
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));
|
||||
Future _pickImageFromGallery() async{
|
||||
final image = await ImagePicker().pickImage(source: ImageSource.gallery);
|
||||
if (image == null) return;
|
||||
setState(() {
|
||||
_selectedImage = compressedFile;
|
||||
});
|
||||
}
|
||||
|
||||
_selectedImage = File(image.path);
|
||||
});
|
||||
}
|
||||
|
||||
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));
|
||||
final image = await ImagePicker().pickImage(source: ImageSource.camera);
|
||||
if (image == null) return;
|
||||
setState(() {
|
||||
_selectedImage = compressedFile;
|
||||
});
|
||||
}
|
||||
_selectedImage = File(image.path);
|
||||
});
|
||||
}
|
||||
|
||||
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,
|
||||
|
||||
void _saveProfile() async {
|
||||
if (passwordInput.text != confirmPasswordInput.text) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(content: Text('Passwords do not match')));
|
||||
return;
|
||||
}
|
||||
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
String? id = prefs.getString('id');
|
||||
|
||||
if (!mounted) return;
|
||||
|
||||
if (id != null) {
|
||||
final response = await api.putUser(
|
||||
context,
|
||||
api.ApiService.auth,
|
||||
'PUT',
|
||||
'/api/users',
|
||||
{
|
||||
'id': id,
|
||||
'username': usernameInput.text,
|
||||
'email': emailInput.text,
|
||||
'password': passwordInput.text,
|
||||
},
|
||||
_selectedImage // Pass the selected image to the putUser function
|
||||
);
|
||||
|
||||
return File(result!.path);
|
||||
}
|
||||
|
||||
void _saveProfile() async {
|
||||
if (passwordInput.text != confirmPasswordInput.text) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(content: Text('Passwords do not match')));
|
||||
return;
|
||||
}
|
||||
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
String? id = prefs.getString('id');
|
||||
|
||||
if (!mounted) {
|
||||
return;
|
||||
}
|
||||
if (id != null){
|
||||
final response = await api.request(context, api.ApiService.auth, 'PUT', '/api/users', {
|
||||
'id' : id,
|
||||
'username': usernameInput.text,
|
||||
'email': emailInput.text,
|
||||
'password': passwordInput.text,
|
||||
'profilePicture': _selectedImage,
|
||||
});
|
||||
|
||||
if (!mounted) {
|
||||
return;
|
||||
}
|
||||
if (!mounted) return;
|
||||
|
||||
if (response != null) {
|
||||
User updatedUser = User(
|
||||
id,
|
||||
emailInput.text,
|
||||
usernameInput.text,
|
||||
_selectedImage,
|
||||
DateTime.now(),
|
||||
);
|
||||
setState(() {
|
||||
user = updatedUser;
|
||||
user = null;
|
||||
});
|
||||
|
||||
Navigator.of(context).pop(); // Close the dialog
|
||||
Navigator.pushReplacementNamed(context, '/profile');
|
||||
|
||||
} else {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(content: Text('Something went wrong! Please contact an admin.')),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void _deleteProfile(BuildContext context) {
|
||||
showDialog(
|
||||
|
@ -44,7 +44,7 @@ class User {
|
||||
String id;
|
||||
String email;
|
||||
String username;
|
||||
File? profilePicture;
|
||||
String profilePicture;
|
||||
DateTime createdAt;
|
||||
|
||||
User( this.id, this.email, this.username, this.profilePicture, this.createdAt);
|
||||
|
@ -41,6 +41,8 @@ class _ProfilePageState extends State<ProfilePage> {
|
||||
Map<String, dynamic> json = jsonDecode(response);
|
||||
User jsonUser = User.fromJson(json);
|
||||
|
||||
print(jsonUser.profilePicture);
|
||||
|
||||
setState(() {
|
||||
userData = jsonUser;
|
||||
user = jsonUser;
|
||||
@ -71,11 +73,13 @@ class _ProfilePageState extends State<ProfilePage> {
|
||||
: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
userData?.profilePicture != null ?
|
||||
const Icon(
|
||||
Icons.account_circle,
|
||||
size: 100,
|
||||
color: Colors.grey,
|
||||
),
|
||||
)
|
||||
: Image(image: NetworkImage('https://pub-bf709b641048489ca70f693673e3e04c.r2.dev/h4picturebucket/PPb83569bef3b9470782d7b42bc4e552ff.png'), height: 100),
|
||||
const SizedBox(height: 20),
|
||||
Text(
|
||||
userData!.username,
|
||||
|
Loading…
Reference in New Issue
Block a user