Added basic login

This commit is contained in:
Robert committed 2023-06-22 22:56:24 +02:00
1 parent bde4e861c2
commit 4224875fb0
14 files changed
+524 -5

No files matched your search

@@ -56,8 +56,8 @@
Grid.Column="0"
Grid.RowSpan="3"
VerticalAlignment="Top"
Height="75"
Width="75"
Height="40"
Width="40"
Margin="0 0 15 0"
IsVisible="{CompiledBinding RobertProfileImage, Converter={x:Static StringConverters.IsNotNullOrEmpty}}"
RenderOptions.BitmapInterpolationMode="HighQuality">
@@ -0,0 +1,59 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:currentUser="clr-namespace:Artemis.UI.Screens.Workshop.CurrentUser"
xmlns:avalonia="clr-namespace:Material.Icons.Avalonia;assembly=Material.Icons.Avalonia"
xmlns:controls="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="Artemis.UI.Screens.Workshop.CurrentUser.CurrentUserView"
x:DataType="currentUser:CurrentUserViewModel">
<Panel>
<!-- Signed out -->
<Ellipse Height="28" Width="28" IsVisible="{CompiledBinding !IsLoggedIn}">
<Ellipse.ContextFlyout>
<MenuFlyout>
<MenuItem Header="Login" Command="{CompiledBinding Login}">
<MenuItem.Icon>
<avalonia:MaterialIcon Kind="Login" />
</MenuItem.Icon>
</MenuItem>
</MenuFlyout>
</Ellipse.ContextFlyout>
<Ellipse.Fill>
<ImageBrush Source="/Assets/Images/avatar-placeholder.png" />
</Ellipse.Fill>
</Ellipse>
<!-- Signed in -->
<Ellipse Height="28" Width="28" IsVisible="{CompiledBinding IsLoggedIn}" Name="UserMenu">
<Ellipse.ContextFlyout>
<Flyout>
<Grid ColumnDefinitions="Auto,*" RowDefinitions="*,*,*" MinWidth="300">
<Ellipse Grid.Column="0" Grid.RowSpan="3" Height="50" Width="50" Margin="0 0 8 0" VerticalAlignment="Top">
<Ellipse.Fill>
<ImageBrush Source="{CompiledBinding Avatar}" />
</Ellipse.Fill>
</Ellipse>
<TextBlock Grid.Column="1" Grid.Row="0" Text="{CompiledBinding Name}" Margin="0 4 0 0"></TextBlock>
<TextBlock Grid.Column="1" Grid.Row="1" Text="{CompiledBinding Email}"></TextBlock>
<controls:HyperlinkButton
Grid.Column="1"
Grid.Row="2"
Margin="-8 0 0 0"
Padding="6 4"
Click="Button_OnClick">
Sign out
</controls:HyperlinkButton>
</Grid>
</Flyout>
</Ellipse.ContextFlyout>
<Ellipse.Fill>
<ImageBrush Source="{CompiledBinding Avatar}" />
</Ellipse.Fill>
</Ellipse>
</Panel>
</UserControl>
@@ -0,0 +1,21 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Interactivity;
using Avalonia.Markup.Xaml;
using Avalonia.ReactiveUI;
namespace Artemis.UI.Screens.Workshop.CurrentUser;
public partial class CurrentUserView : ReactiveUserControl<CurrentUserViewModel>
{
public CurrentUserView()
{
InitializeComponent();
}
private void Button_OnClick(object? sender, RoutedEventArgs e)
{
UserMenu.ContextFlyout?.Hide();
ViewModel?.Logout();
}
}
@@ -0,0 +1,104 @@
using System;
using System.Linq;
using System.Reactive;
using System.Reactive.Disposables;
using System.Threading;
using System.Threading.Tasks;
using Artemis.UI.Shared;
using Artemis.WebClient.Workshop.Services;
using Avalonia.Media.Imaging;
using Flurl.Http;
using ReactiveUI;
namespace Artemis.UI.Screens.Workshop.CurrentUser;
public class CurrentUserViewModel : ActivatableViewModelBase
{
private readonly IAuthenticationService _authenticationService;
private ObservableAsPropertyHelper<bool>? _isLoggedIn;
private string? _userId;
private string? _name;
private string? _email;
private Bitmap? _avatar;
public CurrentUserViewModel(IAuthenticationService authenticationService)
{
_authenticationService = authenticationService;
Login = ReactiveCommand.CreateFromTask(ExecuteLogin);
this.WhenActivated(d => _isLoggedIn = _authenticationService.WhenAnyValue(s => s.IsLoggedIn).ToProperty(this, vm => vm.IsLoggedIn).DisposeWith(d));
this.WhenActivated(d =>
{
Task.Run(async () =>
{
await _authenticationService.AutoLogin();
await LoadCurrentUser();
}).DisposeWith(d);
});
}
public void Logout()
{
_authenticationService.Logout();
}
public string? UserId
{
get => _userId;
set => RaiseAndSetIfChanged(ref _userId, value);
}
public string? Name
{
get => _name;
set => RaiseAndSetIfChanged(ref _name, value);
}
public string? Email
{
get => _email;
set => RaiseAndSetIfChanged(ref _email, value);
}
public Bitmap? Avatar
{
get => _avatar;
set => RaiseAndSetIfChanged(ref _avatar, value);
}
public ReactiveCommand<Unit, Unit> Login { get; }
public bool IsLoggedIn => _isLoggedIn?.Value ?? false;
private async Task ExecuteLogin(CancellationToken cancellationToken)
{
await _authenticationService.Login();
await LoadCurrentUser();
Console.WriteLine(_authenticationService.Claims);
}
private async Task LoadCurrentUser()
{
if (!IsLoggedIn)
return;
UserId = _authenticationService.Claims.FirstOrDefault(c => c.Type == "sub")?.Value;
Name = _authenticationService.Claims.FirstOrDefault(c => c.Type == "name")?.Value;
Email = _authenticationService.Claims.FirstOrDefault(c => c.Type == "email")?.Value;
if (UserId != null)
await LoadAvatar(UserId);
}
private async Task LoadAvatar(string userId)
{
try
{
Avatar = new Bitmap(await $"{IAuthenticationService.AUTHORITY}/user/avatar/{userId}".GetStreamAsync());
}
catch (Exception)
{
// ignored
}
}
}
@@ -30,6 +30,7 @@
</ListBox.ItemTemplate>
</ListBox>
</Border>
<ContentControl Grid.Column="1" VerticalAlignment="Top" HorizontalAlignment="Right" Content="{CompiledBinding CurrentUserViewModel}" Margin="8"></ContentControl>
</Grid>
</Border>
</UserControl>
@@ -4,6 +4,7 @@ using System.Reactive;
using System.Reactive.Linq;
using System.Threading.Tasks;
using Artemis.Core;
using Artemis.UI.Screens.Workshop.CurrentUser;
using Artemis.UI.Shared.Services;
using Artemis.UI.Shared.Services.Builders;
using Artemis.WebClient.Workshop;
@@ -18,8 +19,9 @@ public class WorkshopViewModel : MainScreenViewModel
{
private readonly IWorkshopClient _workshopClient;
public WorkshopViewModel(IScreen hostScreen, IWorkshopClient workshopClient) : base(hostScreen, "workshop")
public WorkshopViewModel(IScreen hostScreen, IWorkshopClient workshopClient, CurrentUserViewModel currentUserViewModel) : base(hostScreen, "workshop")
{
CurrentUserViewModel = currentUserViewModel;
_workshopClient = workshopClient;
DisplayName = "Workshop";
@@ -27,7 +29,8 @@ public class WorkshopViewModel : MainScreenViewModel
}
public ObservableCollection<IGetEntries_Entries_Nodes> Test { get; set; } = new();
public CurrentUserViewModel CurrentUserViewModel { get; set; }
private async Task GetEntries()
{