diff --git a/src/Artemis.UI.Shared/Routing/Router/Navigation.cs b/src/Artemis.UI.Shared/Routing/Router/Navigation.cs
index 50505a706..0d0f6083c 100644
--- a/src/Artemis.UI.Shared/Routing/Router/Navigation.cs
+++ b/src/Artemis.UI.Shared/Routing/Router/Navigation.cs
@@ -118,11 +118,9 @@ internal class Navigation
Completed = true;
}
- public bool PathEquals(string path, bool allowPartialMatch)
+ public bool PathEquals(string path, RouterNavigationOptions options)
{
- if (allowPartialMatch)
- return _resolution.Path.StartsWith(path, StringComparison.InvariantCultureIgnoreCase);
- return string.Equals(_resolution.Path, path, StringComparison.InvariantCultureIgnoreCase);
+ return options.PathEquals(_resolution.Path, path);
}
private bool CancelIfRequested(NavigationArguments args, string stage, object screen)
diff --git a/src/Artemis.UI.Shared/Routing/Router/Router.cs b/src/Artemis.UI.Shared/Routing/Router/Router.cs
index 84e44c4ac..282511c40 100644
--- a/src/Artemis.UI.Shared/Routing/Router/Router.cs
+++ b/src/Artemis.UI.Shared/Routing/Router/Router.cs
@@ -58,11 +58,9 @@ internal class Router : CorePropertyChanged, IRouter, IDisposable
return false;
}
- private bool PathEquals(string path, bool allowPartialMatch)
+ private bool PathEquals(string path, RouterNavigationOptions options)
{
- if (allowPartialMatch)
- return _currentRouteSubject.Value != null && _currentRouteSubject.Value.StartsWith(path, StringComparison.InvariantCultureIgnoreCase);
- return string.Equals(_currentRouteSubject.Value, path, StringComparison.InvariantCultureIgnoreCase);
+ return _currentRouteSubject.Value != null && options.PathEquals(_currentRouteSubject.Value, path);
}
///
@@ -84,7 +82,7 @@ internal class Router : CorePropertyChanged, IRouter, IDisposable
{
if (_root == null)
throw new ArtemisRoutingException("Cannot navigate without a root having been set");
- if (PathEquals(path, options.IgnoreOnPartialMatch) || (_currentNavigation != null && _currentNavigation.PathEquals(path, options.IgnoreOnPartialMatch)))
+ if (PathEquals(path, options) || (_currentNavigation != null && _currentNavigation.PathEquals(path, options)))
return;
string? previousPath = _currentRouteSubject.Value;
diff --git a/src/Artemis.UI.Shared/Routing/Router/RouterNavigationOptions.cs b/src/Artemis.UI.Shared/Routing/Router/RouterNavigationOptions.cs
index a5c63ab88..273f85c2c 100644
--- a/src/Artemis.UI.Shared/Routing/Router/RouterNavigationOptions.cs
+++ b/src/Artemis.UI.Shared/Routing/Router/RouterNavigationOptions.cs
@@ -1,3 +1,5 @@
+using System;
+
namespace Artemis.UI.Shared.Routing;
///
@@ -21,9 +23,31 @@ public class RouterNavigationOptions
/// If set to true, a route change from page/subpage1/subpage2 to page/subpage1 will be ignored.
public bool IgnoreOnPartialMatch { get; set; } = false;
+ ///
+ /// Gets or sets the path to use when determining whether the path is a partial match,
+ /// only has any effect if is .
+ ///
+ public string? PartialMatchOverride { get; set; }
+
///
/// Gets or sets a boolean value indicating whether logging should be enabled.
/// Errors and warnings are always logged.
///
public bool EnableLogging { get; set; } = true;
+
+ ///
+ /// Determines whether the given two paths are considered equal using these navigation options.
+ ///
+ /// The current path.
+ /// The target path.
+ /// if the paths are considered equal; otherwise .
+ internal bool PathEquals(string current, string target)
+ {
+ if (PartialMatchOverride != null && IgnoreOnPartialMatch)
+ target = PartialMatchOverride;
+
+ if (IgnoreOnPartialMatch)
+ return current.StartsWith(target, StringComparison.InvariantCultureIgnoreCase);
+ return string.Equals(current, target, StringComparison.InvariantCultureIgnoreCase);
+ }
}
\ No newline at end of file
diff --git a/src/Artemis.UI/Routing/RouteViewModel.cs b/src/Artemis.UI/Routing/RouteViewModel.cs
index 78cc458c9..df49bc79c 100644
--- a/src/Artemis.UI/Routing/RouteViewModel.cs
+++ b/src/Artemis.UI/Routing/RouteViewModel.cs
@@ -4,20 +4,20 @@ namespace Artemis.UI.Routing;
public class RouteViewModel
{
- public RouteViewModel(string name, string path, string? mathPath = null)
+ public RouteViewModel(string name, string path, string? matchPath = null)
{
Path = path;
Name = name;
- MathPath = mathPath;
+ MatchPath = matchPath;
}
public string Path { get; }
public string Name { get; }
- public string? MathPath { get; }
+ public string? MatchPath { get; }
public bool Matches(string path)
{
- return path.StartsWith(MathPath ?? Path, StringComparison.InvariantCultureIgnoreCase);
+ return path.StartsWith(MatchPath ?? Path, StringComparison.InvariantCultureIgnoreCase);
}
///
diff --git a/src/Artemis.UI/Screens/Workshop/Entries/EntriesViewModel.cs b/src/Artemis.UI/Screens/Workshop/Entries/EntriesViewModel.cs
index 903a4d649..0d966ba89 100644
--- a/src/Artemis.UI/Screens/Workshop/Entries/EntriesViewModel.cs
+++ b/src/Artemis.UI/Screens/Workshop/Entries/EntriesViewModel.cs
@@ -34,7 +34,7 @@ public class EntriesViewModel : RoutableHostScreen
// Navigate on tab change
this.WhenAnyValue(vm => vm.SelectedTab)
.WhereNotNull()
- .Subscribe(s => router.Navigate(s.Path, new RouterNavigationOptions {IgnoreOnPartialMatch = true}))
+ .Subscribe(s => router.Navigate(s.Path, new RouterNavigationOptions {IgnoreOnPartialMatch = true, PartialMatchOverride = s.MatchPath}))
.DisposeWith(d);
});
}
diff --git a/src/Artemis.UI/Screens/Workshop/Home/WorkshopHomeViewModel.cs b/src/Artemis.UI/Screens/Workshop/Home/WorkshopHomeViewModel.cs
index 07fb24452..a0f82de17 100644
--- a/src/Artemis.UI/Screens/Workshop/Home/WorkshopHomeViewModel.cs
+++ b/src/Artemis.UI/Screens/Workshop/Home/WorkshopHomeViewModel.cs
@@ -1,15 +1,11 @@
using System.Reactive;
-using System.Reactive.Disposables;
using System.Threading;
using System.Threading.Tasks;
using Artemis.UI.Extensions;
using Artemis.UI.Screens.Workshop.SubmissionWizard;
-using Artemis.UI.Shared;
using Artemis.UI.Shared.Routing;
using Artemis.UI.Shared.Services;
-using Artemis.WebClient.Workshop;
using Artemis.WebClient.Workshop.Services;
-using Avalonia.Threading;
using ReactiveUI;
namespace Artemis.UI.Screens.Workshop.Home;
@@ -17,13 +13,11 @@ namespace Artemis.UI.Screens.Workshop.Home;
public class WorkshopHomeViewModel : RoutableScreen
{
private readonly IWindowService _windowService;
- private readonly IWorkshopService _workshopService;
private bool _workshopReachable;
public WorkshopHomeViewModel(IRouter router, IWindowService windowService, IWorkshopService workshopService)
{
_windowService = windowService;
- _workshopService = workshopService;
AddSubmission = ReactiveCommand.CreateFromTask(ExecuteAddSubmission, this.WhenAnyValue(vm => vm.WorkshopReachable));
Navigate = ReactiveCommand.CreateFromTask(async r => await router.Navigate(r), this.WhenAnyValue(vm => vm.WorkshopReachable));
@@ -42,6 +36,6 @@ public class WorkshopHomeViewModel : RoutableScreen
private async Task ExecuteAddSubmission(CancellationToken arg)
{
- await _windowService.ShowDialogAsync();
+ await _windowService.ShowDialogAsync();
}
}
\ No newline at end of file
diff --git a/src/Artemis.UI/Screens/Workshop/Library/SubmissionDetailView.axaml b/src/Artemis.UI/Screens/Workshop/Library/SubmissionDetailView.axaml
index 4967d463b..c42098365 100644
--- a/src/Artemis.UI/Screens/Workshop/Library/SubmissionDetailView.axaml
+++ b/src/Artemis.UI/Screens/Workshop/Library/SubmissionDetailView.axaml
@@ -5,6 +5,7 @@
xmlns:library="clr-namespace:Artemis.UI.Screens.Workshop.Library"
xmlns:avalonia="clr-namespace:Material.Icons.Avalonia;assembly=Material.Icons.Avalonia"
xmlns:converters="clr-namespace:Artemis.UI.Converters"
+ xmlns:controls="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="Artemis.UI.Screens.Workshop.Library.SubmissionDetailView"
x:DataType="library:SubmissionDetailViewModel">
@@ -43,6 +44,9 @@
+
+ View workshop page
+
diff --git a/src/Artemis.UI/Screens/Workshop/Library/SubmissionDetailViewModel.cs b/src/Artemis.UI/Screens/Workshop/Library/SubmissionDetailViewModel.cs
index 869080c80..11d35afb1 100644
--- a/src/Artemis.UI/Screens/Workshop/Library/SubmissionDetailViewModel.cs
+++ b/src/Artemis.UI/Screens/Workshop/Library/SubmissionDetailViewModel.cs
@@ -7,9 +7,11 @@ using System.Threading;
using System.Threading.Tasks;
using Artemis.UI.Screens.Workshop.Entries;
using Artemis.UI.Screens.Workshop.Parameters;
+using Artemis.UI.Screens.Workshop.SubmissionWizard;
using Artemis.UI.Shared.Routing;
using Artemis.UI.Shared.Services;
using Artemis.WebClient.Workshop;
+using Artemis.WebClient.Workshop.Services;
using Avalonia.Media.Imaging;
using ReactiveUI;
using StrawberryShake;
@@ -22,26 +24,32 @@ public class SubmissionDetailViewModel : RoutableScreen _getEntrySpecificationsViewModel;
private readonly IWindowService _windowService;
+ private readonly IWorkshopService _workshopService;
private readonly IRouter _router;
private IGetSubmittedEntryById_Entry? _entry;
private EntrySpecificationsViewModel? _entrySpecificationsViewModel;
public SubmissionDetailViewModel(IWorkshopClient client,
- IHttpClientFactory httpClientFactory,
- Func entrySpecificationsViewModel,
+ IHttpClientFactory httpClientFactory,
IWindowService windowService,
- IRouter router)
+ IWorkshopService workshopService,
+ IRouter router,
+ Func entrySpecificationsViewModel)
{
_client = client;
_httpClientFactory = httpClientFactory;
- _getEntrySpecificationsViewModel = entrySpecificationsViewModel;
_windowService = windowService;
+ _workshopService = workshopService;
_router = router;
+ _getEntrySpecificationsViewModel = entrySpecificationsViewModel;
+ Save = ReactiveCommand.CreateFromTask(ExecuteSave);
CreateRelease = ReactiveCommand.CreateFromTask(ExecuteCreateRelease);
DeleteSubmission = ReactiveCommand.CreateFromTask(ExecuteDeleteSubmission);
+ ViewWorkshopPage = ReactiveCommand.CreateFromTask(ExecuteViewWorkshopPage);
}
+ public ReactiveCommand Save { get; }
public ReactiveCommand CreateRelease { get; }
public ReactiveCommand DeleteSubmission { get; }
@@ -57,6 +65,8 @@ public class SubmissionDetailViewModel : RoutableScreen RaiseAndSetIfChanged(ref _entry, value);
}
+ public ReactiveCommand ViewWorkshopPage { get; }
+
public override async Task OnNavigating(WorkshopDetailParameters parameters, NavigationArguments args, CancellationToken cancellationToken)
{
IOperationResult result = await _client.GetSubmittedEntryById.ExecuteAsync(parameters.EntryId, cancellationToken);
@@ -107,16 +117,24 @@ public class SubmissionDetailViewModel : RoutableScreen result = await _client.UpdateEntry.ExecuteAsync(input, cancellationToken);
+ result.EnsureNoErrors();
+ }
+
+ private async Task ExecuteCreateRelease(CancellationToken cancellationToken)
+ {
+ if (Entry != null)
+ await _windowService.ShowDialogAsync(Entry);
}
private async Task ExecuteDeleteSubmission(CancellationToken cancellationToken)
{
if (Entry == null)
return;
-
+
bool confirmed = await _windowService.ShowConfirmContentDialog(
"Delete submission?",
"You cannot undo this by yourself.\r\n" +
@@ -128,4 +146,10 @@ public class SubmissionDetailViewModel : RoutableScreen();
+ await _windowService.ShowDialogAsync();
}
private async Task ExecuteNavigateToEntry(IGetSubmittedEntries_SubmittedEntries entry, CancellationToken cancellationToken)
diff --git a/src/Artemis.UI/Screens/Workshop/SubmissionWizard/IWorkshopWizardViewModel.cs b/src/Artemis.UI/Screens/Workshop/SubmissionWizard/IWorkshopWizardViewModel.cs
new file mode 100644
index 000000000..58724c14c
--- /dev/null
+++ b/src/Artemis.UI/Screens/Workshop/SubmissionWizard/IWorkshopWizardViewModel.cs
@@ -0,0 +1,7 @@
+namespace Artemis.UI.Screens.Workshop.SubmissionWizard;
+
+public interface IWorkshopWizardViewModel
+{
+ SubmissionViewModel Screen { get; set; }
+ bool ShouldClose { get; set; }
+}
\ No newline at end of file
diff --git a/src/Artemis.UI/Screens/Workshop/SubmissionWizard/ReleaseWizardView.axaml b/src/Artemis.UI/Screens/Workshop/SubmissionWizard/ReleaseWizardView.axaml
new file mode 100644
index 000000000..522bd4d33
--- /dev/null
+++ b/src/Artemis.UI/Screens/Workshop/SubmissionWizard/ReleaseWizardView.axaml
@@ -0,0 +1,61 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Artemis.UI/Screens/Workshop/SubmissionWizard/ReleaseWizardView.axaml.cs b/src/Artemis.UI/Screens/Workshop/SubmissionWizard/ReleaseWizardView.axaml.cs
new file mode 100644
index 000000000..50bbc4ace
--- /dev/null
+++ b/src/Artemis.UI/Screens/Workshop/SubmissionWizard/ReleaseWizardView.axaml.cs
@@ -0,0 +1,35 @@
+using System;
+using System.Reactive.Disposables;
+using System.Reactive.Linq;
+using Artemis.UI.Shared;
+using Avalonia;
+using Avalonia.Threading;
+using ReactiveUI;
+
+namespace Artemis.UI.Screens.Workshop.SubmissionWizard;
+
+public partial class ReleaseWizardView: ReactiveAppWindow
+{
+ public ReleaseWizardView()
+ {
+ InitializeComponent();
+#if DEBUG
+ this.AttachDevTools();
+#endif
+
+ this.WhenActivated(d => ViewModel.WhenAnyValue(vm => vm.Screen).WhereNotNull().Subscribe(Navigate).DisposeWith(d));
+ this.WhenActivated(d => ViewModel.WhenAnyValue(vm => vm.ShouldClose).Where(c => c).Subscribe(_ => Close()).DisposeWith(d));
+ }
+
+ private void Navigate(SubmissionViewModel viewModel)
+ {
+ try
+ {
+ Dispatcher.UIThread.Invoke(() => Frame.NavigateFromObject(viewModel));
+ }
+ catch (Exception e)
+ {
+ ViewModel?.WindowService.ShowExceptionDialog("Wizard screen failed to activate", e);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Artemis.UI/Screens/Workshop/SubmissionWizard/ReleaseWizardViewModel.cs b/src/Artemis.UI/Screens/Workshop/SubmissionWizard/ReleaseWizardViewModel.cs
new file mode 100644
index 000000000..8ad0db0f6
--- /dev/null
+++ b/src/Artemis.UI/Screens/Workshop/SubmissionWizard/ReleaseWizardViewModel.cs
@@ -0,0 +1,51 @@
+using Artemis.UI.Screens.Workshop.CurrentUser;
+using Artemis.UI.Shared;
+using Artemis.UI.Shared.Services;
+using Artemis.WebClient.Workshop;
+using DryIoc;
+
+namespace Artemis.UI.Screens.Workshop.SubmissionWizard;
+
+public class ReleaseWizardViewModel : ActivatableViewModelBase, IWorkshopWizardViewModel
+{
+ private readonly SubmissionWizardState _state;
+ private SubmissionViewModel? _screen;
+ private bool _shouldClose;
+
+ public ReleaseWizardViewModel(IContainer container, IWindowService windowService, CurrentUserViewModel currentUserViewModel, IGetSubmittedEntryById_Entry entry)
+ {
+ _state = new SubmissionWizardState(this, container, windowService)
+ {
+ EntryType = entry.EntryType,
+ EntryId = entry.Id
+ };
+
+ WindowService = windowService;
+ CurrentUserViewModel = currentUserViewModel;
+ CurrentUserViewModel.AllowLogout = false;
+ Entry = entry;
+
+ _state.StartForCurrentEntry();
+ }
+
+ public IWindowService WindowService { get; }
+ public IGetSubmittedEntryById_Entry Entry { get; }
+ public CurrentUserViewModel CurrentUserViewModel { get; }
+
+ public SubmissionViewModel? Screen
+ {
+ get => _screen;
+ set
+ {
+ if (value != null)
+ value.State = _state;
+ RaiseAndSetIfChanged(ref _screen, value);
+ }
+ }
+
+ public bool ShouldClose
+ {
+ get => _shouldClose;
+ set => RaiseAndSetIfChanged(ref _shouldClose, value);
+ }
+}
\ No newline at end of file
diff --git a/src/Artemis.UI/Screens/Workshop/SubmissionWizard/Steps/EntryTypeStepViewModel.cs b/src/Artemis.UI/Screens/Workshop/SubmissionWizard/Steps/EntryTypeStepViewModel.cs
index cce78ea9d..620b0e6f4 100644
--- a/src/Artemis.UI/Screens/Workshop/SubmissionWizard/Steps/EntryTypeStepViewModel.cs
+++ b/src/Artemis.UI/Screens/Workshop/SubmissionWizard/Steps/EntryTypeStepViewModel.cs
@@ -35,7 +35,6 @@ public class EntryTypeStepViewModel : SubmissionViewModel
return;
State.EntryType = SelectedEntryType.Value;
- if (State.EntryType == EntryType.Profile)
- State.ChangeScreen();
+ State.StartForCurrentEntry();
}
}
\ No newline at end of file
diff --git a/src/Artemis.UI/Screens/Workshop/SubmissionWizard/Steps/Profile/ProfileAdaptionHintsStepViewModel.cs b/src/Artemis.UI/Screens/Workshop/SubmissionWizard/Steps/Profile/ProfileAdaptionHintsStepViewModel.cs
index 768ca5405..b9ec09c15 100644
--- a/src/Artemis.UI/Screens/Workshop/SubmissionWizard/Steps/Profile/ProfileAdaptionHintsStepViewModel.cs
+++ b/src/Artemis.UI/Screens/Workshop/SubmissionWizard/Steps/Profile/ProfileAdaptionHintsStepViewModel.cs
@@ -62,6 +62,9 @@ public class ProfileAdaptionHintsStepViewModel : SubmissionViewModel
if (Layers.Any(l => l.AdaptionHintCount == 0))
return;
- State.ChangeScreen();
+ if (State.EntryId == null)
+ State.ChangeScreen();
+ else
+ State.ChangeScreen();
}
}
\ No newline at end of file
diff --git a/src/Artemis.UI/Screens/Workshop/SubmissionWizard/Steps/Profile/ProfileSelectionStepViewModel.cs b/src/Artemis.UI/Screens/Workshop/SubmissionWizard/Steps/Profile/ProfileSelectionStepViewModel.cs
index 3cc2b409a..86b49a6d4 100644
--- a/src/Artemis.UI/Screens/Workshop/SubmissionWizard/Steps/Profile/ProfileSelectionStepViewModel.cs
+++ b/src/Artemis.UI/Screens/Workshop/SubmissionWizard/Steps/Profile/ProfileSelectionStepViewModel.cs
@@ -1,34 +1,22 @@
using System;
using System.Collections.ObjectModel;
-using System.IO;
using System.Linq;
using System.Reactive;
using System.Reactive.Disposables;
using System.Reactive.Linq;
using Artemis.Core;
using Artemis.Core.Services;
-using Artemis.Storage.Entities.Profile;
-using Artemis.Storage.Repositories.Interfaces;
using Artemis.UI.Extensions;
using Artemis.UI.Screens.Workshop.Profile;
-using Avalonia;
-using Avalonia.Controls;
-using Avalonia.Controls.Shapes;
-using Avalonia.Layout;
-using Avalonia.Media;
-using Avalonia.Media.Imaging;
using Material.Icons;
-using Material.Icons.Avalonia;
using ReactiveUI;
using SkiaSharp;
-using Path = Avalonia.Controls.Shapes.Path;
namespace Artemis.UI.Screens.Workshop.SubmissionWizard.Steps.Profile;
public class ProfileSelectionStepViewModel : SubmissionViewModel
{
private readonly IProfileService _profileService;
- private readonly IProfileCategoryRepository _profileCategoryRepository;
private ProfileConfiguration? _selectedProfile;
///
@@ -49,26 +37,12 @@ public class ProfileSelectionStepViewModel : SubmissionViewModel
this.WhenAnyValue(vm => vm.SelectedProfile).Subscribe(p => Update(p));
this.WhenActivated((CompositeDisposable _) =>
{
+ ShowGoBack = State.EntryId == null;
if (State.EntrySource is ProfileConfiguration profileConfiguration)
SelectedProfile = Profiles.FirstOrDefault(p => p.ProfileId == profileConfiguration.ProfileId);
});
}
- private void Update(ProfileConfiguration? profileConfiguration)
- {
- ProfilePreview.ProfileConfiguration = null;
-
- foreach (ProfileConfiguration configuration in Profiles)
- {
- if (configuration == profileConfiguration)
- _profileService.ActivateProfile(configuration);
- else
- _profileService.DeactivateProfile(configuration);
- }
-
- ProfilePreview.ProfileConfiguration = profileConfiguration;
- }
-
public ObservableCollection Profiles { get; }
public ProfilePreviewViewModel ProfilePreview { get; }
@@ -84,6 +58,21 @@ public class ProfileSelectionStepViewModel : SubmissionViewModel
///
public override ReactiveCommand GoBack { get; }
+ private void Update(ProfileConfiguration? profileConfiguration)
+ {
+ ProfilePreview.ProfileConfiguration = null;
+
+ foreach (ProfileConfiguration configuration in Profiles)
+ {
+ if (configuration == profileConfiguration)
+ _profileService.ActivateProfile(configuration);
+ else
+ _profileService.DeactivateProfile(configuration);
+ }
+
+ ProfilePreview.ProfileConfiguration = profileConfiguration;
+ }
+
private void ExecuteContinue()
{
if (SelectedProfile == null)
diff --git a/src/Artemis.UI/Screens/Workshop/SubmissionWizard/Steps/UploadStepViewModel.cs b/src/Artemis.UI/Screens/Workshop/SubmissionWizard/Steps/UploadStepViewModel.cs
index fc726e908..c98e44efa 100644
--- a/src/Artemis.UI/Screens/Workshop/SubmissionWizard/Steps/UploadStepViewModel.cs
+++ b/src/Artemis.UI/Screens/Workshop/SubmissionWizard/Steps/UploadStepViewModel.cs
@@ -1,37 +1,36 @@
using System;
using System.Reactive;
+using System.Reactive.Disposables;
using System.Reactive.Linq;
using System.Threading;
using System.Threading.Tasks;
+using Artemis.UI.Shared.Routing;
using Artemis.UI.Shared.Services;
+using Artemis.UI.Shared.Utilities;
using Artemis.WebClient.Workshop;
+using Artemis.WebClient.Workshop.Exceptions;
+using Artemis.WebClient.Workshop.Services;
using Artemis.WebClient.Workshop.UploadHandlers;
using ReactiveUI;
using StrawberryShake;
-using System.Reactive.Disposables;
-using Artemis.Core;
-using Artemis.UI.Shared.Routing;
-using System;
-using Artemis.UI.Shared.Utilities;
-using Artemis.WebClient.Workshop.Services;
namespace Artemis.UI.Screens.Workshop.SubmissionWizard.Steps;
public class UploadStepViewModel : SubmissionViewModel
{
+ private readonly EntryUploadHandlerFactory _entryUploadHandlerFactory;
+ private readonly Progress _progress = new();
+ private readonly ObservableAsPropertyHelper _progressIndeterminate;
+ private readonly ObservableAsPropertyHelper _progressPercentage;
+ private readonly IRouter _router;
+ private readonly IWindowService _windowService;
private readonly IWorkshopClient _workshopClient;
private readonly IWorkshopService _workshopService;
- private readonly EntryUploadHandlerFactory _entryUploadHandlerFactory;
- private readonly IWindowService _windowService;
- private readonly IRouter _router;
- private readonly Progress _progress = new();
- private readonly ObservableAsPropertyHelper _progressPercentage;
- private readonly ObservableAsPropertyHelper _progressIndeterminate;
private Guid? _entryId;
+ private bool _failed;
private bool _finished;
private bool _succeeded;
- private bool _failed;
///
public UploadStepViewModel(IWorkshopClient workshopClient, IWorkshopService workshopService, EntryUploadHandlerFactory entryUploadHandlerFactory, IWindowService windowService, IRouter router)
@@ -83,7 +82,45 @@ public class UploadStepViewModel : SubmissionViewModel
set => RaiseAndSetIfChanged(ref _failed, value);
}
- public async Task ExecuteUpload(CancellationToken cancellationToken)
+ 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
+ {
+ IEntryUploadHandler uploadHandler = _entryUploadHandlerFactory.CreateHandler(State.EntryType);
+ EntryUploadResult uploadResult = await uploadHandler.CreateReleaseAsync(_entryId.Value, State.EntrySource!, _progress, 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);
+ }
+
+ Succeeded = true;
+ }
+ catch (Exception)
+ {
+ // Something went wrong when creating a release :c
+ // We'll keep the workshop entry so that the user can make changes and try again
+ Failed = true;
+ }
+ finally
+ {
+ Finished = true;
+ }
+ }
+
+ private async Task CreateEntry(CancellationToken cancellationToken)
{
IOperationResult result = await _workshopClient.AddEntry.ExecuteAsync(new CreateEntryInput
{
@@ -100,68 +137,45 @@ public class UploadStepViewModel : SubmissionViewModel
{
await _windowService.ShowConfirmContentDialog("Failed to create workshop entry", result.Errors.ToString() ?? "Not even an error message", "Close", null);
State.ChangeScreen();
- return;
+ return null;
}
if (cancellationToken.IsCancellationRequested)
- return;
+ {
+ State.ChangeScreen();
+ return null;
+ }
+
+
+ if (State.Icon == null)
+ return entryId;
// Upload image
- if (State.Icon != null)
- await _workshopService.SetEntryIcon(entryId.Value, _progress, State.Icon, cancellationToken);
-
- // Create the workshop entry
try
{
- IEntryUploadHandler uploadHandler = _entryUploadHandlerFactory.CreateHandler(State.EntryType);
- EntryUploadResult uploadResult = await uploadHandler.CreateReleaseAsync(entryId.Value, State.EntrySource!, _progress, 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);
- return;
- }
-
- _entryId = entryId;
- Succeeded = true;
+ ImageUploadResult imageUploadResult = await _workshopService.SetEntryIcon(entryId.Value, _progress, State.Icon, cancellationToken);
+ if (!imageUploadResult.IsSuccess)
+ throw new ArtemisWorkshopException(imageUploadResult.Message);
}
catch (Exception e)
{
- // Something went wrong when creating a release :c
- // We'll keep the workshop entry so that the user can make changes and try again
- Failed = true;
- }
- finally
- {
- Finished = true;
+ // It's not critical if this fails
+ await _windowService.ShowConfirmContentDialog(
+ "Failed to upload icon",
+ "Your submission will continue, you can try upload a new image afterwards\r\n" + e.Message,
+ "Continue",
+ null
+ );
}
+
+ return entryId;
}
private async Task ExecuteContinue()
{
- State.Finish();
+ State.Close();
- if (_entryId == null)
- return;
-
- switch (State.EntryType)
- {
- case EntryType.Layout:
- await _router.Navigate($"workshop/entries/layouts/{_entryId.Value}");
- break;
- case EntryType.Plugin:
- await _router.Navigate($"workshop/entries/plugins/{_entryId.Value}");
- break;
- case EntryType.Profile:
- await _router.Navigate($"workshop/entries/profiles/{_entryId.Value}");
- break;
- default:
- throw new ArgumentOutOfRangeException();
- }
+ if (_entryId != null)
+ await _router.Navigate($"workshop/library/submissions/{_entryId.Value}");
}
}
\ No newline at end of file
diff --git a/src/Artemis.UI/Screens/Workshop/SubmissionWizard/SubmissionViewModel.cs b/src/Artemis.UI/Screens/Workshop/SubmissionWizard/SubmissionViewModel.cs
index 3cd79cb65..fec465981 100644
--- a/src/Artemis.UI/Screens/Workshop/SubmissionWizard/SubmissionViewModel.cs
+++ b/src/Artemis.UI/Screens/Workshop/SubmissionWizard/SubmissionViewModel.cs
@@ -11,7 +11,6 @@ public abstract class SubmissionViewModel : ValidatableViewModelBase
private bool _showGoBack = true;
private bool _showHeader = true;
- public SubmissionWizardViewModel WizardViewModel { get; set; } = null!;
public SubmissionWizardState State { get; set; } = null!;
public abstract ReactiveCommand Continue { get; }
diff --git a/src/Artemis.UI/Screens/Workshop/SubmissionWizard/SubmissionWizardState.cs b/src/Artemis.UI/Screens/Workshop/SubmissionWizard/SubmissionWizardState.cs
index 3484c8c36..b6f8d53fc 100644
--- a/src/Artemis.UI/Screens/Workshop/SubmissionWizard/SubmissionWizardState.cs
+++ b/src/Artemis.UI/Screens/Workshop/SubmissionWizard/SubmissionWizardState.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.IO;
+using Artemis.UI.Screens.Workshop.SubmissionWizard.Steps.Profile;
using Artemis.UI.Shared.Services;
using Artemis.WebClient.Workshop;
using DryIoc;
@@ -11,9 +12,9 @@ public class SubmissionWizardState
{
private readonly IContainer _container;
private readonly IWindowService _windowService;
- private readonly SubmissionWizardViewModel _wizardViewModel;
+ private readonly IWorkshopWizardViewModel _wizardViewModel;
- public SubmissionWizardState(SubmissionWizardViewModel wizardViewModel, IContainer container, IWindowService windowService)
+ public SubmissionWizardState(IWorkshopWizardViewModel wizardViewModel, IContainer container, IWindowService windowService)
{
_wizardViewModel = wizardViewModel;
_container = container;
@@ -21,6 +22,7 @@ public class SubmissionWizardState
}
public EntryType EntryType { get; set; }
+ public Guid? EntryId { get; set; }
public string Name { get; set; } = string.Empty;
public Stream? Icon { get; set; }
@@ -45,13 +47,16 @@ public class SubmissionWizardState
}
}
- public void Finish()
+ public void Close()
{
- _wizardViewModel.Close(true);
+ _wizardViewModel.ShouldClose = true;
}
- public void Cancel()
+ public void StartForCurrentEntry()
{
- _wizardViewModel.Close(false);
+ if (EntryType == EntryType.Profile)
+ ChangeScreen();
+ else
+ throw new NotImplementedException();
}
}
\ No newline at end of file
diff --git a/src/Artemis.UI/Screens/Workshop/SubmissionWizard/SubmissionWizardView.axaml b/src/Artemis.UI/Screens/Workshop/SubmissionWizard/SubmissionWizardView.axaml
index e313f0f9f..d64ed0199 100644
--- a/src/Artemis.UI/Screens/Workshop/SubmissionWizard/SubmissionWizardView.axaml
+++ b/src/Artemis.UI/Screens/Workshop/SubmissionWizard/SubmissionWizardView.axaml
@@ -18,7 +18,7 @@
-
+
diff --git a/src/Artemis.UI/Screens/Workshop/SubmissionWizard/SubmissionWizardView.axaml.cs b/src/Artemis.UI/Screens/Workshop/SubmissionWizard/SubmissionWizardView.axaml.cs
index cb510d01e..6c7ece92f 100644
--- a/src/Artemis.UI/Screens/Workshop/SubmissionWizard/SubmissionWizardView.axaml.cs
+++ b/src/Artemis.UI/Screens/Workshop/SubmissionWizard/SubmissionWizardView.axaml.cs
@@ -1,5 +1,6 @@
using System;
using System.Reactive.Disposables;
+using System.Reactive.Linq;
using Artemis.UI.Shared;
using Avalonia;
using Avalonia.Threading;
@@ -17,6 +18,7 @@ public partial class SubmissionWizardView : ReactiveAppWindow ViewModel.WhenAnyValue(vm => vm.Screen).Subscribe(Navigate).DisposeWith(d));
+ this.WhenActivated(d => ViewModel.WhenAnyValue(vm => vm.ShouldClose).Where(c => c).Subscribe(_ => Close()).DisposeWith(d));
}
private void Navigate(SubmissionViewModel viewModel)
diff --git a/src/Artemis.UI/Screens/Workshop/SubmissionWizard/SubmissionWizardViewModel.cs b/src/Artemis.UI/Screens/Workshop/SubmissionWizard/SubmissionWizardViewModel.cs
index f2361b8ed..a18c63e71 100644
--- a/src/Artemis.UI/Screens/Workshop/SubmissionWizard/SubmissionWizardViewModel.cs
+++ b/src/Artemis.UI/Screens/Workshop/SubmissionWizard/SubmissionWizardViewModel.cs
@@ -6,16 +6,19 @@ using DryIoc;
namespace Artemis.UI.Screens.Workshop.SubmissionWizard;
-public class SubmissionWizardViewModel : DialogViewModelBase
+public class SubmissionWizardViewModel : ActivatableViewModelBase, IWorkshopWizardViewModel
{
private readonly SubmissionWizardState _state;
private SubmissionViewModel _screen;
+ private bool _shouldClose;
- public SubmissionWizardViewModel(IContainer container, IWindowService windowService, CurrentUserViewModel currentUserViewModel, WelcomeStepViewModel welcomeStepViewModel)
+ public SubmissionWizardViewModel(IContainer container,
+ IWindowService windowService,
+ CurrentUserViewModel currentUserViewModel,
+ WelcomeStepViewModel welcomeStepViewModel)
{
_state = new SubmissionWizardState(this, container, windowService);
_screen = welcomeStepViewModel;
- _screen.WizardViewModel = this;
_screen.State = _state;
WindowService = windowService;
@@ -31,9 +34,14 @@ public class SubmissionWizardViewModel : DialogViewModelBase
get => _screen;
set
{
- value.WizardViewModel = this;
value.State = _state;
RaiseAndSetIfChanged(ref _screen, value);
}
}
+
+ public bool ShouldClose
+ {
+ get => _shouldClose;
+ set => RaiseAndSetIfChanged(ref _shouldClose, value);
+ }
}
\ No newline at end of file
diff --git a/src/Artemis.WebClient.Workshop/Artemis.WebClient.Workshop.csproj b/src/Artemis.WebClient.Workshop/Artemis.WebClient.Workshop.csproj
index 32d841d41..389fa75e5 100644
--- a/src/Artemis.WebClient.Workshop/Artemis.WebClient.Workshop.csproj
+++ b/src/Artemis.WebClient.Workshop/Artemis.WebClient.Workshop.csproj
@@ -44,5 +44,8 @@
MSBuild:GenerateGraphQLCode
+
+ MSBuild:GenerateGraphQLCode
+
diff --git a/src/Artemis.WebClient.Workshop/Queries/UpdateEntry.graphql b/src/Artemis.WebClient.Workshop/Queries/UpdateEntry.graphql
new file mode 100644
index 000000000..fe53ec3e5
--- /dev/null
+++ b/src/Artemis.WebClient.Workshop/Queries/UpdateEntry.graphql
@@ -0,0 +1,5 @@
+mutation UpdateEntry ($input: UpdateEntryInput!) {
+ updateEntry(input: $input) {
+ id
+ }
+}
diff --git a/src/Artemis.WebClient.Workshop/Services/IWorkshopService.cs b/src/Artemis.WebClient.Workshop/Services/IWorkshopService.cs
index f859a4f2c..5c7dbd35f 100644
--- a/src/Artemis.WebClient.Workshop/Services/IWorkshopService.cs
+++ b/src/Artemis.WebClient.Workshop/Services/IWorkshopService.cs
@@ -64,6 +64,24 @@ public class WorkshopService : IWorkshopService
await _router.Navigate($"workshop/offline/{status.Message}");
return status.IsReachable;
}
+
+ public async Task NavigateToEntry(Guid entryId, EntryType entryType)
+ {
+ switch (entryType)
+ {
+ case EntryType.Profile:
+ await _router.Navigate($"workshop/entries/profiles/details/{entryId}");
+ break;
+ case EntryType.Layout:
+ await _router.Navigate($"workshop/entries/layouts/details/{entryId}");
+ break;
+ case EntryType.Plugin:
+ await _router.Navigate($"workshop/entries/plugins/details/{entryId}");
+ break;
+ default:
+ throw new ArgumentOutOfRangeException(nameof(entryType));
+ }
+ }
}
public interface IWorkshopService
@@ -71,6 +89,7 @@ public interface IWorkshopService
Task SetEntryIcon(Guid entryId, Progress progress, Stream icon, CancellationToken cancellationToken);
Task GetWorkshopStatus(CancellationToken cancellationToken);
Task ValidateWorkshopStatus(CancellationToken cancellationToken);
-
+ Task NavigateToEntry(Guid entryId, EntryType entryType);
+
public record WorkshopStatus(bool IsReachable, string Message);
}
\ No newline at end of file