diff --git a/src/PostIt/PostIt/ViewModels/MainPageViewModel.cs b/src/PostIt/PostIt/ViewModels/MainPageViewModel.cs
index d907606f..d1d16306 100644
--- a/src/PostIt/PostIt/ViewModels/MainPageViewModel.cs
+++ b/src/PostIt/PostIt/ViewModels/MainPageViewModel.cs
@@ -35,6 +35,18 @@ public partial class MainPageViewModel : ViewModelBase
[ObservableProperty]
public partial string DraftArticle { get; set; }
+ /// Editor buffer for the post's publication state.
+ /// Reflects the server-side IsPublished flag (the
+ /// existence of a row in BlogSpotPublication) and
+ /// is pushed to the server via
+ /// on explicit
+ /// toggle — it is NOT included in the regular Save
+ /// payload, mirroring the wire contract where
+ /// BlogPostDto doesn't carry Publish as a
+ /// mutable field. Toggling is its own action.
+ [ObservableProperty]
+ public partial bool DraftIsPublished { get; set; }
+
[ObservableProperty]
public partial ViewModelBase? CurrentViewModel { get; set; }
@@ -102,6 +114,7 @@ public partial class MainPageViewModel : ViewModelBase
WindowTitle = "PostIt";
DraftTitle = string.Empty;
DraftArticle = string.Empty;
+ DraftIsPublished = false;
CurrentViewModel = this;
}
@@ -131,6 +144,9 @@ public partial class MainPageViewModel : ViewModelBase
// doesn't show stale content.
DraftTitle = value?.Title ?? string.Empty;
DraftArticle = value?.Article ?? string.Empty;
+ // Mirror publication state too. Defaults to false on
+ // null selection so a fresh draft starts unpublished.
+ DraftIsPublished = value?.IsPublished ?? false;
UpdateCommandStates();
}
@@ -241,6 +257,46 @@ public partial class MainPageViewModel : ViewModelBase
});
}
+ ///
+ /// Toggle the publication state of the currently selected
+ /// post. Pushes the new state to
+ /// PUT /api/BlogApi/{id}/publish and reflects it
+ /// locally in + the
+ /// selected post so the UI updates without a full
+ /// refresh.
+ ///
+ /// The toggle is its own action — separate from Save
+ /// — because Publish is not part of the
+ /// BlogPostDto payload. Bundling it into Save
+ /// would require a wire-shape change and a second server
+ /// overload; the dedicated endpoint keeps the wire
+ /// contract clean.
+ ///
+ [RelayCommand]
+ internal async Task TogglePublish()
+ {
+ if (SelectedPost is null || SelectedPost.Id == 0)
+ {
+ StatusMessage = "Sélectionnez un billet existant pour changer sa publication.";
+ return;
+ }
+
+ await ExecuteAsync(async () =>
+ {
+ var desired = !DraftIsPublished;
+ await BlogClient.SetPublishAsync(SelectedPost.Id, desired);
+ DraftIsPublished = desired;
+ // Mirror into the selected post so a subsequent
+ // RefreshPostsAsync() doesn't blow away the
+ // locally flipped state until the round-trip
+ // re-hydrates it.
+ SelectedPost.IsPublished = desired;
+ StatusMessage = desired
+ ? $"Billet {SelectedPost.Id} publié."
+ : $"Billet {SelectedPost.Id} remis en brouillon.";
+ });
+ }
+
[RelayCommand]
internal void OpenSettings()
{
diff --git a/src/PostIt/PostIt/Views/MainPage.axaml b/src/PostIt/PostIt/Views/MainPage.axaml
index c6e7fb10..0246857e 100644
--- a/src/PostIt/PostIt/Views/MainPage.axaml
+++ b/src/PostIt/PostIt/Views/MainPage.axaml
@@ -35,6 +35,18 @@
+
+