diff --git a/global.json b/global.json index 1243cf82..d495e625 100644 --- a/global.json +++ b/global.json @@ -2,8 +2,8 @@ "sdk": { "allowPrerelease": false }, - "msbuild-sdks": { - "Uno.Sdk": "5.6.0-dev.250", - "Microsoft.Build.NoTargets": "3.7.56" - } -} \ No newline at end of file + "msbuild-sdks": { + "Uno.Sdk": "5.6.0-dev.264", + "Microsoft.Build.NoTargets": "3.7.56" + } +} diff --git a/src/app/MZikmund.App.Core/Services/Account/UserService.cs b/src/app/MZikmund.App.Core/Services/Account/UserService.cs index 30aa2fa1..f5c51164 100644 --- a/src/app/MZikmund.App.Core/Services/Account/UserService.cs +++ b/src/app/MZikmund.App.Core/Services/Account/UserService.cs @@ -102,7 +102,7 @@ private async Task EnsureIdentityClientAsync() _identityClient = PublicClientApplicationBuilder .Create(AuthenticationConstants.ApplicationId) .WithAuthority(AzureCloudInstance.AzurePublic, AuthenticationConstants.TenantId) - .WithRedirectUri("https://login.microsoftonline.com/common/oauth2/nativeclient") + .WithRedirectUri("http://localhost") .WithUnoHelpers() .Build(); diff --git a/src/app/MZikmund.App.Core/ViewModels/Admin/CategoryPickerDialogViewModel.cs b/src/app/MZikmund.App.Core/ViewModels/Admin/CategoryPickerDialogViewModel.cs index b2430275..fdc28c48 100644 --- a/src/app/MZikmund.App.Core/ViewModels/Admin/CategoryPickerDialogViewModel.cs +++ b/src/app/MZikmund.App.Core/ViewModels/Admin/CategoryPickerDialogViewModel.cs @@ -4,7 +4,7 @@ namespace MZikmund.ViewModels.Admin; -public class CategoryPickerDialogViewModel : DialogViewModel +public partial class CategoryPickerDialogViewModel : DialogViewModel { private readonly Guid[] _initialSelection; private readonly IMZikmundApi _api; @@ -15,6 +15,12 @@ public CategoryPickerDialogViewModel(Guid[] selectedCategoryIds, IMZikmundApi ap _api = api; } + [ObservableProperty] + public Category[] _allCategories = Array.Empty(); + + [ObservableProperty] + public Category[] _selectedCategories = Array.Empty(); + public override async void OnOpened(ContentDialog contentDialog) { try @@ -28,8 +34,4 @@ public override async void OnOpened(ContentDialog contentDialog) // TODO: Handle dialog exception } } - - public Category[] AllCategories { get; private set; } = Array.Empty(); - - public Category[] SelectedCategories { get; set; } = Array.Empty(); } diff --git a/src/app/MZikmund.App.Core/ViewModels/Admin/PostEditorViewModel.cs b/src/app/MZikmund.App.Core/ViewModels/Admin/PostEditorViewModel.cs index d4751628..5b443081 100644 --- a/src/app/MZikmund.App.Core/ViewModels/Admin/PostEditorViewModel.cs +++ b/src/app/MZikmund.App.Core/ViewModels/Admin/PostEditorViewModel.cs @@ -17,11 +17,34 @@ public partial class PostEditorViewModel : PageViewModel private readonly ILoadingIndicator _loadingIndicator; private readonly IPostContentProcessor _postContentProcessor; private readonly ITimerFactory _timerFactory; - private string _postTitle = ""; private DispatcherQueueTimer? _previewTimer; private bool _isPreviewDirty = true; + + [ObservableProperty] private string _postContent = ""; + [ObservableProperty] + private string _postRouteName = ""; + + [ObservableProperty] + private string _tags = ""; + + [ObservableProperty] + private string _postTitle = ""; + + [ObservableProperty] + private string _htmlPreview = ""; + + [ObservableProperty] + [NotifyPropertyChangedFor(nameof(CategoriesText))] + private Category[] _categories = Array.Empty(); + + [ObservableProperty] + private Post? _post = null; + + [ObservableProperty] + private bool _isPublished; + public PostEditorViewModel(IMZikmundApi api, IDialogService dialogService, ILoadingIndicator loadingIndicator, IPostContentProcessor postContentProcessor, ITimerFactory timerFactory) { _api = api; @@ -31,44 +54,22 @@ public PostEditorViewModel(IMZikmundApi api, IDialogService dialogService, ILoad _timerFactory = timerFactory; } - public override string Title => Post?.Title ?? ""; - - public string PostTitle + partial void OnPostTitleChanged(string value) { - get => _postTitle; - set - { - _postTitle = value; - PostRouteName = _postTitle.GenerateRouteName(); - } + PostRouteName = value.GenerateRouteName(); } - public string PostRouteName { get; set; } = ""; - - public string Tags { get; set; } = ""; - - public Category[] Categories { get; set; } = Array.Empty(); - - public string PostContent + partial void OnPostContentChanged(string value) { - get => _postContent; - set - { - if (SetProperty(ref _postContent, value)) - { - _isPreviewDirty = true; - } - } + _isPreviewDirty = true; } - public string HtmlPreview { get; set; } = ""; + public override string Title => Post?.Title ?? ""; public string CategoriesText => Categories is null or { Length: 0 } ? Localizer.Instance.GetString("NoCategoriesSelected") : string.Join(", ", Categories.Select(c => c.DisplayName)); - public Post? Post { get; set; } - [RelayCommand] private async Task PickCategoriesAsync() { @@ -96,8 +97,8 @@ private async Task SaveAsync() Post.RouteName = PostRouteName; Post.Tags = tags; Post.Categories = Categories; - Post.IsPublished = true; - Post.PublishedDate = DateTimeOffset.UtcNow; // TODO: Don't always publish! + Post.IsPublished = IsPublished; + Post.PublishedDate = Post.PublishedDate ?? DateTimeOffset.UtcNow; Post.Content = PostContent; if (Post.Id == Guid.Empty) @@ -170,5 +171,6 @@ private void PopulateInfo(Post post) PostTitle = post.Title; PostRouteName = post.RouteName; PostContent = post.Content; + IsPublished = post.PublishedDate is not null; // TODO: This logic is wrong, we should work with post status! } } diff --git a/src/app/MZikmund.App/App.xaml.cs b/src/app/MZikmund.App/App.xaml.cs index 3a69c234..cb5b9fd4 100644 --- a/src/app/MZikmund.App/App.xaml.cs +++ b/src/app/MZikmund.App/App.xaml.cs @@ -74,7 +74,7 @@ protected override void OnLaunched(LaunchActivatedEventArgs args) MainWindow = builder.Window; #if DEBUG - MainWindow.EnableHotReload(); + MainWindow.UseStudio(); #endif Host = builder.Build(); diff --git a/src/app/MZikmund.App/Dialogs/Admin/CategoryPickerDialog.xaml.cs b/src/app/MZikmund.App/Dialogs/Admin/CategoryPickerDialog.xaml.cs index c9a4ae04..7775f275 100644 --- a/src/app/MZikmund.App/Dialogs/Admin/CategoryPickerDialog.xaml.cs +++ b/src/app/MZikmund.App/Dialogs/Admin/CategoryPickerDialog.xaml.cs @@ -1,16 +1,17 @@ -using MZikmund.DataContracts.Blog; +using MZikmund.App.Core.ViewModels.Admin; +using MZikmund.DataContracts.Blog; using MZikmund.ViewModels.Admin; namespace MZikmund.Dialogs.Admin; -public sealed partial class CategoryPickerDialog : CategoryPickerDialogBase +public sealed partial class CategoryPickerDialog : CategoryPickerDialogBase, ICategoryPickerDialog { public CategoryPickerDialog() { InitializeComponent(); } - internal void SetSelectedItems(IEnumerable itemsToSelect) + public void SetSelectedItems(IEnumerable itemsToSelect) { foreach (var category in itemsToSelect) { diff --git a/src/app/MZikmund.App/MZikmund.App.csproj b/src/app/MZikmund.App/MZikmund.App.csproj index a1718877..604ca78f 100644 --- a/src/app/MZikmund.App/MZikmund.App.csproj +++ b/src/app/MZikmund.App/MZikmund.App.csproj @@ -42,6 +42,16 @@ + + + x86 + x64 + arm64 + + + + + diff --git a/src/app/MZikmund.App/Assets/PostPreviewTemplate.html b/src/app/MZikmund.App/Templates/PostPreviewTemplate.html similarity index 100% rename from src/app/MZikmund.App/Assets/PostPreviewTemplate.html rename to src/app/MZikmund.App/Templates/PostPreviewTemplate.html diff --git a/src/app/MZikmund.App/Views/Admin/PostEditorView.xaml b/src/app/MZikmund.App/Views/Admin/PostEditorView.xaml index 8be7acf1..4029cb46 100644 --- a/src/app/MZikmund.App/Views/Admin/PostEditorView.xaml +++ b/src/app/MZikmund.App/Views/Admin/PostEditorView.xaml @@ -8,48 +8,48 @@ Background="{ThemeResource ApplicationPageBackgroundThemeBrush}" mc:Ignorable="d"> - - - - - - - + + + + + diff --git a/src/app/MZikmund.App/Views/Admin/PostEditorView.xaml.cs b/src/app/MZikmund.App/Views/Admin/PostEditorView.xaml.cs index c0a1e6d6..3dc420a2 100644 --- a/src/app/MZikmund.App/Views/Admin/PostEditorView.xaml.cs +++ b/src/app/MZikmund.App/Views/Admin/PostEditorView.xaml.cs @@ -14,7 +14,7 @@ public PostEditorView() { InitializeComponent(); // Read the template from the embedded resource - _postPreviewTemplate = typeof(PostEditorView).Assembly.GetManifestResourceStream("MZikmund.App.Assets.PostPreviewTemplate.html")!.ReadToEnd()!; + _postPreviewTemplate = typeof(PostEditorView).Assembly.GetManifestResourceStream("MZikmund.App.Templates.PostPreviewTemplate.html")!.ReadToEnd()!; PreviewWebViewContainer.Content = _previewWebView = new WebView2(); this.Loaded += PostEditorView_Loaded; this.Unloaded += PostEditorView_Unloaded; diff --git a/src/app/MZikmund.App/Views/PostView.xaml.cs b/src/app/MZikmund.App/Views/PostView.xaml.cs index f2151839..f9ad75c4 100644 --- a/src/app/MZikmund.App/Views/PostView.xaml.cs +++ b/src/app/MZikmund.App/Views/PostView.xaml.cs @@ -27,7 +27,7 @@ public PostView() { InitializeComponent(); // Read the template from the embedded resource - _postPreviewTemplate = typeof(PostView).Assembly.GetManifestResourceStream("MZikmund.App.Assets.PostPreviewTemplate.html")?.ReadToEnd()!; + _postPreviewTemplate = typeof(PostView).Assembly.GetManifestResourceStream("MZikmund.App.Templates.PostPreviewTemplate.html")?.ReadToEnd()!; PreviewWebViewContainer.Content = _previewWebView = new WebView2(); this.Loaded += PostEditorView_Loaded; this.Unloaded += PostEditorView_Unloaded; diff --git a/src/app/MZikmund.DataContracts/Blog/Post.cs b/src/app/MZikmund.DataContracts/Blog/Post.cs index f2ffd795..0d399a8c 100644 --- a/src/app/MZikmund.DataContracts/Blog/Post.cs +++ b/src/app/MZikmund.DataContracts/Blog/Post.cs @@ -15,6 +15,7 @@ public string Content get => _content.ReplaceLineEndings("\r\n"); set => _content = value; } + public string Abstract { get; set; } = ""; public string? HeroImageUrl { get; set; }