Added app loaders and screen for the ui. Added identity service. Started auth screens

This commit is contained in:
Masu Baumgartner
2024-10-01 21:02:55 +02:00
parent ca1b7a84c9
commit 522d0c1471
8 changed files with 223 additions and 18 deletions

View File

@@ -0,0 +1,27 @@
using Microsoft.AspNetCore.Components;
using MoonCore.Blazor.Helpers;
using Moonlight.Client.Interfaces;
using Moonlight.Client.Services;
using Moonlight.Client.UI.Screens;
namespace Moonlight.Client.Implementations;
public class AuthenticationUiHandler : IAppLoader, IAppScreen
{
public int Priority => 0;
public Task<bool> ShouldRender(IServiceProvider serviceProvider)
{
var identityService = serviceProvider.GetRequiredService<IdentityService>();
return Task.FromResult(identityService.IsLoggedIn);
}
public RenderFragment Render() => ComponentHelper.FromType<AuthenticationScreen>();
public async Task Load(IServiceProvider serviceProvider)
{
var identityService = serviceProvider.GetRequiredService<IdentityService>();
await identityService.Check();
}
}

View File

@@ -0,0 +1,7 @@
namespace Moonlight.Client.Interfaces;
public interface IAppLoader
{
public int Priority { get; }
public Task Load(IServiceProvider serviceProvider);
}

View File

@@ -0,0 +1,10 @@
using Microsoft.AspNetCore.Components;
namespace Moonlight.Client.Interfaces;
public interface IAppScreen
{
public int Priority { get; }
public Task<bool> ShouldRender(IServiceProvider serviceProvider);
public RenderFragment Render();
}

View File

@@ -25,7 +25,6 @@
<ItemGroup>
<Folder Include="Helpers\" />
<Folder Include="Services\" />
<Folder Include="UI\Components\" />
<Folder Include="wwwroot\css\" />
</ItemGroup>

View File

@@ -55,6 +55,10 @@ var implementationService = new ImplementationService();
implementationService.Register<ISidebarItemProvider, DefaultSidebarItemProvider>();
var authUiHandler = new AuthenticationUiHandler();
implementationService.Register<IAppScreen>(authUiHandler);
implementationService.Register<IAppLoader>(authUiHandler);
builder.Services.AddSingleton(implementationService);
await builder.Build().RunAsync();

View File

@@ -0,0 +1,57 @@
using MoonCore.Blazor.Tailwind.Services;
using MoonCore.Exceptions;
using MoonCore.Helpers;
using Moonlight.Shared.Http.Responses.Auth;
namespace Moonlight.Client.Services;
public class IdentityService
{
public string Username { get; private set; }
public string Email { get; private set; }
public string[] Permissions { get; private set; }
public bool IsLoggedIn { get; private set; }
public event Func<Task> OnStateChanged;
private readonly CookieService CookieService;
private readonly HttpApiClient ApiClient;
public IdentityService(CookieService cookieService, HttpApiClient apiClient)
{
CookieService = cookieService;
ApiClient = apiClient;
}
public async Task Check()
{
try
{
var response = await ApiClient.GetJson<CheckResponse>("api/auth/check");
Username = response.Username;
Email = response.Email;
Permissions = response.Permissions;
IsLoggedIn = true;
}
catch (HttpApiException)
{
IsLoggedIn = false;
}
await OnStateChanged();
}
public async Task Login(string token)
{
await CookieService.SetValue("token", token, 30);
await Check();
}
public async Task Logout()
{
await CookieService.SetValue("token", "", 30);
await Check();
}
}

View File

@@ -1,30 +1,53 @@
@using MoonCore.Helpers
@using MoonCore.PluginFramework.Services
@using Moonlight.Client.Interfaces
@using Moonlight.Client.UI.Partials
@inherits LayoutComponentBase
<div>
<AppSidebar Layout="this" />
<div class="lg:pl-72">
<AppHeader Layout="this"/>
@inject ImplementationService ImplementationService
@inject IServiceProvider ServiceProvider
@inject ILogger<MainLayout> Logger
<ErrorHandler>
<main class="py-10">
<div class="px-4 sm:px-6 lg:px-8">
@Body
</div>
</main>
</ErrorHandler>
@if (IsLoading)
{
<LazyLoader Load="Load">
<ToastLauncher />
<ModalLauncher />
</LazyLoader>
}
else if (CurrentScreen != null)
{
@CurrentScreen
}
else
{
<div>
<AppSidebar Layout="this"/>
<div class="lg:pl-72">
<AppHeader Layout="this"/>
<ErrorHandler>
<main class="py-10">
<div class="px-4 sm:px-6 lg:px-8">
<CascadingValue Value="this" IsFixed="true">
@Body
</CascadingValue>
</div>
</main>
</ErrorHandler>
</div>
</div>
</div>
}
<ToastLauncher/>
<ModalLauncher/>
@code
{
public event Func<Task> OnStateChanged;
// Mobile navigation
public event Func<Task> OnStateChanged;
public bool ShowMobileNavigation { get; private set; } = false;
public async Task ToggleMobileNavigation()
@@ -32,4 +55,64 @@
ShowMobileNavigation = !ShowMobileNavigation;
await OnStateChanged();
}
}
// App loaders & screens
private bool IsLoading = true;
private RenderFragment? CurrentScreen;
private async Task Load(LazyLoader lazyLoader)
{
await lazyLoader.UpdateText("Retrieving data");
await RunLoaders();
await RenderScreens();
IsLoading = false;
await InvokeAsync(StateHasChanged);
}
public async Task Reload()
{
IsLoading = true;
await InvokeAsync(StateHasChanged);
}
private async Task RunLoaders()
{
var appLoaders = ImplementationService
.Get<IAppLoader>()
.OrderBy(x => x.Priority);
foreach (var loader in appLoaders) //TODO: Measure performance of every loader?
{
try
{
await loader.Load(ServiceProvider);
}
catch (Exception e)
{
Logger.LogCritical("An app loader threw an unhandled exception: {e}", e);
}
}
}
public async Task RenderScreens()
{
CurrentScreen = null;
var appScreens = ImplementationService
.Get<IAppScreen>()
.OrderBy(x => x.Priority);
foreach (var screen in appScreens)
{
if (!await screen.ShouldRender(ServiceProvider))
continue;
CurrentScreen = screen.Render();
await InvokeAsync(StateHasChanged);
return;
}
}
}

View File

@@ -0,0 +1,18 @@
@page "/auth/register"
@page "/auth/login"
@inject NavigationManager Navigation
@{
var url = new Uri(Navigation.Uri);
var isRegister = url.LocalPath.StartsWith("/auth/register");
}
@if (isRegister)
{
}
else
{
}