mirror of
https://github.com/Artemis-RGB/Artemis
synced 2026-02-04 10:53:31 +00:00
Submission wizard - Added Lottie animations and the first few steps
This commit is contained in:
parent
661242ebf9
commit
78cb95aabc
@ -24,6 +24,7 @@
|
|||||||
<!--Condition below is needed to remove Avalonia.Diagnostics package from build output in Release configuration.-->
|
<!--Condition below is needed to remove Avalonia.Diagnostics package from build output in Release configuration.-->
|
||||||
<PackageReference Condition="'$(Configuration)' == 'Debug'" Include="Avalonia.Diagnostics" Version="$(AvaloniaVersion)" />
|
<PackageReference Condition="'$(Configuration)' == 'Debug'" Include="Avalonia.Diagnostics" Version="$(AvaloniaVersion)" />
|
||||||
<PackageReference Include="Avalonia.ReactiveUI" Version="$(AvaloniaVersion)" />
|
<PackageReference Include="Avalonia.ReactiveUI" Version="$(AvaloniaVersion)" />
|
||||||
|
<PackageReference Include="Avalonia.Skia.Lottie" Version="11.0.0" />
|
||||||
<PackageReference Include="Avalonia.Xaml.Behaviors" Version="$(AvaloniaVersion)" />
|
<PackageReference Include="Avalonia.Xaml.Behaviors" Version="$(AvaloniaVersion)" />
|
||||||
<PackageReference Include="DryIoc.dll" Version="5.4.0" />
|
<PackageReference Include="DryIoc.dll" Version="5.4.0" />
|
||||||
<PackageReference Include="DynamicData" Version="7.13.1" />
|
<PackageReference Include="DynamicData" Version="7.13.1" />
|
||||||
|
|||||||
1
src/Artemis.UI/Assets/Animations/email.json
Normal file
1
src/Artemis.UI/Assets/Animations/email.json
Normal file
File diff suppressed because one or more lines are too long
1
src/Artemis.UI/Assets/Animations/login-pending.json
Normal file
1
src/Artemis.UI/Assets/Animations/login-pending.json
Normal file
File diff suppressed because one or more lines are too long
1
src/Artemis.UI/Assets/Animations/password.json
Normal file
1
src/Artemis.UI/Assets/Animations/password.json
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
1
src/Artemis.UI/Assets/Animations/workshop-wizard.json
Normal file
1
src/Artemis.UI/Assets/Animations/workshop-wizard.json
Normal file
File diff suppressed because one or more lines are too long
@ -9,9 +9,9 @@
|
|||||||
x:Class="Artemis.UI.Screens.Workshop.CurrentUser.CurrentUserView"
|
x:Class="Artemis.UI.Screens.Workshop.CurrentUser.CurrentUserView"
|
||||||
x:DataType="currentUser:CurrentUserViewModel">
|
x:DataType="currentUser:CurrentUserViewModel">
|
||||||
|
|
||||||
<Panel Name="Container" IsVisible="{CompiledBinding !Loading}">
|
<Panel Name="Container">
|
||||||
<!-- Signed out -->
|
<!-- Signed out -->
|
||||||
<Ellipse Height="{CompiledBinding Bounds.Height, ElementName=Container}" Width="{CompiledBinding Bounds.Height, ElementName=Container}" IsVisible="{CompiledBinding Name, Converter={x:Static StringConverters.IsNullOrEmpty}}">
|
<Ellipse Height="{CompiledBinding Bounds.Height, ElementName=Container}" Width="{CompiledBinding Bounds.Height, ElementName=Container}" IsVisible="{CompiledBinding IsAnonymous}">
|
||||||
<Ellipse.ContextFlyout>
|
<Ellipse.ContextFlyout>
|
||||||
<MenuFlyout>
|
<MenuFlyout>
|
||||||
<MenuItem Header="Login" Command="{CompiledBinding Login}">
|
<MenuItem Header="Login" Command="{CompiledBinding Login}">
|
||||||
@ -27,7 +27,7 @@
|
|||||||
</Ellipse>
|
</Ellipse>
|
||||||
|
|
||||||
<!-- Signed in -->
|
<!-- Signed in -->
|
||||||
<Ellipse Height="{CompiledBinding Bounds.Height, ElementName=Container}" Width="{CompiledBinding Bounds.Height, ElementName=Container}" IsVisible="{CompiledBinding Name, Converter={x:Static StringConverters.IsNotNullOrEmpty}}" Name="UserMenu">
|
<Ellipse Height="{CompiledBinding Bounds.Height, ElementName=Container}" Width="{CompiledBinding Bounds.Height, ElementName=Container}" IsVisible="{CompiledBinding !IsAnonymous}" Name="UserMenu">
|
||||||
<Ellipse.ContextFlyout>
|
<Ellipse.ContextFlyout>
|
||||||
<Flyout>
|
<Flyout>
|
||||||
<Grid ColumnDefinitions="Auto,*" RowDefinitions="*,*,*" MinWidth="300">
|
<Grid ColumnDefinitions="Auto,*" RowDefinitions="*,*,*" MinWidth="300">
|
||||||
@ -39,6 +39,7 @@
|
|||||||
<TextBlock Grid.Column="1" Grid.Row="0" Text="{CompiledBinding Name}" Margin="0 4 0 0"></TextBlock>
|
<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>
|
<TextBlock Grid.Column="1" Grid.Row="1" Text="{CompiledBinding Email}"></TextBlock>
|
||||||
<controls:HyperlinkButton
|
<controls:HyperlinkButton
|
||||||
|
IsVisible="{CompiledBinding AllowLogout}"
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
Grid.Row="2"
|
Grid.Row="2"
|
||||||
Margin="-8 0 0 0"
|
Margin="-8 0 0 0"
|
||||||
@ -54,6 +55,4 @@
|
|||||||
</Ellipse.Fill>
|
</Ellipse.Fill>
|
||||||
</Ellipse>
|
</Ellipse>
|
||||||
</Panel>
|
</Panel>
|
||||||
|
|
||||||
|
|
||||||
</UserControl>
|
</UserControl>
|
||||||
@ -19,8 +19,10 @@ namespace Artemis.UI.Screens.Workshop.CurrentUser;
|
|||||||
public class CurrentUserViewModel : ActivatableViewModelBase
|
public class CurrentUserViewModel : ActivatableViewModelBase
|
||||||
{
|
{
|
||||||
private readonly IAuthenticationService _authenticationService;
|
private readonly IAuthenticationService _authenticationService;
|
||||||
|
private readonly ObservableAsPropertyHelper<bool> _isAnonymous;
|
||||||
private readonly ILogger _logger;
|
private readonly ILogger _logger;
|
||||||
private readonly IWindowService _windowService;
|
private readonly IWindowService _windowService;
|
||||||
|
private bool _allowLogout = true;
|
||||||
private Bitmap? _avatar;
|
private Bitmap? _avatar;
|
||||||
private string? _email;
|
private string? _email;
|
||||||
private bool _loading = true;
|
private bool _loading = true;
|
||||||
@ -34,6 +36,8 @@ public class CurrentUserViewModel : ActivatableViewModelBase
|
|||||||
_windowService = windowService;
|
_windowService = windowService;
|
||||||
Login = ReactiveCommand.CreateFromTask(ExecuteLogin);
|
Login = ReactiveCommand.CreateFromTask(ExecuteLogin);
|
||||||
|
|
||||||
|
_isAnonymous = this.WhenAnyValue(vm => vm.Loading, vm => vm.Name, (l, n) => l || n == null).ToProperty(this, vm => vm.IsAnonymous);
|
||||||
|
|
||||||
this.WhenActivated(d =>
|
this.WhenActivated(d =>
|
||||||
{
|
{
|
||||||
Task.Run(AutoLogin);
|
Task.Run(AutoLogin);
|
||||||
@ -41,40 +45,49 @@ public class CurrentUserViewModel : ActivatableViewModelBase
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool IsAnonymous => _isAnonymous.Value;
|
||||||
|
|
||||||
|
public bool AllowLogout
|
||||||
|
{
|
||||||
|
get => _allowLogout;
|
||||||
|
set => RaiseAndSetIfChanged(ref _allowLogout, value);
|
||||||
|
}
|
||||||
|
|
||||||
public bool Loading
|
public bool Loading
|
||||||
{
|
{
|
||||||
get => _loading;
|
get => _loading;
|
||||||
set => RaiseAndSetIfChanged(ref _loading, value);
|
private set => RaiseAndSetIfChanged(ref _loading, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public string? UserId
|
public string? UserId
|
||||||
{
|
{
|
||||||
get => _userId;
|
get => _userId;
|
||||||
set => RaiseAndSetIfChanged(ref _userId, value);
|
private set => RaiseAndSetIfChanged(ref _userId, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public string? Name
|
public string? Name
|
||||||
{
|
{
|
||||||
get => _name;
|
get => _name;
|
||||||
set => RaiseAndSetIfChanged(ref _name, value);
|
private set => RaiseAndSetIfChanged(ref _name, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public string? Email
|
public string? Email
|
||||||
{
|
{
|
||||||
get => _email;
|
get => _email;
|
||||||
set => RaiseAndSetIfChanged(ref _email, value);
|
private set => RaiseAndSetIfChanged(ref _email, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Bitmap? Avatar
|
public Bitmap? Avatar
|
||||||
{
|
{
|
||||||
get => _avatar;
|
get => _avatar;
|
||||||
set => RaiseAndSetIfChanged(ref _avatar, value);
|
private set => RaiseAndSetIfChanged(ref _avatar, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ReactiveCommand<Unit, Unit> Login { get; }
|
public ReactiveCommand<Unit, Unit> Login { get; }
|
||||||
|
|
||||||
public void Logout()
|
public void Logout()
|
||||||
{
|
{
|
||||||
|
if (AllowLogout)
|
||||||
_authenticationService.Logout();
|
_authenticationService.Logout();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -8,13 +8,10 @@
|
|||||||
x:DataType="currentUser:WorkshopLoginViewModel">
|
x:DataType="currentUser:WorkshopLoginViewModel">
|
||||||
<StackPanel Width="400">
|
<StackPanel Width="400">
|
||||||
<TextBlock TextWrapping="Wrap">
|
<TextBlock TextWrapping="Wrap">
|
||||||
In order to login you must enter your Artemis credentials in a browser.
|
A browser window has opened where you'll be able to create an account and/or log in.
|
||||||
</TextBlock>
|
|
||||||
<TextBlock TextWrapping="Wrap" Margin="0 15">
|
|
||||||
If you do not have an account yet you can create one in the browser too. Alternatively you can log in with Google or Discord.
|
|
||||||
</TextBlock>
|
</TextBlock>
|
||||||
|
|
||||||
<TextBlock>Waiting for login...</TextBlock>
|
<TextBlock Margin="0 15 0 0">Waiting for log in...</TextBlock>
|
||||||
<ProgressBar Margin="0 5 0 0" IsIndeterminate="True"></ProgressBar>
|
<ProgressBar Margin="0 5 0 0" IsIndeterminate="True"></ProgressBar>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</UserControl>
|
</UserControl>
|
||||||
@ -0,0 +1,48 @@
|
|||||||
|
<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:steps="clr-namespace:Artemis.UI.Screens.Workshop.SubmissionWizard.Steps"
|
||||||
|
xmlns:workshop="clr-namespace:Artemis.WebClient.Workshop;assembly=Artemis.WebClient.Workshop"
|
||||||
|
xmlns:converters="clr-namespace:Artemis.UI.Shared.Converters;assembly=Artemis.UI.Shared"
|
||||||
|
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||||
|
x:Class="Artemis.UI.Screens.Workshop.SubmissionWizard.Steps.EntryTypeView"
|
||||||
|
x:DataType="steps:EntryTypeViewModel">
|
||||||
|
<UserControl.Resources>
|
||||||
|
<converters:EnumToBooleanConverter x:Key="EnumBoolConverter" />
|
||||||
|
</UserControl.Resources>
|
||||||
|
<StackPanel>
|
||||||
|
<StackPanel.Styles>
|
||||||
|
<Styles>
|
||||||
|
<Style Selector="TextBlock">
|
||||||
|
<Setter Property="TextWrapping" Value="Wrap"></Setter>
|
||||||
|
</Style>
|
||||||
|
</Styles>
|
||||||
|
</StackPanel.Styles>
|
||||||
|
<TextBlock Theme="{StaticResource TitleTextBlockStyle}" TextWrapping="Wrap">
|
||||||
|
Submission type
|
||||||
|
</TextBlock>
|
||||||
|
<TextBlock TextWrapping="Wrap">
|
||||||
|
Please select the type of content you want to submit to the workshop.
|
||||||
|
</TextBlock>
|
||||||
|
<RadioButton GroupName="EntryType"
|
||||||
|
Margin="0 15 0 0"
|
||||||
|
IsChecked="{CompiledBinding SelectedEntryType, Converter={StaticResource EnumBoolConverter}, ConverterParameter={x:Static workshop:EntryType.Profile}}" >
|
||||||
|
<RadioButton.Content>
|
||||||
|
<StackPanel>
|
||||||
|
<TextBlock>Profile</TextBlock>
|
||||||
|
<TextBlock Classes="subtitle" TextWrapping="Wrap">A profile which others can install to enjoy new lighting and interactions.</TextBlock>
|
||||||
|
</StackPanel>
|
||||||
|
</RadioButton.Content>
|
||||||
|
</RadioButton>
|
||||||
|
<RadioButton GroupName="EntryType"
|
||||||
|
IsChecked="{CompiledBinding SelectedEntryType, Converter={StaticResource EnumBoolConverter}, ConverterParameter={x:Static workshop:EntryType.Layout}}">
|
||||||
|
<RadioButton.Content>
|
||||||
|
<StackPanel>
|
||||||
|
<TextBlock>Layout</TextBlock>
|
||||||
|
<TextBlock Classes="subtitle" TextWrapping="Wrap">A layout providing users with a visual representation of a device.</TextBlock>
|
||||||
|
</StackPanel>
|
||||||
|
</RadioButton.Content>
|
||||||
|
</RadioButton>
|
||||||
|
</StackPanel>
|
||||||
|
</UserControl>
|
||||||
@ -0,0 +1,17 @@
|
|||||||
|
using Avalonia.Markup.Xaml;
|
||||||
|
using Avalonia.ReactiveUI;
|
||||||
|
|
||||||
|
namespace Artemis.UI.Screens.Workshop.SubmissionWizard.Steps;
|
||||||
|
|
||||||
|
public partial class EntryTypeView : ReactiveUserControl<EntryTypeViewModel>
|
||||||
|
{
|
||||||
|
public EntryTypeView()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void InitializeComponent()
|
||||||
|
{
|
||||||
|
AvaloniaXamlLoader.Load(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,41 @@
|
|||||||
|
using System;
|
||||||
|
using System.Reactive;
|
||||||
|
using System.Reactive.Linq;
|
||||||
|
using Artemis.WebClient.Workshop;
|
||||||
|
using ReactiveUI;
|
||||||
|
|
||||||
|
namespace Artemis.UI.Screens.Workshop.SubmissionWizard.Steps;
|
||||||
|
|
||||||
|
public class EntryTypeViewModel : SubmissionViewModel
|
||||||
|
{
|
||||||
|
private EntryType? _selectedEntryType;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public EntryTypeViewModel()
|
||||||
|
{
|
||||||
|
GoBack = ReactiveCommand.Create(() => State.ChangeScreen<WelcomeStepViewModel>());
|
||||||
|
Continue = ReactiveCommand.Create(ExecuteContinue, this.WhenAnyValue(vm => vm.SelectedEntryType).Select(e => e != null));
|
||||||
|
}
|
||||||
|
|
||||||
|
public EntryType? SelectedEntryType
|
||||||
|
{
|
||||||
|
get => _selectedEntryType;
|
||||||
|
set => RaiseAndSetIfChanged(ref _selectedEntryType, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override ReactiveCommand<Unit, Unit> Continue { get; }
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override ReactiveCommand<Unit, Unit> GoBack { get; }
|
||||||
|
|
||||||
|
private void ExecuteContinue()
|
||||||
|
{
|
||||||
|
if (SelectedEntryType == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
State.EntryType = SelectedEntryType.Value;
|
||||||
|
if (State.EntryType == EntryType.Profile)
|
||||||
|
State.ChangeScreen<ProfileSelectionStepViewModel>();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,33 @@
|
|||||||
|
<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:steps="clr-namespace:Artemis.UI.Screens.Workshop.SubmissionWizard.Steps"
|
||||||
|
mc:Ignorable="d" d:DesignWidth="970" d:DesignHeight="625"
|
||||||
|
x:Class="Artemis.UI.Screens.Workshop.SubmissionWizard.Steps.LoginStepView"
|
||||||
|
x:DataType="steps:LoginStepViewModel">
|
||||||
|
<StackPanel>
|
||||||
|
<StackPanel.Styles>
|
||||||
|
<Styles>
|
||||||
|
<Style Selector="TextBlock">
|
||||||
|
<Setter Property="TextAlignment" Value="Center"></Setter>
|
||||||
|
<Setter Property="TextWrapping" Value="Wrap"></Setter>
|
||||||
|
</Style>
|
||||||
|
</Styles>
|
||||||
|
</StackPanel.Styles>
|
||||||
|
<TextBlock Theme="{StaticResource TitleTextBlockStyle}">First things first</TextBlock>
|
||||||
|
<TextBlock>
|
||||||
|
<Run>In order to submit anything to the workshop you must be logged in.</Run>
|
||||||
|
<LineBreak />
|
||||||
|
<Run>Creating an account is free and we'll not bother you with a newsletter or crap like that.</Run>
|
||||||
|
</TextBlock>
|
||||||
|
|
||||||
|
<Lottie Path="/Assets/Animations/login-pending.json" RepeatCount="-1" Width="250" Height="250"></Lottie>
|
||||||
|
|
||||||
|
<TextBlock>
|
||||||
|
<Run>Click continue to (create an account) and log in.</Run>
|
||||||
|
<LineBreak/>
|
||||||
|
<Run>You'll also be able to log in with Google or Discord.</Run>
|
||||||
|
</TextBlock>
|
||||||
|
</StackPanel>
|
||||||
|
</UserControl>
|
||||||
@ -0,0 +1,17 @@
|
|||||||
|
using Avalonia.Markup.Xaml;
|
||||||
|
using Avalonia.ReactiveUI;
|
||||||
|
|
||||||
|
namespace Artemis.UI.Screens.Workshop.SubmissionWizard.Steps;
|
||||||
|
|
||||||
|
public partial class LoginStepView : ReactiveUserControl<LoginStepView>
|
||||||
|
{
|
||||||
|
public LoginStepView()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void InitializeComponent()
|
||||||
|
{
|
||||||
|
AvaloniaXamlLoader.Load(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,50 @@
|
|||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reactive;
|
||||||
|
using System.Security.Claims;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Artemis.UI.Screens.Workshop.CurrentUser;
|
||||||
|
using Artemis.UI.Shared.Services;
|
||||||
|
using Artemis.WebClient.Workshop.Services;
|
||||||
|
using FluentAvalonia.UI.Controls;
|
||||||
|
using IdentityModel;
|
||||||
|
using ReactiveUI;
|
||||||
|
|
||||||
|
namespace Artemis.UI.Screens.Workshop.SubmissionWizard.Steps;
|
||||||
|
|
||||||
|
public class LoginStepViewModel : SubmissionViewModel
|
||||||
|
{
|
||||||
|
private readonly IAuthenticationService _authenticationService;
|
||||||
|
private readonly IWindowService _windowService;
|
||||||
|
|
||||||
|
public LoginStepViewModel(IAuthenticationService authenticationService, IWindowService windowService)
|
||||||
|
{
|
||||||
|
_authenticationService = authenticationService;
|
||||||
|
_windowService = windowService;
|
||||||
|
|
||||||
|
Continue = ReactiveCommand.CreateFromTask(ExecuteLogin);
|
||||||
|
ShowGoBack = false;
|
||||||
|
ShowHeader = false;
|
||||||
|
ContinueText = "Log In";
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override ReactiveCommand<Unit, Unit> Continue { get; }
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override ReactiveCommand<Unit, Unit> GoBack { get; } = null!;
|
||||||
|
|
||||||
|
private async Task ExecuteLogin(CancellationToken ct)
|
||||||
|
{
|
||||||
|
ContentDialogResult result = await _windowService.CreateContentDialog().WithViewModel(out WorkshopLoginViewModel _).WithTitle("Workshop login").ShowAsync();
|
||||||
|
if (result != ContentDialogResult.Primary)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Claim? emailVerified = _authenticationService.Claims.FirstOrDefault(c => c.Type == JwtClaimTypes.EmailVerified);
|
||||||
|
if (emailVerified?.Value == "true")
|
||||||
|
State.ChangeScreen<EntryTypeViewModel>();
|
||||||
|
else
|
||||||
|
State.ChangeScreen<ValidateEmailStepViewModel>();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,10 @@
|
|||||||
|
<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:steps="clr-namespace:Artemis.UI.Screens.Workshop.SubmissionWizard.Steps"
|
||||||
|
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||||
|
x:Class="Artemis.UI.Screens.Workshop.SubmissionWizard.Steps.ProfileSelectionStepView"
|
||||||
|
x:DataType="steps:ProfileSelectionStepViewModel">
|
||||||
|
Welcome to Avalonia!
|
||||||
|
</UserControl>
|
||||||
@ -0,0 +1,18 @@
|
|||||||
|
using Avalonia;
|
||||||
|
using Avalonia.Controls;
|
||||||
|
using Avalonia.Markup.Xaml;
|
||||||
|
|
||||||
|
namespace Artemis.UI.Screens.Workshop.SubmissionWizard.Steps;
|
||||||
|
|
||||||
|
public partial class ProfileSelectionStepView : UserControl
|
||||||
|
{
|
||||||
|
public ProfileSelectionStepView()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void InitializeComponent()
|
||||||
|
{
|
||||||
|
AvaloniaXamlLoader.Load(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,13 @@
|
|||||||
|
using System.Reactive;
|
||||||
|
using ReactiveUI;
|
||||||
|
|
||||||
|
namespace Artemis.UI.Screens.Workshop.SubmissionWizard.Steps;
|
||||||
|
|
||||||
|
public class ProfileSelectionStepViewModel : SubmissionViewModel
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override ReactiveCommand<Unit, Unit> Continue { get; }
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override ReactiveCommand<Unit, Unit> GoBack { get; }
|
||||||
|
}
|
||||||
@ -0,0 +1,41 @@
|
|||||||
|
<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:steps="clr-namespace:Artemis.UI.Screens.Workshop.SubmissionWizard.Steps"
|
||||||
|
xmlns:avalonia="clr-namespace:Material.Icons.Avalonia;assembly=Material.Icons.Avalonia"
|
||||||
|
mc:Ignorable="d" d:DesignWidth="970" d:DesignHeight="625"
|
||||||
|
x:Class="Artemis.UI.Screens.Workshop.SubmissionWizard.Steps.ValidateEmailStepView"
|
||||||
|
x:DataType="steps:ValidateEmailStepViewModel">
|
||||||
|
<StackPanel >
|
||||||
|
<StackPanel.Styles>
|
||||||
|
<Styles>
|
||||||
|
<Style Selector="TextBlock">
|
||||||
|
<Setter Property="TextAlignment" Value="Center"></Setter>
|
||||||
|
</Style>
|
||||||
|
</Styles>
|
||||||
|
</StackPanel.Styles>
|
||||||
|
<TextBlock Theme="{StaticResource TitleTextBlockStyle}" TextWrapping="Wrap">Confirm email address</TextBlock>
|
||||||
|
<TextBlock TextWrapping="Wrap">
|
||||||
|
<Run>Before you can continue, please confirm your email address.</Run> (<Run Text="{CompiledBinding Email.Value}"></Run>)
|
||||||
|
<LineBreak />
|
||||||
|
<Run>You'll find the confirmation mail in your inbox.</Run>
|
||||||
|
<LineBreak />
|
||||||
|
<LineBreak />
|
||||||
|
<TextBlock>Don't see an email? Check your spam box!</TextBlock>
|
||||||
|
</TextBlock>
|
||||||
|
|
||||||
|
<Lottie Path="/Assets/Animations/email.json" RepeatCount="-1" Width="200" Height="200"></Lottie>
|
||||||
|
|
||||||
|
<Button Margin="0 0 0 15" HorizontalAlignment="Center" Command="{CompiledBinding Refresh}">
|
||||||
|
<StackPanel Orientation="Horizontal" Spacing="5">
|
||||||
|
<avalonia:MaterialIcon Kind="Refresh" />
|
||||||
|
<TextBlock>Refresh</TextBlock>
|
||||||
|
</StackPanel>
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
<TextBlock Theme="{StaticResource CaptionTextBlockStyle}">
|
||||||
|
PS: We take this step to avoid the workshop getting spammed with low quality content.
|
||||||
|
</TextBlock>
|
||||||
|
</StackPanel>
|
||||||
|
</UserControl>
|
||||||
@ -0,0 +1,17 @@
|
|||||||
|
using Avalonia.Markup.Xaml;
|
||||||
|
using Avalonia.ReactiveUI;
|
||||||
|
|
||||||
|
namespace Artemis.UI.Screens.Workshop.SubmissionWizard.Steps;
|
||||||
|
|
||||||
|
public partial class ValidateEmailStepView : ReactiveUserControl<ValidateEmailStepViewModel>
|
||||||
|
{
|
||||||
|
public ValidateEmailStepView()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void InitializeComponent()
|
||||||
|
{
|
||||||
|
AvaloniaXamlLoader.Load(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,78 @@
|
|||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reactive;
|
||||||
|
using System.Reactive.Disposables;
|
||||||
|
using System.Security.Claims;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Artemis.WebClient.Workshop.Services;
|
||||||
|
using IdentityModel;
|
||||||
|
using ReactiveUI;
|
||||||
|
using Timer = System.Timers.Timer;
|
||||||
|
|
||||||
|
namespace Artemis.UI.Screens.Workshop.SubmissionWizard.Steps;
|
||||||
|
|
||||||
|
public class ValidateEmailStepViewModel : SubmissionViewModel
|
||||||
|
{
|
||||||
|
private readonly IAuthenticationService _authenticationService;
|
||||||
|
private ObservableAsPropertyHelper<Claim?>? _email;
|
||||||
|
|
||||||
|
public ValidateEmailStepViewModel(IAuthenticationService authenticationService)
|
||||||
|
{
|
||||||
|
_authenticationService = authenticationService;
|
||||||
|
|
||||||
|
Continue = ReactiveCommand.Create(ExecuteContinue);
|
||||||
|
Refresh = ReactiveCommand.CreateFromTask(ExecuteRefresh);
|
||||||
|
ShowGoBack = false;
|
||||||
|
ShowHeader = false;
|
||||||
|
|
||||||
|
this.WhenActivated(d =>
|
||||||
|
{
|
||||||
|
_email = authenticationService.GetClaim(JwtClaimTypes.Email).ToProperty(this, vm => vm.Email).DisposeWith(d);
|
||||||
|
|
||||||
|
Timer updateTimer = new(TimeSpan.FromSeconds(15));
|
||||||
|
updateTimer.Elapsed += (_, _) => Task.Run(Update);
|
||||||
|
updateTimer.Start();
|
||||||
|
|
||||||
|
updateTimer.DisposeWith(d);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override ReactiveCommand<Unit, Unit> Continue { get; }
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override ReactiveCommand<Unit, Unit> GoBack { get; } = null!;
|
||||||
|
|
||||||
|
public ReactiveCommand<Unit, Unit> Refresh { get; }
|
||||||
|
|
||||||
|
public Claim? Email => _email?.Value;
|
||||||
|
|
||||||
|
private async Task Update()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Use the refresh token to login again, updating claims
|
||||||
|
await _authenticationService.AutoLogin(true);
|
||||||
|
|
||||||
|
Claim? emailVerified = _authenticationService.Claims.FirstOrDefault(c => c.Type == JwtClaimTypes.EmailVerified);
|
||||||
|
if (emailVerified?.Value == "true")
|
||||||
|
ExecuteContinue();
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
// ignored, meh
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ExecuteContinue()
|
||||||
|
{
|
||||||
|
State.ChangeScreen<EntryTypeViewModel>();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task ExecuteRefresh(CancellationToken ct)
|
||||||
|
{
|
||||||
|
await Update();
|
||||||
|
await Task.Delay(1000, ct);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -3,50 +3,17 @@
|
|||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
xmlns:steps="clr-namespace:Artemis.UI.Screens.Workshop.SubmissionWizard.Steps"
|
xmlns:steps="clr-namespace:Artemis.UI.Screens.Workshop.SubmissionWizard.Steps"
|
||||||
xmlns:avalonia="clr-namespace:Material.Icons.Avalonia;assembly=Material.Icons.Avalonia"
|
mc:Ignorable="d" d:DesignWidth="970" d:DesignHeight="625"
|
||||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
|
||||||
x:Class="Artemis.UI.Screens.Workshop.SubmissionWizard.Steps.WelcomeStepView"
|
x:Class="Artemis.UI.Screens.Workshop.SubmissionWizard.Steps.WelcomeStepView"
|
||||||
x:DataType="steps:WelcomeStepViewModel">
|
x:DataType="steps:WelcomeStepViewModel">
|
||||||
<StackPanel>
|
<StackPanel Margin="0 50 0 0" >
|
||||||
<TextBlock Theme="{StaticResource TitleTextBlockStyle}">Welcome to the Workshop Submission Wizard 🧙</TextBlock>
|
<TextBlock Theme="{StaticResource TitleTextBlockStyle}" TextAlignment="Center" TextWrapping="Wrap">
|
||||||
<TextBlock>Here we'll take you, step by step, through the process of uploading your submission to the workshop.</TextBlock>
|
Welcome to the Workshop Submission Wizard 🧙
|
||||||
|
</TextBlock>
|
||||||
<StackPanel IsVisible="{CompiledBinding !IsLoggedIn}" Margin="0 35 0 0">
|
<TextBlock TextAlignment="Center" TextWrapping="Wrap">
|
||||||
<TextBlock Theme="{StaticResource SubtitleTextBlockStyle}" TextWrapping="Wrap">First things first</TextBlock>
|
Here we'll take you, step by step, through the process of uploading your submission to the workshop.
|
||||||
<TextBlock TextWrapping="Wrap">
|
|
||||||
<Run>In order to submit anything to the workshop you must be logged in.</Run>
|
|
||||||
<LineBreak />
|
|
||||||
<LineBreak />
|
|
||||||
<Run>Creating an account is free and we'll not bother you with a newsletter or crap like that. You can also log in with Google or Discord.</Run>
|
|
||||||
</TextBlock>
|
</TextBlock>
|
||||||
|
|
||||||
<Button Margin="0 15 0 0" Command="{CompiledBinding Login}">
|
<Lottie Path="/Assets/Animations/workshop-wizard.json" RepeatCount="1" Width="300" Height="400"></Lottie>
|
||||||
<StackPanel Orientation="Horizontal" Spacing="5">
|
|
||||||
<avalonia:MaterialIcon Kind="ExternalLink" />
|
|
||||||
<TextBlock>Create account or log in</TextBlock>
|
|
||||||
</StackPanel>
|
|
||||||
</Button>
|
|
||||||
</StackPanel>
|
|
||||||
|
|
||||||
<StackPanel IsVisible="{CompiledBinding ShowMissingVerification}" Margin="0 35 0 0">
|
|
||||||
<TextBlock Theme="{StaticResource SubtitleTextBlockStyle}" TextWrapping="Wrap">Confirm email address</TextBlock>
|
|
||||||
<TextBlock TextWrapping="Wrap">
|
|
||||||
<Run>Before you can continue, please confirm your email address.</Run> (<Run Text="{CompiledBinding Email.Value}"></Run>)
|
|
||||||
<LineBreak />
|
|
||||||
<Run>You'll find the confirmation mail in your inbox.</Run>
|
|
||||||
<LineBreak />
|
|
||||||
<LineBreak />
|
|
||||||
<TextBlock>Don't see an email? Check your spam box!</TextBlock>
|
|
||||||
</TextBlock>
|
|
||||||
|
|
||||||
<Button Margin="0 15 0 5" Command="{CompiledBinding Refresh}">
|
|
||||||
<StackPanel Orientation="Horizontal" Spacing="5">
|
|
||||||
<avalonia:MaterialIcon Kind="Refresh" />
|
|
||||||
<TextBlock>Refresh</TextBlock>
|
|
||||||
</StackPanel>
|
|
||||||
</Button>
|
|
||||||
|
|
||||||
<TextBlock Theme="{StaticResource CaptionTextBlockStyle}">PS: We take this step to avoid the workshop getting flooded with bogus content.</TextBlock>
|
|
||||||
</StackPanel>
|
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</UserControl>
|
</UserControl>
|
||||||
@ -1,50 +1,24 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Linq;
|
||||||
using System.Reactive;
|
using System.Reactive;
|
||||||
using System.Reactive.Disposables;
|
|
||||||
using System.Security.Claims;
|
|
||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Artemis.UI.Screens.Workshop.CurrentUser;
|
|
||||||
using Artemis.UI.Shared.Services;
|
|
||||||
using Artemis.WebClient.Workshop.Services;
|
using Artemis.WebClient.Workshop.Services;
|
||||||
using IdentityModel;
|
using IdentityModel;
|
||||||
using ReactiveUI;
|
using ReactiveUI;
|
||||||
using Timer = System.Timers.Timer;
|
|
||||||
|
|
||||||
namespace Artemis.UI.Screens.Workshop.SubmissionWizard.Steps;
|
namespace Artemis.UI.Screens.Workshop.SubmissionWizard.Steps;
|
||||||
|
|
||||||
public class WelcomeStepViewModel : SubmissionViewModel
|
public class WelcomeStepViewModel : SubmissionViewModel
|
||||||
{
|
{
|
||||||
private readonly IAuthenticationService _authenticationService;
|
private readonly IAuthenticationService _authenticationService;
|
||||||
private readonly ObservableAsPropertyHelper<bool> _showMissingVerification;
|
|
||||||
private readonly IWindowService _windowService;
|
|
||||||
private ObservableAsPropertyHelper<Claim?>? _email;
|
|
||||||
private ObservableAsPropertyHelper<Claim?>? _emailVerified;
|
|
||||||
private ObservableAsPropertyHelper<bool>? _isLoggedIn;
|
|
||||||
|
|
||||||
public WelcomeStepViewModel(IAuthenticationService authenticationService, IWindowService windowService)
|
public WelcomeStepViewModel(IAuthenticationService authenticationService)
|
||||||
{
|
{
|
||||||
_authenticationService = authenticationService;
|
_authenticationService = authenticationService;
|
||||||
_windowService = windowService;
|
|
||||||
_showMissingVerification = this.WhenAnyValue(vm => vm.IsLoggedIn, vm => vm.EmailVerified, (l, v) => l && (v == null || v.Value == "false")).ToProperty(this, vm => vm.ShowMissingVerification);
|
|
||||||
|
|
||||||
|
Continue = ReactiveCommand.CreateFromTask(ExecuteContinue);
|
||||||
|
ShowHeader = false;
|
||||||
ShowGoBack = false;
|
ShowGoBack = false;
|
||||||
Continue = ReactiveCommand.Create(ExecuteContinue);
|
|
||||||
Login = ReactiveCommand.CreateFromTask(ExecuteLogin);
|
|
||||||
Refresh = ReactiveCommand.CreateFromTask(ExecuteRefresh);
|
|
||||||
|
|
||||||
this.WhenActivated(d =>
|
|
||||||
{
|
|
||||||
_isLoggedIn = authenticationService.IsLoggedIn.ToProperty(this, vm => vm.IsLoggedIn).DisposeWith(d);
|
|
||||||
_emailVerified = authenticationService.GetClaim(JwtClaimTypes.EmailVerified).ToProperty(this, vm => vm.EmailVerified).DisposeWith(d);
|
|
||||||
_email = authenticationService.GetClaim(JwtClaimTypes.Email).ToProperty(this, vm => vm.Email).DisposeWith(d);
|
|
||||||
|
|
||||||
Timer updateTimer = new(TimeSpan.FromSeconds(15));
|
|
||||||
updateTimer.Elapsed += (_, _) => Task.Run(Update);
|
|
||||||
updateTimer.Start();
|
|
||||||
|
|
||||||
updateTimer.DisposeWith(d);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
@ -53,43 +27,20 @@ public class WelcomeStepViewModel : SubmissionViewModel
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override ReactiveCommand<Unit, Unit> GoBack { get; } = null!;
|
public override ReactiveCommand<Unit, Unit> GoBack { get; } = null!;
|
||||||
|
|
||||||
public ReactiveCommand<Unit, Unit> Login { get; }
|
private async Task ExecuteContinue()
|
||||||
public ReactiveCommand<Unit, Unit> Refresh { get; }
|
|
||||||
|
|
||||||
public bool ShowMissingVerification => _showMissingVerification.Value;
|
|
||||||
public bool IsLoggedIn => _isLoggedIn?.Value ?? false;
|
|
||||||
public Claim? EmailVerified => _emailVerified?.Value;
|
|
||||||
public Claim? Email => _email?.Value;
|
|
||||||
|
|
||||||
private async Task Update()
|
|
||||||
{
|
{
|
||||||
if (EmailVerified?.Value == "true")
|
bool loggedIn = await _authenticationService.AutoLogin(true);
|
||||||
return;
|
|
||||||
|
|
||||||
try
|
if (!loggedIn)
|
||||||
{
|
{
|
||||||
// Use the refresh token to login again, updating claims
|
State.ChangeScreen<LoginStepViewModel>();
|
||||||
await _authenticationService.AutoLogin(true);
|
|
||||||
}
|
}
|
||||||
catch (Exception)
|
else
|
||||||
{
|
{
|
||||||
// ignored, meh
|
if (_authenticationService.Claims.Any(c => c.Type == JwtClaimTypes.EmailVerified && c.Value == "true"))
|
||||||
|
State.ChangeScreen<EntryTypeViewModel>();
|
||||||
|
else
|
||||||
|
State.ChangeScreen<ValidateEmailStepViewModel>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ExecuteContinue()
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task ExecuteLogin(CancellationToken ct)
|
|
||||||
{
|
|
||||||
await _windowService.CreateContentDialog().WithViewModel(out WorkshopLoginViewModel _).WithTitle("Workshop login").ShowAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task ExecuteRefresh(CancellationToken ct)
|
|
||||||
{
|
|
||||||
await Update();
|
|
||||||
await Task.Delay(1000, ct);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@ -0,0 +1,43 @@
|
|||||||
|
using System.Reactive;
|
||||||
|
using Artemis.UI.Shared;
|
||||||
|
using ReactiveUI;
|
||||||
|
|
||||||
|
namespace Artemis.UI.Screens.Workshop.SubmissionWizard;
|
||||||
|
|
||||||
|
public abstract class SubmissionViewModel : ActivatableViewModelBase
|
||||||
|
{
|
||||||
|
private string _continueText = "Continue";
|
||||||
|
private bool _showFinish;
|
||||||
|
private bool _showGoBack = true;
|
||||||
|
private bool _showHeader = true;
|
||||||
|
|
||||||
|
public SubmissionWizardViewModel WizardViewModel { get; set; } = null!;
|
||||||
|
public SubmissionWizardState State { get; set; } = null!;
|
||||||
|
|
||||||
|
public abstract ReactiveCommand<Unit, Unit> Continue { get; }
|
||||||
|
public abstract ReactiveCommand<Unit, Unit> GoBack { get; }
|
||||||
|
|
||||||
|
public bool ShowHeader
|
||||||
|
{
|
||||||
|
get => _showHeader;
|
||||||
|
set => RaiseAndSetIfChanged(ref _showHeader, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool ShowGoBack
|
||||||
|
{
|
||||||
|
get => _showGoBack;
|
||||||
|
set => RaiseAndSetIfChanged(ref _showGoBack, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool ShowFinish
|
||||||
|
{
|
||||||
|
get => _showFinish;
|
||||||
|
set => RaiseAndSetIfChanged(ref _showFinish, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public string ContinueText
|
||||||
|
{
|
||||||
|
get => _continueText;
|
||||||
|
set => RaiseAndSetIfChanged(ref _continueText, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,34 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using Artemis.WebClient.Workshop;
|
||||||
|
using DryIoc;
|
||||||
|
|
||||||
|
namespace Artemis.UI.Screens.Workshop.SubmissionWizard;
|
||||||
|
|
||||||
|
public class SubmissionWizardState
|
||||||
|
{
|
||||||
|
private readonly SubmissionWizardViewModel _wizardViewModel;
|
||||||
|
private readonly IContainer _container;
|
||||||
|
|
||||||
|
public SubmissionWizardState(SubmissionWizardViewModel wizardViewModel, IContainer container)
|
||||||
|
{
|
||||||
|
_wizardViewModel = wizardViewModel;
|
||||||
|
_container = container;
|
||||||
|
}
|
||||||
|
|
||||||
|
public EntryType EntryType { get; set; }
|
||||||
|
|
||||||
|
public string Name { get; set; } = string.Empty;
|
||||||
|
public Stream? Icon { get; set; }
|
||||||
|
public string Summary { get; set; } = string.Empty;
|
||||||
|
public string Description { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
public List<int> Categories { get; set; } = new();
|
||||||
|
public List<int> Tags { get; set; } = new();
|
||||||
|
public List<Stream> Images { get; set; } = new();
|
||||||
|
|
||||||
|
public void ChangeScreen<TSubmissionViewModel>() where TSubmissionViewModel : SubmissionViewModel
|
||||||
|
{
|
||||||
|
_wizardViewModel.Screen = _container.Resolve<TSubmissionViewModel>();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -17,7 +17,8 @@
|
|||||||
<Grid Margin="15" RowDefinitions="Auto,*,Auto">
|
<Grid Margin="15" RowDefinitions="Auto,*,Auto">
|
||||||
<Grid RowDefinitions="*,*" ColumnDefinitions="Auto,*,Auto" Margin="0 0 0 15">
|
<Grid RowDefinitions="*,*" ColumnDefinitions="Auto,*,Auto" Margin="0 0 0 15">
|
||||||
<ContentControl Grid.Column="0" Grid.RowSpan="2" Width="65" Height="65" VerticalAlignment="Center" Margin="0 0 20 0" Content="{CompiledBinding CurrentUserViewModel}"/>
|
<ContentControl Grid.Column="0" Grid.RowSpan="2" Width="65" Height="65" VerticalAlignment="Center" Margin="0 0 20 0" Content="{CompiledBinding CurrentUserViewModel}"/>
|
||||||
<TextBlock Grid.Row="0" Grid.Column="1" FontSize="36" VerticalAlignment="Bottom" Text="{CompiledBinding CurrentUserViewModel.Name, FallbackValue=Not logged in}"/>
|
<TextBlock Grid.Row="0" Grid.Column="1" FontSize="36" VerticalAlignment="Bottom" Text="{CompiledBinding CurrentUserViewModel.Name}" IsVisible="{CompiledBinding !CurrentUserViewModel.IsAnonymous}"/>
|
||||||
|
<TextBlock Grid.Row="0" Grid.Column="1" FontSize="36" VerticalAlignment="Bottom" Text="Anon 🕵️" IsVisible="{CompiledBinding CurrentUserViewModel.IsAnonymous}"/>
|
||||||
|
|
||||||
<StackPanel Grid.Row="0" Grid.Column="2" HorizontalAlignment="Right" VerticalAlignment="Bottom" Orientation="Horizontal">
|
<StackPanel Grid.Row="0" Grid.Column="2" HorizontalAlignment="Right" VerticalAlignment="Bottom" Orientation="Horizontal">
|
||||||
<controls:HyperlinkButton Classes="icon-button" ToolTip.Tip="View Wiki" NavigateUri="https://wiki.artemis-rgb.com?mtm_campaign=artemis&mtm_kwd=workshop-wizard">
|
<controls:HyperlinkButton Classes="icon-button" ToolTip.Tip="View Wiki" NavigateUri="https://wiki.artemis-rgb.com?mtm_campaign=artemis&mtm_kwd=workshop-wizard">
|
||||||
@ -44,9 +45,7 @@
|
|||||||
<Button Command="{CompiledBinding Screen.GoBack}" IsVisible="{CompiledBinding Screen.ShowGoBack}">
|
<Button Command="{CompiledBinding Screen.GoBack}" IsVisible="{CompiledBinding Screen.ShowGoBack}">
|
||||||
Back
|
Back
|
||||||
</Button>
|
</Button>
|
||||||
<Button Command="{CompiledBinding Screen.Continue}" IsVisible="{CompiledBinding !Screen.ShowFinish}" Width="80">
|
<Button Command="{CompiledBinding Screen.Continue}" IsVisible="{CompiledBinding !Screen.ShowFinish}" Width="80" Content="{CompiledBinding Screen.ContinueText}"/>
|
||||||
Continue
|
|
||||||
</Button>
|
|
||||||
<Button Command="{CompiledBinding Screen.Continue}" IsVisible="{CompiledBinding Screen.ShowFinish}" Width="80">
|
<Button Command="{CompiledBinding Screen.Continue}" IsVisible="{CompiledBinding Screen.ShowFinish}" Width="80">
|
||||||
Finish
|
Finish
|
||||||
</Button>
|
</Button>
|
||||||
|
|||||||
@ -1,19 +1,24 @@
|
|||||||
using System.Reactive;
|
using Artemis.UI.Screens.Workshop.CurrentUser;
|
||||||
using Artemis.UI.Screens.Workshop.CurrentUser;
|
|
||||||
using Artemis.UI.Screens.Workshop.SubmissionWizard.Steps;
|
using Artemis.UI.Screens.Workshop.SubmissionWizard.Steps;
|
||||||
using Artemis.UI.Shared;
|
using Artemis.UI.Shared;
|
||||||
using ReactiveUI;
|
using DryIoc;
|
||||||
|
|
||||||
namespace Artemis.UI.Screens.Workshop.SubmissionWizard;
|
namespace Artemis.UI.Screens.Workshop.SubmissionWizard;
|
||||||
|
|
||||||
public class SubmissionWizardViewModel : DialogViewModelBase<bool>
|
public class SubmissionWizardViewModel : DialogViewModelBase<bool>
|
||||||
{
|
{
|
||||||
|
private readonly SubmissionWizardState _state;
|
||||||
private SubmissionViewModel _screen;
|
private SubmissionViewModel _screen;
|
||||||
|
|
||||||
public SubmissionWizardViewModel(CurrentUserViewModel currentUserViewModel, WelcomeStepViewModel welcomeStepViewModel)
|
public SubmissionWizardViewModel(IContainer container, CurrentUserViewModel currentUserViewModel, WelcomeStepViewModel welcomeStepViewModel)
|
||||||
{
|
{
|
||||||
|
_state = new SubmissionWizardState(this, container);
|
||||||
_screen = welcomeStepViewModel;
|
_screen = welcomeStepViewModel;
|
||||||
|
_screen.WizardViewModel = this;
|
||||||
|
_screen.State = _state;
|
||||||
|
|
||||||
CurrentUserViewModel = currentUserViewModel;
|
CurrentUserViewModel = currentUserViewModel;
|
||||||
|
CurrentUserViewModel.AllowLogout = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public CurrentUserViewModel CurrentUserViewModel { get; }
|
public CurrentUserViewModel CurrentUserViewModel { get; }
|
||||||
@ -21,27 +26,11 @@ public class SubmissionWizardViewModel : DialogViewModelBase<bool>
|
|||||||
public SubmissionViewModel Screen
|
public SubmissionViewModel Screen
|
||||||
{
|
{
|
||||||
get => _screen;
|
get => _screen;
|
||||||
set => RaiseAndSetIfChanged(ref _screen, value);
|
set
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public abstract class SubmissionViewModel : ActivatableViewModelBase
|
|
||||||
{
|
{
|
||||||
private bool _showFinish;
|
value.WizardViewModel = this;
|
||||||
private bool _showGoBack = true;
|
value.State = _state;
|
||||||
|
RaiseAndSetIfChanged(ref _screen, value);
|
||||||
public abstract ReactiveCommand<Unit, Unit> Continue { get; }
|
}
|
||||||
public abstract ReactiveCommand<Unit, Unit> GoBack { get; }
|
|
||||||
|
|
||||||
public bool ShowGoBack
|
|
||||||
{
|
|
||||||
get => _showGoBack;
|
|
||||||
set => RaiseAndSetIfChanged(ref _showGoBack, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool ShowFinish
|
|
||||||
{
|
|
||||||
get => _showFinish;
|
|
||||||
set => RaiseAndSetIfChanged(ref _showFinish, value);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -79,14 +79,14 @@ internal class AuthenticationService : CorePropertyChanged, IAuthenticationServi
|
|||||||
|
|
||||||
if (response.IsError)
|
if (response.IsError)
|
||||||
{
|
{
|
||||||
if (response.Error == OidcConstants.TokenErrors.ExpiredToken)
|
if (response.Error is OidcConstants.TokenErrors.ExpiredToken or OidcConstants.TokenErrors.InvalidGrant)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
throw new ArtemisWebClientException("Failed to request refresh token: " + response.Error);
|
throw new ArtemisWebClientException("Failed to request refresh token: " + response.Error);
|
||||||
}
|
}
|
||||||
|
|
||||||
SetCurrentUser(response);
|
SetCurrentUser(response);
|
||||||
return false;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static byte[] HashSha256(string inputString)
|
private static byte[] HashSha256(string inputString)
|
||||||
|
|||||||
@ -2,6 +2,6 @@ namespace Artemis.WebClient.Workshop;
|
|||||||
|
|
||||||
public static class WorkshopConstants
|
public static class WorkshopConstants
|
||||||
{
|
{
|
||||||
public const string AUTHORITY_URL = "https://identity.artemis-rgb.com";
|
public const string AUTHORITY_URL = "https://localhost:5001";
|
||||||
public const string WORKSHOP_URL = "https://workshop.artemis-rgb.com";
|
public const string WORKSHOP_URL = "https://workshop.artemis-rgb.com";
|
||||||
}
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user