diff --git a/src/PostIt/PostIt/Controls/StatusBar.axaml b/src/PostIt/PostIt/Controls/StatusBar.axaml new file mode 100644 index 000000000..eaa6f5a09 --- /dev/null +++ b/src/PostIt/PostIt/Controls/StatusBar.axaml @@ -0,0 +1,22 @@ + + + + + + + + diff --git a/src/PostIt/PostIt/Controls/StatusBar.axaml.cs b/src/PostIt/PostIt/Controls/StatusBar.axaml.cs new file mode 100644 index 000000000..975f9b2f9 --- /dev/null +++ b/src/PostIt/PostIt/Controls/StatusBar.axaml.cs @@ -0,0 +1,11 @@ +using Avalonia.Controls; + +namespace PostIt.Controls; + +public partial class StatusBar : UserControl +{ + public StatusBar() + { + InitializeComponent(); + } +} diff --git a/src/PostIt/PostIt/ViewModels/ActivitiesPageViewModel.cs b/src/PostIt/PostIt/ViewModels/ActivitiesPageViewModel.cs index 2dc8938f3..801cf21d4 100644 --- a/src/PostIt/PostIt/ViewModels/ActivitiesPageViewModel.cs +++ b/src/PostIt/PostIt/ViewModels/ActivitiesPageViewModel.cs @@ -43,6 +43,14 @@ public partial class ActivitiesPageViewModel : ViewModelBase [ObservableProperty] public partial string StatusMessage { get; set; } = "Choisissez une activité."; + [ObservableProperty] + public partial StatusNotice ActionStatus { get; set; } = StatusNotice.Info("Choisissez une activité."); + + partial void OnStatusMessageChanged(string value) + { + ActionStatus = StatusNotice.FromMessage(value); + } + public ActivityInfo? CurrentActivity => SelectedSpecialization ?? SelectedActivity; public string SelectedActivityLabel => SelectedActivity?.Name ?? "(aucune activité)"; public string CurrentActivityLabel => CurrentActivity?.Name ?? "(aucune)"; diff --git a/src/PostIt/PostIt/ViewModels/CirclesPageViewModel.cs b/src/PostIt/PostIt/ViewModels/CirclesPageViewModel.cs index 9cee3ea8c..6d70add1d 100644 --- a/src/PostIt/PostIt/ViewModels/CirclesPageViewModel.cs +++ b/src/PostIt/PostIt/ViewModels/CirclesPageViewModel.cs @@ -65,6 +65,14 @@ public partial class CirclesPageViewModel : ViewModelBase [ObservableProperty] public partial string StatusMessage { get; set; } = string.Empty; + [ObservableProperty] + public partial StatusNotice ActionStatus { get; set; } = StatusNotice.Info("Pret."); + + partial void OnStatusMessageChanged(string value) + { + ActionStatus = StatusNotice.FromMessage(value); + } + public CirclesPageViewModel(CircleApiClient client) { diff --git a/src/PostIt/PostIt/ViewModels/Commands/BillingCommandPageViewModel.cs b/src/PostIt/PostIt/ViewModels/Commands/BillingCommandPageViewModel.cs index 0ab76291d..5fd7d8461 100644 --- a/src/PostIt/PostIt/ViewModels/Commands/BillingCommandPageViewModel.cs +++ b/src/PostIt/PostIt/ViewModels/Commands/BillingCommandPageViewModel.cs @@ -23,6 +23,9 @@ public abstract partial class BillingCommandPageViewModel : RemoteViewModelBase [ObservableProperty] public partial string StatusMessage { get; set; } + [ObservableProperty] + public partial StatusNotice ActionStatus { get; set; } = StatusNotice.Info("Pret."); + [ObservableProperty] public partial string Reason { get; set; } = string.Empty; @@ -89,6 +92,11 @@ public abstract partial class BillingCommandPageViewModel : RemoteViewModelBase OnPropertyChanged(nameof(CanUseCurrentLocation)); } + partial void OnStatusMessageChanged(string value) + { + ActionStatus = StatusNotice.FromMessage(value); + } + public async Task InitializeAsync(BillingQueryDetailsDto? existingQuery = null) { await LoadAsync(); diff --git a/src/PostIt/PostIt/ViewModels/Settings/Settings.cs b/src/PostIt/PostIt/ViewModels/Settings/Settings.cs index e63f0b321..b59ef9933 100644 --- a/src/PostIt/PostIt/ViewModels/Settings/Settings.cs +++ b/src/PostIt/PostIt/ViewModels/Settings/Settings.cs @@ -31,6 +31,19 @@ public partial class Settings : ViewModelBase [ObservableProperty] public partial string SearchText { get; set; } = string.Empty; + [ObservableProperty] + public partial StatusNotice ActionStatus { get; set; } = StatusNotice.Info("Pret."); + + public void SetActionStatus(string message, StatusSeverity severity = StatusSeverity.Info) + { + ActionStatus = severity switch + { + StatusSeverity.Error => StatusNotice.Error(message), + StatusSeverity.Warning => StatusNotice.Warning(message), + _ => StatusNotice.Info(message), + }; + } + /// /// Catch top-level mutations: the four ObservableProperty /// setters above all funnel through here, and we flip @@ -406,6 +419,8 @@ public partial class Settings : ViewModelBase [RelayCommand(CanExecute = nameof(CanSave))] public void Save() { + SetActionStatus("Enregistrement des parametres...", StatusSeverity.Info); + var configDir = Path.Combine( Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "PostIt"); @@ -425,10 +440,13 @@ public partial class Settings : ViewModelBase File.SetUnixFileMode(configPath, UnixFileMode.UserRead | UnixFileMode.UserWrite); IsDirty = false; + SetActionStatus("Parametres sauvegardes.", StatusSeverity.Info); + Console.WriteLine($"💾 Settings saved to {configPath}"); } catch (Exception ex) { + SetActionStatus($"Echec sauvegarde parametres: {ex.Message}", StatusSeverity.Error); Console.Error.WriteLine($"🩎 Error saving settings to {configPath}: {ex.Message}"); throw; } diff --git a/src/PostIt/PostIt/ViewModels/StatusNotice.cs b/src/PostIt/PostIt/ViewModels/StatusNotice.cs new file mode 100644 index 000000000..2d14b28b3 --- /dev/null +++ b/src/PostIt/PostIt/ViewModels/StatusNotice.cs @@ -0,0 +1,58 @@ +namespace PostIt.ViewModels; + +public enum StatusSeverity +{ + Info, + Warning, + Error +} + +public sealed class StatusNotice +{ + public string Message { get; } + public StatusSeverity Severity { get; } + public string Glyph { get; } + public string Background { get; } + public string BorderBrush { get; } + public string Foreground { get; } + + private StatusNotice(string message, StatusSeverity severity) + { + Message = string.IsNullOrWhiteSpace(message) ? "Pret." : message; + Severity = severity; + + (Glyph, Background, BorderBrush, Foreground) = severity switch + { + StatusSeverity.Error => ("!", "#FDECEA", "#C62828", "#7F1D1D"), + StatusSeverity.Warning => ("~", "#FFF8E1", "#E6A700", "#7C4A03"), + _ => ("i", "#E8F0FE", "#5B8DEF", "#1E3A8A"), + }; + } + + public static StatusNotice Info(string message) => new(message, StatusSeverity.Info); + public static StatusNotice Warning(string message) => new(message, StatusSeverity.Warning); + public static StatusNotice Error(string message) => new(message, StatusSeverity.Error); + + public static StatusNotice FromMessage(string? message) + { + if (string.IsNullOrWhiteSpace(message)) + { + return Info("Pret."); + } + + var text = message.Trim(); + var lower = text.ToLowerInvariant(); + + if (lower.StartsWith("erreur") || lower.StartsWith("echec") || lower.StartsWith("impossible")) + { + return Error(text); + } + + if (lower.Contains("refuse") || lower.Contains("annule") || lower.Contains("obligatoire") || lower.Contains("deja")) + { + return Warning(text); + } + + return Info(text); + } +} diff --git a/src/PostIt/PostIt/Views/ActivitiesPage.axaml b/src/PostIt/PostIt/Views/ActivitiesPage.axaml index 16d883443..a34d8edf2 100644 --- a/src/PostIt/PostIt/Views/ActivitiesPage.axaml +++ b/src/PostIt/PostIt/Views/ActivitiesPage.axaml @@ -1,6 +1,7 @@ - + diff --git a/src/PostIt/PostIt/Views/CirclesPage.axaml b/src/PostIt/PostIt/Views/CirclesPage.axaml index 6fc2172ba..8488201e2 100644 --- a/src/PostIt/PostIt/Views/CirclesPage.axaml +++ b/src/PostIt/PostIt/Views/CirclesPage.axaml @@ -1,6 +1,7 @@ - + diff --git a/src/PostIt/PostIt/Views/Commands/RdvPage.axaml b/src/PostIt/PostIt/Views/Commands/RdvPage.axaml index 46280602b..4c88b0108 100644 --- a/src/PostIt/PostIt/Views/Commands/RdvPage.axaml +++ b/src/PostIt/PostIt/Views/Commands/RdvPage.axaml @@ -1,6 +1,7 @@ @@ -71,16 +72,8 @@ Content="{Binding SubmitLabel}" Command="{Binding SubmitCommand}" IsEnabled="{Binding IsSupported}" /> - + - +