Skip to content

Commit

Permalink
Merge pull request #208 from MartinZikmund/feature/post-editor
Browse files Browse the repository at this point in the history
  • Loading branch information
MartinZikmund authored Dec 3, 2023
2 parents d19054b + cedf9bd commit 55074ae
Show file tree
Hide file tree
Showing 63 changed files with 658 additions and 327 deletions.
Binary file added assets/fonts/CascadiaCode.ttf
Binary file not shown.
18 changes: 9 additions & 9 deletions src/Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -101,14 +101,14 @@
<PackageVersion Include="Uno.Wasm.Bootstrap" Version="8.0.3" />
<PackageVersion Include="Uno.Wasm.Bootstrap.DevServer" Version="8.0.3" />
<PackageVersion Include="Uno.Wasm.Bootstrap.Server" Version="8.0.4" />
<PackageVersion Include="Uno.WinUI" Version="5.1.0-dev.590" />
<PackageVersion Include="Uno.WinUI.MSAL" Version="5.1.0-dev.590" />
<PackageVersion Include="Uno.WinUI.Lottie" Version="5.1.0-dev.590" />
<PackageVersion Include="Uno.WinUI.DevServer" Version="5.1.0-dev.590" />
<PackageVersion Include="Uno.WinUI.Skia.Gtk" Version="5.1.0-dev.590" />
<PackageVersion Include="Uno.WinUI.Skia.Linux.FrameBuffer" Version="5.1.0-dev.590" />
<PackageVersion Include="Uno.WinUI.Skia.Wpf" Version="5.1.0-dev.590" />
<PackageVersion Include="Uno.WinUI.WebAssembly" Version="5.1.0-dev.590" />
<PackageVersion Include="Uno.WinUI" Version="5.1.0-dev.732" />
<PackageVersion Include="Uno.WinUI.MSAL" Version="5.1.0-dev.732" />
<PackageVersion Include="Uno.WinUI.Lottie" Version="5.1.0-dev.732" />
<PackageVersion Include="Uno.WinUI.DevServer" Version="5.1.0-dev.732" />
<PackageVersion Include="Uno.WinUI.Skia.Gtk" Version="5.1.0-dev.732" />
<PackageVersion Include="Uno.WinUI.Skia.Linux.FrameBuffer" Version="5.1.0-dev.732" />
<PackageVersion Include="Uno.WinUI.Skia.Wpf" Version="5.1.0-dev.732" />
<PackageVersion Include="Uno.WinUI.WebAssembly" Version="5.1.0-dev.732" />
<PackageVersion Include="Xamarin.Google.Android.Material" Version="1.10.0.1" />
</ItemGroup>
</Project>
</Project>
12 changes: 0 additions & 12 deletions src/app/MZikmund.DataContracts/Blog/EditCategory.cs

This file was deleted.

10 changes: 0 additions & 10 deletions src/app/MZikmund.DataContracts/Blog/EditTag.cs

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
using MZikmund.DataContracts.Blog;

namespace MZikmund.Web.Core.Dtos;
namespace MZikmund.DataContracts.Blog;

public class Post
{
Expand All @@ -25,4 +23,8 @@ public class Post
public Category[] Categories { get; set; } = Array.Empty<Category>();

public Tag[] Tags { get; set; } = Array.Empty<Tag>();

public string LanguageCode { get; set; } = "en";

public bool IsPublished { get; set; }
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
using MZikmund.DataContracts.Blog;

namespace MZikmund.Web.Core.Dtos;
namespace MZikmund.DataContracts.Blog;

public class PostListItem
{
Expand Down
26 changes: 26 additions & 0 deletions src/app/MZikmund.DataContracts/PagedResponse.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace MZikmund.DataContracts;

public class PagedResponse<T>
{
public PagedResponse(IEnumerable<T> data, int pageNumber, int pageSize, int totalCount)
{
Data = data;
PageNumber = pageNumber;
PageSize = pageSize;
TotalCount = totalCount;
}

public IEnumerable<T> Data { get; }

public int PageNumber { get; }

public int PageSize { get; }

public int TotalCount { get; }
}
2 changes: 2 additions & 0 deletions src/app/MZikmund/App.cs
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,8 @@ private static void ConfigureServices(IServiceCollection services)
services.AddScoped<CategoriesManagerViewModel>();
services.AddScoped<AddOrUpdateCategoryDialogViewModel>();
services.AddScoped<AddOrUpdateTagDialogViewModel>();
services.AddScoped<PostsManagerViewModel>();
services.AddScoped<PostEditorViewModel>();

services.AddSingleton<IThemeManager, ThemeManager>();
services.AddSingleton<IAppPreferences, AppPreferences>();
Expand Down
10 changes: 9 additions & 1 deletion src/app/MZikmund/MZikmund.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,14 @@
</ItemGroup>

<ItemGroup>
<Content Include="..\..\..\assets\fonts\generated\fonts\icomoon.ttf" Link="Assets\Fonts\icomoon.ttf" />
<UpToDateCheckInput Remove="Views\Admin\CategoriesManagerView.xaml" />
<UpToDateCheckInput Remove="Views\Admin\PostEditorView.xaml" />
<UpToDateCheckInput Remove="Views\Admin\PostsManagerView.xaml" />
<UpToDateCheckInput Remove="Views\Admin\TagsManagerView.xaml" />
</ItemGroup>

<ItemGroup>
<Content Include="..\..\..\assets\fonts\generated\fonts\icomoon.ttf" Link="Assets\Fonts\icomoon.ttf" />
<Content Include="..\..\..\assets\fonts\CascadiaCode.ttf" Link="Assets\Fonts\CascadiaCode.ttf" />
</ItemGroup>
</Project>
3 changes: 2 additions & 1 deletion src/app/MZikmund/Resources/Fonts.xaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<FontFamily x:Key="IconFont">ms-appx:///MZikmund/Assets/Fonts/icomoon.ttf#icomoon</FontFamily>
<FontFamily x:Key="IconFont">ms-appx:///MZikmund/Assets/Fonts/icomoon.ttf#icomoon</FontFamily>
<FontFamily x:Key="CodeFont">ms-appx:///MZikmund/Assets/Fonts/CascadiaCode.ttf#Cascadia Code</FontFamily>
<x:String x:Key="HomeGlyph">&#xE901;</x:String>
<x:String x:Key="BlogGlyph">&#xE900;</x:String>
<x:String x:Key="ContactsGlyph">&#xE907;</x:String>
Expand Down
2 changes: 2 additions & 0 deletions src/app/MZikmund/Services/Navigation/INavigationService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ public interface INavigationService
{
void Navigate<TViewModel>();

void Navigate<TViewModel>(object parameter);

bool GoBack();

void Initialize();
Expand Down
6 changes: 4 additions & 2 deletions src/app/MZikmund/Services/Navigation/NavigationService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,16 @@ public bool GoBack()
return false;
}

public void Navigate<TViewModel>()
public void Navigate<TViewModel>() => Navigate<TViewModel>(null);

public void Navigate<TViewModel>(object? parameter)
{
if (!TryFindViewForViewModel(typeof(TViewModel), out var viewType))
{
throw new InvalidOperationException($"ViewModel type {typeof(TViewModel).Name} is not registered for navigation.");
}

Frame.Navigate(viewType);
Frame.Navigate(viewType, parameter);
}

private bool TryFindViewForViewModel(Type viewModelType, out Type? viewType)
Expand Down
11 changes: 0 additions & 11 deletions src/app/MZikmund/ViewModels/Admin/BlogPostEditorViewModel.cs

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@
using MZikmund.Services.Dialogs;
using MZikmund.Services.Loading;
using MZikmund.Services.Localization;
using Newtonsoft.Json;
using Windows.Storage.Pickers;

namespace MZikmund.ViewModels.Admin;

Expand Down Expand Up @@ -96,7 +94,7 @@ private async Task UpdateCategoryAsync(Category? category)
using var loadingScope = _loadingIndicator.BeginLoading();
if (result == ContentDialogResult.Primary)
{
var apiResponse = await _api.UpdateCategoryAsync(category.Id, new EditCategory()
var apiResponse = await _api.UpdateCategoryAsync(category.Id, new Category()
{
DisplayName = viewModel.Category.DisplayName,
RouteName = viewModel.Category.RouteName,
Expand Down
82 changes: 82 additions & 0 deletions src/app/MZikmund/ViewModels/Admin/PostEditorViewModel.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
using MZikmund.Api.Client;
using MZikmund.DataContracts.Blog;
using MZikmund.Services.Loading;

namespace MZikmund.ViewModels.Admin;

public class PostEditorViewModel : PageViewModel
{
private readonly IMZikmundApi _api;
private readonly ILoadingIndicator _loadingIndicator;

public PostEditorViewModel(IMZikmundApi api, ILoadingIndicator loadingIndicator)
{
_api = api;
_loadingIndicator = loadingIndicator;
}

public override string Title => Post?.Title ?? "";

public string Tags { get; set; } = "";

public Category[] Categories { get; set; } = Array.Empty<Category>();

public string CategoriesText => Categories is null ? "" : string.Join(", ", Categories.Select(c => c.DisplayName));

public Post? Post { get; set; }

public ICommand SaveCommand => GetOrCreateAsyncCommand(SaveAsync);

private async Task SaveAsync()
{
if (Post is null)
{
return;
}

var tags = Tags.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries)
.Select(t => new Tag { DisplayName = t.Trim() })
.ToArray();

Post.Tags = tags;
Post.Categories = Categories;

if (Post.Id == Guid.Empty)
{
await _api.AddPostAsync(Post);
}
else
{
await _api.UpdatePostAsync(Post.Id, Post);
}
}

public override void ViewAppeared() => base.ViewAppeared();

public override async void ViewNavigatedTo(object parameter)
{
using var _ = _loadingIndicator.BeginLoading();
var postId = (Guid)parameter;
if (postId == Guid.Empty)
{
Post = new Post();
}
else
{
Post = (await _api.GetPostAsync(postId)).Content;
}

PopulateInfo(Post!);
}

private void PopulateInfo(Post post)
{
if (post is null)
{
throw new ArgumentNullException(nameof(post));
}

Tags = string.Join(", ", post.Tags.Select(t => t.DisplayName));
Categories = post.Categories.ToArray();
}
}
80 changes: 80 additions & 0 deletions src/app/MZikmund/ViewModels/Admin/PostsManagerViewModel.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
using System.Collections.ObjectModel;
using MZikmund.Api.Client;
using MZikmund.DataContracts.Blog;
using MZikmund.Extensions;
using MZikmund.Models.Dialogs;
using MZikmund.Services.Dialogs;
using MZikmund.Services.Loading;
using MZikmund.Services.Localization;
using MZikmund.Services.Navigation;
using Newtonsoft.Json;
using Windows.Storage.Pickers;

namespace MZikmund.ViewModels.Admin;

public class PostsManagerViewModel : PageViewModel
{
private readonly IDialogService _dialogService;
private readonly ILoadingIndicator _loadingIndicator;
private readonly INavigationService _navigationService;
private readonly IMZikmundApi _api;

public PostsManagerViewModel(
IMZikmundApi api,
IDialogService dialogService,
ILoadingIndicator loadingIndicator,
INavigationService navigationService)
{
_dialogService = dialogService ?? throw new ArgumentNullException(nameof(dialogService));
_loadingIndicator = loadingIndicator ?? throw new ArgumentNullException(nameof(loadingIndicator));
_navigationService = navigationService;
_api = api ?? throw new ArgumentNullException(nameof(api));
}

public override string Title => Localizer.Instance.GetString("Posts");

public ObservableCollection<PostListItem> Posts { get; } = new ObservableCollection<PostListItem>();

public override async void ViewAppeared()
{
await RefreshListAsync();
}

private async Task RefreshListAsync()
{
using var loadingScope = _loadingIndicator.BeginLoading();
try
{
//TODO: Refresh collection based on IDs
var posts = await _api.GetPostsAsync();
Posts.Clear();
Posts.AddRange(posts.Content!.Data.OrderByDescending(t => t.LastModifiedDate));
}
catch (Exception ex)
{
await _dialogService.ShowStatusMessageAsync(
StatusMessageDialogType.Error,
"Could not load data",
$"Error occurred loading data from server. {ex}");
}
}

public ICommand AddPostCommand => GetOrCreateCommand(AddPost);

public ICommand UpdatePostCommand => GetOrCreateCommand<PostListItem>(UpdatePost);

private void AddPost()
{
_navigationService.Navigate<PostEditorViewModel>(Guid.Empty);
}

private void UpdatePost(PostListItem? post)
{
if (post is null)
{
return;
}

_navigationService.Navigate<PostEditorViewModel>(post.Id);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ private async Task UpdateTagAsync(Tag? tag)
using var loadingScope = _loadingIndicator.BeginLoading();
if (result == ContentDialogResult.Primary)
{
var apiResponse = await _api.UpdateTagAsync(tag.Id, new EditTag()
var apiResponse = await _api.UpdateTagAsync(tag.Id, new Tag()
{
DisplayName = viewModel.Tag.DisplayName,
RouteName = viewModel.Tag.RouteName,
Expand Down
Loading

0 comments on commit 55074ae

Please sign in to comment.