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,
|
Id = user.Id,
|
||||||
Email = user.Email,
|
Email = user.Email,
|
||||||
Username = user.Username,
|
Username = user.Username,
|
||||||
ProfilePictureURL = user.ProfilePicture,
|
ProfilePicture = user.ProfilePicture,
|
||||||
}).ToList();
|
}).ToList();
|
||||||
return userDTOs;
|
return userDTOs;
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,7 @@ namespace API.Application.Users.Queries
|
|||||||
return new ConflictObjectResult(new { message = "No user on given Id" });
|
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]
|
[Authorize]
|
||||||
[HttpPut]
|
[HttpPut]
|
||||||
public async Task<IActionResult> PutUser(UpdateUserDTO UpdateUserDTO)
|
public async Task<IActionResult> PutUser([FromForm ]UpdateUserDTO UpdateUserDTO)
|
||||||
{
|
{
|
||||||
return await _updateUser.Handle(UpdateUserDTO);
|
return await _updateUser.Handle(UpdateUserDTO);
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,7 @@ public class UserDTO
|
|||||||
public string Id { get; set; }
|
public string Id { get; set; }
|
||||||
public string Email { get; set; }
|
public string Email { get; set; }
|
||||||
public string Username { 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
|
var request = new PutObjectRequest
|
||||||
{
|
{
|
||||||
InputStream = fileStream,
|
InputStream = fileStream,
|
||||||
|
BucketName = "h4picturebucket",
|
||||||
Key = fileName,
|
Key = fileName,
|
||||||
DisablePayloadSigning = true
|
DisablePayloadSigning = true
|
||||||
};
|
};
|
||||||
@ -40,7 +41,7 @@ namespace API.Persistence.Services
|
|||||||
throw new AmazonS3Exception($"Error uploading file to S3. HTTP Status Code: {response.HttpStatusCode}");
|
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;
|
return imageUrl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,7 @@
|
|||||||
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_image_compress/flutter_image_compress.dart';
|
||||||
import 'package:shared_preferences/shared_preferences.dart';
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
import 'package:http/http.dart' as http;
|
import 'package:http/http.dart' as http;
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
@ -63,6 +66,92 @@ Future<String?> request(BuildContext? context, ApiService service, String method
|
|||||||
return utf8.decode(response.bodyBytes);
|
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 {
|
Future<bool> isLoggedIn(BuildContext context) async {
|
||||||
final messenger = ScaffoldMessenger.of(context);
|
final messenger = ScaffoldMessenger.of(context);
|
||||||
final prefs = await SharedPreferences.getInstance();
|
final prefs = await SharedPreferences.getInstance();
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
|
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
import 'package:flutter_image_compress/flutter_image_compress.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:image_picker/image_picker.dart';
|
import 'package:image_picker/image_picker.dart';
|
||||||
import 'package:mobile/models.dart';
|
import 'package:mobile/models.dart';
|
||||||
@ -46,98 +45,68 @@ class _ProfilePageState extends State<EditProfilePage> {
|
|||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
Future _pickImageFromGallery() async{
|
Future _pickImageFromGallery() async{
|
||||||
final picker = ImagePicker();
|
final image = await ImagePicker().pickImage(source: ImageSource.gallery);
|
||||||
final XFile? image = await picker.pickImage(source: ImageSource.gallery);
|
if (image == null) return;
|
||||||
|
|
||||||
if(image == null) {return;}
|
|
||||||
else{
|
|
||||||
File compressedFile = await _compressImage(File(image.path));
|
|
||||||
setState(() {
|
setState(() {
|
||||||
_selectedImage = compressedFile;
|
_selectedImage = File(image.path);
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Future _pickImageFromCamera() async{
|
Future _pickImageFromCamera() async{
|
||||||
final picker = ImagePicker();
|
final image = await ImagePicker().pickImage(source: ImageSource.camera);
|
||||||
final XFile? image = await picker.pickImage(source: ImageSource.camera);
|
if (image == null) return;
|
||||||
|
|
||||||
if(image == null) {return;}
|
|
||||||
else{
|
|
||||||
File compressedFile = await _compressImage(File(image.path));
|
|
||||||
setState(() {
|
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(
|
void _saveProfile() async {
|
||||||
file.absolute.path,
|
if (passwordInput.text != confirmPasswordInput.text) {
|
||||||
outPath,
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
quality: 80,
|
const SnackBar(content: Text('Passwords do not match')));
|
||||||
minWidth: 1024,
|
return;
|
||||||
minHeight: 1024,
|
}
|
||||||
|
|
||||||
|
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);
|
if (!mounted) return;
|
||||||
}
|
|
||||||
|
|
||||||
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 (response != null) {
|
if (response != null) {
|
||||||
User updatedUser = User(
|
|
||||||
id,
|
|
||||||
emailInput.text,
|
|
||||||
usernameInput.text,
|
|
||||||
_selectedImage,
|
|
||||||
DateTime.now(),
|
|
||||||
);
|
|
||||||
setState(() {
|
setState(() {
|
||||||
user = updatedUser;
|
user = null;
|
||||||
});
|
});
|
||||||
|
|
||||||
Navigator.of(context).pop(); // Close the dialog
|
Navigator.of(context).pop(); // Close the dialog
|
||||||
Navigator.pushReplacementNamed(context, '/profile');
|
Navigator.pushReplacementNamed(context, '/profile');
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
const SnackBar(content: Text('Something went wrong! Please contact an admin.')),
|
const SnackBar(content: Text('Something went wrong! Please contact an admin.')),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void _deleteProfile(BuildContext context) {
|
void _deleteProfile(BuildContext context) {
|
||||||
showDialog(
|
showDialog(
|
||||||
|
@ -44,7 +44,7 @@ class User {
|
|||||||
String id;
|
String id;
|
||||||
String email;
|
String email;
|
||||||
String username;
|
String username;
|
||||||
File? profilePicture;
|
String profilePicture;
|
||||||
DateTime createdAt;
|
DateTime createdAt;
|
||||||
|
|
||||||
User( this.id, this.email, this.username, this.profilePicture, this.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);
|
Map<String, dynamic> json = jsonDecode(response);
|
||||||
User jsonUser = User.fromJson(json);
|
User jsonUser = User.fromJson(json);
|
||||||
|
|
||||||
|
print(jsonUser.profilePicture);
|
||||||
|
|
||||||
setState(() {
|
setState(() {
|
||||||
userData = jsonUser;
|
userData = jsonUser;
|
||||||
user = jsonUser;
|
user = jsonUser;
|
||||||
@ -71,11 +73,13 @@ class _ProfilePageState extends State<ProfilePage> {
|
|||||||
: Column(
|
: Column(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
|
userData?.profilePicture != null ?
|
||||||
const Icon(
|
const Icon(
|
||||||
Icons.account_circle,
|
Icons.account_circle,
|
||||||
size: 100,
|
size: 100,
|
||||||
color: Colors.grey,
|
color: Colors.grey,
|
||||||
),
|
)
|
||||||
|
: Image(image: NetworkImage('https://pub-bf709b641048489ca70f693673e3e04c.r2.dev/h4picturebucket/PPb83569bef3b9470782d7b42bc4e552ff.png'), height: 100),
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 20),
|
||||||
Text(
|
Text(
|
||||||
userData!.username,
|
userData!.username,
|
||||||
|
Loading…
Reference in New Issue
Block a user