1
0
mirror of https://github.com/Artemis-RGB/Artemis synced 2025-12-12 13:28:33 +00:00

Merge branch 'development'

This commit is contained in:
RobertBeekman 2024-01-30 13:15:42 +01:00
commit 960991e77b
8 changed files with 51 additions and 70 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -5,6 +5,7 @@
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"
xmlns:asyncImageLoader="clr-namespace:AsyncImageLoader;assembly=AsyncImageLoader.Avalonia"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="Artemis.UI.Screens.Workshop.CurrentUser.CurrentUserView"
x:DataType="currentUser:CurrentUserViewModel">
@ -27,13 +28,16 @@
</Ellipse>
<!-- Signed in -->
<Ellipse Height="{CompiledBinding Bounds.Height, ElementName=Container}" Width="{CompiledBinding Bounds.Height, ElementName=Container}" IsVisible="{CompiledBinding !IsAnonymous}" Name="UserMenu">
<Ellipse Height="{CompiledBinding Bounds.Height, ElementName=Container}"
Width="{CompiledBinding Bounds.Height, ElementName=Container}"
IsVisible="{CompiledBinding !IsAnonymous}"
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}" />
<ImageBrush asyncImageLoader:ImageBrushLoader.Source="{CompiledBinding AvatarUrl}" />
</Ellipse.Fill>
</Ellipse>
<TextBlock Grid.Column="1" Grid.Row="0" Text="{CompiledBinding Name}" Margin="0 4 0 0"></TextBlock>
@ -51,7 +55,7 @@
</Flyout>
</Ellipse.ContextFlyout>
<Ellipse.Fill>
<ImageBrush Source="{CompiledBinding Avatar}" />
<ImageBrush asyncImageLoader:ImageBrushLoader.Source="{CompiledBinding AvatarUrl}" />
</Ellipse.Fill>
</Ellipse>
</Panel>

View File

@ -21,7 +21,6 @@ public partial class CurrentUserViewModel : ActivatableViewModelBase
{
private readonly IAuthenticationService _authenticationService;
private readonly ObservableAsPropertyHelper<bool> _isAnonymous;
private readonly HttpClient _httpClient;
private readonly ILogger _logger;
private readonly IWindowService _windowService;
[Notify] private bool _allowLogout = true;
@ -30,13 +29,13 @@ public partial class CurrentUserViewModel : ActivatableViewModelBase
[Notify(Setter.Private)] private bool _loading = true;
[Notify(Setter.Private)] private string? _name;
[Notify(Setter.Private)] private string? _userId;
[Notify(Setter.Private)] private string? _avatarUrl;
public CurrentUserViewModel(ILogger logger, IAuthenticationService authenticationService, IWindowService windowService)
{
_logger = logger;
_authenticationService = authenticationService;
_windowService = windowService;
_httpClient = new HttpClient();
Login = ReactiveCommand.CreateFromTask(ExecuteLogin);
_isAnonymous = this.WhenAnyValue(vm => vm.Loading, vm => vm.Name, (l, n) => l || n == null).ToProperty(this, vm => vm.IsAnonymous);
@ -44,7 +43,7 @@ public partial class CurrentUserViewModel : ActivatableViewModelBase
this.WhenActivated(d =>
{
Task.Run(AutoLogin);
_authenticationService.IsLoggedIn.Subscribe(_ => Task.Run(LoadCurrentUser)).DisposeWith(d);
_authenticationService.IsLoggedIn.Subscribe(_ => LoadCurrentUser()).DisposeWith(d);
});
}
@ -66,7 +65,7 @@ public partial class CurrentUserViewModel : ActivatableViewModelBase
.ShowAsync();
if (result == ContentDialogResult.Primary)
await LoadCurrentUser();
LoadCurrentUser();
}
private async Task AutoLogin()
@ -74,7 +73,7 @@ public partial class CurrentUserViewModel : ActivatableViewModelBase
try
{
await _authenticationService.AutoLogin();
await LoadCurrentUser();
LoadCurrentUser();
}
catch (Exception e)
{
@ -86,33 +85,11 @@ public partial class CurrentUserViewModel : ActivatableViewModelBase
}
}
private async Task LoadCurrentUser()
private void LoadCurrentUser()
{
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);
}
else
{
Avatar?.Dispose();
Avatar = null;
}
}
private async Task LoadAvatar(string userId)
{
try
{
Avatar?.Dispose();
Avatar = new Bitmap(await _httpClient.GetStreamAsync($"{WorkshopConstants.AUTHORITY_URL}/user/avatar/{userId}"));
}
catch (Exception)
{
// ignored
}
AvatarUrl = $"{WorkshopConstants.AUTHORITY_URL}/user/avatar/{UserId}";
}
}

View File

@ -17,21 +17,21 @@
</StackPanel.Styles>
<StackPanel IsVisible="{CompiledBinding !Finished}">
<Lottie Path="/Assets/Animations/busy.json" Width="250" Height="250" Margin="0 100" ></Lottie>
<Lottie Path="/Assets/Animations/upload.json" Width="300" Height="300" Margin="0 75" ></Lottie>
<TextBlock Theme="{StaticResource TitleTextBlockStyle}">Uploading your submission...</TextBlock>
</StackPanel>
<StackPanel IsVisible="{CompiledBinding Succeeded}">
<Lottie Path="/Assets/Animations/success.json" RepeatCount="1" Width="250" Height="250" Margin="0 100"></Lottie>
<TextBlock Theme="{StaticResource TitleTextBlockStyle}">All done! Hit finish to view your submission.</TextBlock>
</StackPanel>
</StackPanel>
<StackPanel IsVisible="{CompiledBinding Failed}">
<TextBlock FontSize="140" Margin="0 100">😢</TextBlock>
<TextBlock Theme="{StaticResource SubtitleTextBlockStyle}">
Unfortunately something went wrong while uploading your submission.
</TextBlock>
<TextBlock>Hit finish to view your submission, from there you can try to upload a new release.</TextBlock>
<TextBlock Text="{CompiledBinding FailureMessage}"></TextBlock>
<TextBlock Margin="0 10" Classes="subtitle">If this keeps occuring, hit us up on Discord</TextBlock>
</StackPanel>

View File

@ -5,6 +5,7 @@ using System.Reactive.Disposables;
using System.Reactive.Linq;
using System.Threading;
using System.Threading.Tasks;
using Artemis.Core;
using Artemis.UI.Shared.Routing;
using Artemis.UI.Shared.Services;
using Artemis.UI.Shared.Utilities;
@ -31,6 +32,7 @@ public partial class UploadStepViewModel : SubmissionViewModel
[Notify] private bool _failed;
[Notify] private bool _finished;
[Notify] private bool _succeeded;
[Notify] private string? _failureMessage;
/// <inheritdoc />
public UploadStepViewModel(ILogger logger,
@ -56,37 +58,33 @@ public partial class UploadStepViewModel : SubmissionViewModel
private async Task ExecuteUpload(CancellationToken cancellationToken)
{
// Use the existing entry or create a new one
_entryId = State.EntryId ?? await CreateEntry(cancellationToken);
// If a new entry had to be created but that failed, stop here, CreateEntry will send the user back
if (_entryId == null)
return;
try
{
// Use the existing entry or create a new one
_entryId = State.EntryId ?? await CreateEntry(cancellationToken);
if (_entryId == null)
{
Failed = true;
return;
}
// Create a release for the new entry
IEntryUploadHandler uploadHandler = _entryUploadHandlerFactory.CreateHandler(State.EntryType);
EntryUploadResult uploadResult = await uploadHandler.CreateReleaseAsync(_entryId.Value, State.EntrySource!, cancellationToken);
if (!uploadResult.IsSuccess)
{
string? message = uploadResult.Message;
if (message != null)
message += "\r\n\r\n";
else
message = "";
message += "Your submission has still been saved, you may try to upload a new release";
await _windowService.ShowConfirmContentDialog("Failed to upload workshop entry", message, "Close", null);
}
throw new ArtemisWorkshopException(uploadResult.Message);
Succeeded = true;
}
catch (Exception e)
{
_logger.Error(e, "Failed to upload submission for entry {EntryId}", _entryId);
// Something went wrong when creating a release :c
// We'll keep the workshop entry so that the user can make changes and try again
FailureMessage = e.Message;
Failed = true;
// If something went wrong halfway through, delete the entry
if (_entryId != null)
await _workshopClient.RemoveEntry.ExecuteAsync(_entryId.Value, CancellationToken.None);
}
finally
{
@ -94,10 +92,12 @@ public partial class UploadStepViewModel : SubmissionViewModel
}
}
private async Task<long?> CreateEntry(CancellationToken cancellationToken)
private async Task<long> CreateEntry(CancellationToken cancellationToken)
{
await Task.Delay(2000);
// Let the UI settle before making the thread busy
await Task.Delay(500, cancellationToken);
// Create entry
IOperationResult<IAddEntryResult> result = await _workshopClient.AddEntry.ExecuteAsync(new CreateEntryInput
{
EntryType = State.EntryType,
@ -108,18 +108,16 @@ public partial class UploadStepViewModel : SubmissionViewModel
Tags = State.Tags
}, cancellationToken);
long? entryId = result.Data?.AddEntry?.Id;
if (result.IsErrorResult() || entryId == null)
{
await _windowService.ShowConfirmContentDialog("Failed to create workshop entry", string.Join("\r\n", result.Errors.Select(e => e.Message)), "Close", null);
State.ChangeScreen<SubmitStepViewModel>();
return null;
}
result.EnsureNoErrors();
if (result.Data?.AddEntry == null)
throw new ArtemisWorkshopException("AddEntry returned result");
long entryId = result.Data.AddEntry.Id;
// Upload images
cancellationToken.ThrowIfCancellationRequested();
foreach (ImageUploadRequest image in State.Images.ToList())
{
await TryImageUpload(async () => await _workshopService.UploadEntryImage(entryId.Value, image, cancellationToken));
await TryImageUpload(async () => await _workshopService.UploadEntryImage(entryId, image, cancellationToken));
cancellationToken.ThrowIfCancellationRequested();
}
@ -127,8 +125,7 @@ public partial class UploadStepViewModel : SubmissionViewModel
return entryId;
// Upload icon
await TryImageUpload(async () => await _workshopService.SetEntryIcon(entryId.Value, State.Icon, cancellationToken));
await TryImageUpload(async () => await _workshopService.SetEntryIcon(entryId, State.Icon, cancellationToken));
return entryId;
}
@ -151,7 +148,7 @@ public partial class UploadStepViewModel : SubmissionViewModel
{
State.Close();
if (_entryId != null)
if (Succeeded && _entryId != null)
await _router.Navigate($"workshop/library/submissions/{_entryId.Value}");
}
}

View File

@ -45,6 +45,9 @@
<GraphQL Update="Mutations\UpdateEntryImage.graphql">
<Generator>MSBuild:GenerateGraphQLCode</Generator>
</GraphQL>
<GraphQL Update="Mutations\CreateEntry.graphql">
<Generator>MSBuild:GenerateGraphQLCode</Generator>
</GraphQL>
</ItemGroup>
<ItemGroup>