diff --git a/src/PostIt/PostIt/Services/YavscApiClient.cs b/src/PostIt/PostIt/Services/YavscApiClient.cs
index f08bcc08..4d748f87 100644
--- a/src/PostIt/PostIt/Services/YavscApiClient.cs
+++ b/src/PostIt/PostIt/Services/YavscApiClient.cs
@@ -357,7 +357,7 @@ public class YavscApiClient : IYavscApiClient, IAsyncDisposable
/// single multipart file named file and validates the image
/// content type before persisting it.
///
- public async Task SetAvatarAsync(
+ public async Task SetAvatarAsync(
Stream imageStream,
string fileName,
string? contentType = null,
@@ -400,6 +400,27 @@ public class YavscApiClient : IYavscApiClient, IAsyncDisposable
}
await EnsureSuccessOrThrowAsync(response, ct).ConfigureAwait(false);
+
+ var payload = await response.Content.ReadAsStringAsync(ct).ConfigureAwait(false);
+ if (string.IsNullOrWhiteSpace(payload))
+ return "Avatar mis à jour.";
+
+ try
+ {
+ using var json = JsonDocument.Parse(payload);
+ if (json.RootElement.TryGetProperty("message", out var msgEl))
+ {
+ var message = msgEl.GetString();
+ if (!string.IsNullOrWhiteSpace(message))
+ return message;
+ }
+ }
+ catch (JsonException)
+ {
+ // Keep a user-friendly fallback when the API payload is not JSON.
+ }
+
+ return "Avatar mis à jour.";
}
public async Task LogoutAsync()
diff --git a/src/PostIt/PostIt/Views/SettingsPage.axaml b/src/PostIt/PostIt/Views/SettingsPage.axaml
index 3c6d7410..611b8995 100644
--- a/src/PostIt/PostIt/Views/SettingsPage.axaml
+++ b/src/PostIt/PostIt/Views/SettingsPage.axaml
@@ -46,8 +46,18 @@
-
-
diff --git a/src/PostIt/PostIt/Views/SettingsPage.axaml.cs b/src/PostIt/PostIt/Views/SettingsPage.axaml.cs
index 0a0de615..593dcfee 100644
--- a/src/PostIt/PostIt/Views/SettingsPage.axaml.cs
+++ b/src/PostIt/PostIt/Views/SettingsPage.axaml.cs
@@ -3,7 +3,10 @@
using System;
using System.IO;
using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
using Avalonia.Controls;
+using Avalonia.Media;
using Avalonia.Platform.Storage;
using Microsoft.Extensions.DependencyInjection;
using PostIt.Services;
@@ -11,6 +14,11 @@ using PostIt.Services;
namespace PostIt.Views;
public partial class SettingsPage: ContentPage
{
+ private const int MaxAvatarSizeMegabytes = 2;
+ private const string AcceptedAvatarFormats = "PNG, JPG/JPEG, WEBP, GIF";
+
+ private int _avatarStatusVersion;
+
public SettingsPage()
{
InitializeComponent();
@@ -18,9 +26,15 @@ public partial class SettingsPage: ContentPage
private async void ChooseAvatar_Click(object? sender, Avalonia.Interactivity.RoutedEventArgs e)
{
+ var statusVersion = Interlocked.Increment(ref _avatarStatusVersion);
+ ChooseAvatarButton.IsEnabled = false;
+ SetAvatarStatus("Sélection d'un fichier avatar...", Brushes.Gray);
+
var topLevel = TopLevel.GetTopLevel(this);
if (topLevel is null)
{
+ SetAvatarStatus("Impossible d'accéder à la fenêtre active.", Brushes.IndianRed);
+ ChooseAvatarButton.IsEnabled = true;
return;
}
@@ -40,19 +54,51 @@ public partial class SettingsPage: ContentPage
var file = files.FirstOrDefault();
if (file is null)
{
+ SetAvatarStatus("Upload annulé.", Brushes.Gray);
+ ChooseAvatarButton.IsEnabled = true;
return;
}
try
{
+ SetAvatarStatus("Upload avatar en cours...", Brushes.Gray);
+
await using var stream = await file.OpenReadAsync();
var api = ((App)App.Current!).ServiceProvider!.GetRequiredService();
- await api.SetAvatarAsync(stream, file.Name, GetMimeType(file.Name));
+ var message = await api.SetAvatarAsync(stream, file.Name, GetMimeType(file.Name));
+ SetAvatarStatus(string.IsNullOrWhiteSpace(message)
+ ? "Avatar mis à jour."
+ : message, Brushes.ForestGreen);
+
+ _ = ClearSuccessStatusLaterAsync(statusVersion);
}
catch (Exception ex)
{
+ SetAvatarStatus($"Échec upload avatar: {ex.Message}", Brushes.IndianRed);
Console.Error.WriteLine($"🩎 Avatar upload failed: {ex.Message}");
}
+ finally
+ {
+ ChooseAvatarButton.IsEnabled = true;
+ }
+ }
+
+ private async Task ClearSuccessStatusLaterAsync(int statusVersion)
+ {
+ await Task.Delay(TimeSpan.FromSeconds(5)).ConfigureAwait(true);
+ if (statusVersion != _avatarStatusVersion)
+ return;
+
+ if (AvatarUploadStatusText.Foreground == Brushes.ForestGreen)
+ {
+ SetAvatarStatus($"Avatar prêt. Formats supportés: {AcceptedAvatarFormats}. Taille max: {MaxAvatarSizeMegabytes} MB.", Brushes.Gray);
+ }
+ }
+
+ private void SetAvatarStatus(string message, IBrush color)
+ {
+ AvatarUploadStatusText.Foreground = color;
+ AvatarUploadStatusText.Text = message;
}
private static string GetMimeType(string fileName)