UI - Added routing (#802)

ColorGradient - Fixed GetColor returning the first stop if position was after the last stop
This commit is contained in:
RobertBeekman authored and GitHub committed 2023-07-02 22:15:38 +02:00
1 parent 79309dcee7
commit 962b13c6ed
77 files changed
+2034 -854

No files matched your search

@@ -149,7 +149,7 @@ public class ProfileConfigurationEditViewModel : DialogViewModelBase<ProfileConf
return;
if (_profileConfiguration.IsBeingEdited)
_profileEditorService.ChangeCurrentProfileConfiguration(null);
await _profileEditorService.ChangeCurrentProfileConfiguration(null);
_profileService.RemoveProfileConfiguration(_profileConfiguration);
Close(_profileConfiguration);
}
@@ -11,9 +11,9 @@ using Artemis.Core;
using Artemis.Core.Services;
using Artemis.UI.DryIoc.Factories;
using Artemis.UI.Shared;
using Artemis.UI.Shared.Routing;
using Artemis.UI.Shared.Services;
using Artemis.UI.Shared.Services.Builders;
using Artemis.UI.Shared.Services.ProfileEditor;
using DynamicData;
using DynamicData.Binding;
using Newtonsoft.Json;
@@ -24,23 +24,19 @@ namespace Artemis.UI.Screens.Sidebar;
public class SidebarCategoryViewModel : ActivatableViewModelBase
{
private readonly IProfileService _profileService;
private readonly ISidebarVmFactory _vmFactory;
private readonly IWindowService _windowService;
private readonly IProfileEditorService _profileEditorService;
private readonly ISidebarVmFactory _vmFactory;
private readonly IRouter _router;
private ObservableAsPropertyHelper<bool>? _isCollapsed;
private ObservableAsPropertyHelper<bool>? _isSuspended;
private SidebarProfileConfigurationViewModel? _selectedProfileConfiguration;
public SidebarCategoryViewModel(ProfileCategory profileCategory,
IProfileService profileService,
IWindowService windowService,
IProfileEditorService profileEditorService,
ISidebarVmFactory vmFactory)
public SidebarCategoryViewModel(ProfileCategory profileCategory, IProfileService profileService, IWindowService windowService, ISidebarVmFactory vmFactory, IRouter router)
{
_profileService = profileService;
_windowService = windowService;
_profileEditorService = profileEditorService;
_vmFactory = vmFactory;
_router = router;
ProfileCategory = profileCategory;
SourceList<ProfileConfiguration> profileConfigurations = new();
@@ -66,6 +62,14 @@ public class SidebarCategoryViewModel : ActivatableViewModelBase
this.WhenActivated(d =>
{
// Navigate on selection change
this.WhenAnyValue(vm => vm.SelectedProfileConfiguration)
.WhereNotNull()
.Subscribe(s => _router.Navigate($"profile-editor/{s.ProfileConfiguration.ProfileId}", new RouterNavigationOptions {IgnoreOnPartialMatch = true, RecycleScreens = false}))
.DisposeWith(d);
_router.CurrentPath.WhereNotNull().Subscribe(r => SelectedProfileConfiguration = ProfileConfigurations.FirstOrDefault(c => c.Matches(r))).DisposeWith(d);
// Update the list of profiles whenever the category fires events
Observable.FromEventPattern<ProfileConfigurationEventArgs>(x => profileCategory.ProfileConfigurationAdded += x, x => profileCategory.ProfileConfigurationAdded -= x)
.Subscribe(e => profileConfigurations.Add(e.EventArgs.ProfileConfiguration))
@@ -73,34 +77,9 @@ public class SidebarCategoryViewModel : ActivatableViewModelBase
Observable.FromEventPattern<ProfileConfigurationEventArgs>(x => profileCategory.ProfileConfigurationRemoved += x, x => profileCategory.ProfileConfigurationRemoved -= x)
.Subscribe(e => profileConfigurations.RemoveMany(profileConfigurations.Items.Where(c => c == e.EventArgs.ProfileConfiguration)))
.DisposeWith(d);
profileEditorService.ProfileConfiguration
.Subscribe(p => SelectedProfileConfiguration = ProfileConfigurations.FirstOrDefault(c => ReferenceEquals(c.ProfileConfiguration, p)))
.DisposeWith(d);
_isCollapsed = ProfileCategory.WhenAnyValue(vm => vm.IsCollapsed).ToProperty(this, vm => vm.IsCollapsed).DisposeWith(d);
_isSuspended = ProfileCategory.WhenAnyValue(vm => vm.IsSuspended).ToProperty(this, vm => vm.IsSuspended).DisposeWith(d);
// Change the current profile configuration when a new one is selected
this.WhenAnyValue(vm => vm.SelectedProfileConfiguration)
.WhereNotNull()
.Subscribe(s =>
{
try
{
profileEditorService.ChangeCurrentProfileConfiguration(s.ProfileConfiguration);
}
catch (Exception e)
{
if (s.ProfileConfiguration.BrokenState != null && s.ProfileConfiguration.BrokenStateException != null)
_windowService.ShowExceptionDialog(s.ProfileConfiguration.BrokenState, s.ProfileConfiguration.BrokenStateException);
else
_windowService.ShowExceptionDialog(e.Message, e);
profileEditorService.ChangeCurrentProfileConfiguration(null);
SelectedProfileConfiguration = null;
}
});
});
profileConfigurations.Edit(updater =>
@@ -158,7 +137,7 @@ public class SidebarCategoryViewModel : ActivatableViewModelBase
if (await _windowService.ShowConfirmContentDialog($"Delete {ProfileCategory.Name}", "Do you want to delete this category and all its profiles?"))
{
if (ProfileCategory.ProfileConfigurations.Any(c => c.IsBeingEdited))
_profileEditorService.ChangeCurrentProfileConfiguration(null);
await _router.Navigate("home");
_profileService.DeleteProfileCategory(ProfileCategory);
}
}
@@ -8,6 +8,7 @@ using System.Threading.Tasks;
using Artemis.Core;
using Artemis.Core.Services;
using Artemis.UI.Shared;
using Artemis.UI.Shared.Routing;
using Artemis.UI.Shared.Services;
using Artemis.UI.Shared.Services.ProfileEditor;
using Newtonsoft.Json;
@@ -17,15 +18,15 @@ namespace Artemis.UI.Screens.Sidebar;
public class SidebarProfileConfigurationViewModel : ActivatableViewModelBase
{
private readonly IProfileEditorService _profileEditorService;
private readonly IRouter _router;
private readonly IProfileService _profileService;
private readonly IWindowService _windowService;
private ObservableAsPropertyHelper<bool>? _isDisabled;
public SidebarProfileConfigurationViewModel(ProfileConfiguration profileConfiguration, IProfileService profileService, IProfileEditorService profileEditorService, IWindowService windowService)
public SidebarProfileConfigurationViewModel(IRouter router, ProfileConfiguration profileConfiguration, IProfileService profileService, IWindowService windowService)
{
_router = router;
_profileService = profileService;
_profileEditorService = profileEditorService;
_windowService = windowService;
ProfileConfiguration = profileConfiguration;
@@ -98,7 +99,7 @@ public class SidebarProfileConfigurationViewModel : ActivatableViewModelBase
return;
if (ProfileConfiguration.IsBeingEdited)
_profileEditorService.ChangeCurrentProfileConfiguration(null);
await _router.Navigate("home");
_profileService.RemoveProfileConfiguration(ProfileConfiguration);
}
@@ -131,4 +132,9 @@ public class SidebarProfileConfigurationViewModel : ActivatableViewModelBase
ProfileConfigurationExportModel export = _profileService.ExportProfile(ProfileConfiguration);
_profileService.ImportProfile(ProfileConfiguration.Category, export, true, false, "copy");
}
public bool Matches(string s)
{
return s.StartsWith("profile-editor") && s.EndsWith(ProfileConfiguration.ProfileId.ToString());
}
}
@@ -1,35 +1,25 @@
using System;
using Artemis.UI.Shared;
using DryIoc;
using Material.Icons;
using ReactiveUI;
namespace Artemis.UI.Screens.Sidebar;
public class SidebarScreenViewModel<T> : SidebarScreenViewModel where T : MainScreenViewModel
public class SidebarScreenViewModel : ViewModelBase
{
public SidebarScreenViewModel(MaterialIconKind icon, string displayName) : base(icon, displayName)
{
}
public override Type ScreenType => typeof(T);
public override MainScreenViewModel CreateInstance(IContainer container, IScreen screen)
{
return container.Resolve<T>(new object[] { screen });
}
}
public abstract class SidebarScreenViewModel : ViewModelBase
{
protected SidebarScreenViewModel(MaterialIconKind icon, string displayName)
public SidebarScreenViewModel(MaterialIconKind icon, string displayName, string path)
{
Icon = icon;
Path = path;
DisplayName = displayName;
}
public MaterialIconKind Icon { get; }
public string Path { get; }
public abstract Type ScreenType { get; }
public abstract MainScreenViewModel CreateInstance(IContainer container, IScreen screen);
public bool Matches(string? path)
{
if (path == null)
return false;
return path.StartsWith(Path, StringComparison.InvariantCultureIgnoreCase);
}
}
@@ -8,17 +8,12 @@ using System.Threading.Tasks;
using Artemis.Core;
using Artemis.Core.Services;
using Artemis.UI.DryIoc.Factories;
using Artemis.UI.Screens.Home;
using Artemis.UI.Screens.ProfileEditor;
using Artemis.UI.Screens.Settings;
using Artemis.UI.Screens.SurfaceEditor;
using Artemis.UI.Screens.Workshop;
using Artemis.UI.Shared;
using Artemis.UI.Shared.Routing;
using Artemis.UI.Shared.Services;
using Artemis.UI.Shared.Services.Builders;
using Artemis.UI.Shared.Services.ProfileEditor;
using Avalonia.ReactiveUI;
using DryIoc;
using Avalonia.Threading;
using DynamicData;
using DynamicData.Binding;
using Material.Icons;
@@ -28,50 +23,34 @@ namespace Artemis.UI.Screens.Sidebar;
public class SidebarViewModel : ActivatableViewModelBase
{
private readonly IScreen _hostScreen;
private readonly IContainer _container;
private readonly IProfileEditorService _profileEditorService;
private readonly IProfileEditorVmFactory _profileEditorVmFactory;
private readonly IRouter _router;
private readonly IWindowService _windowService;
private SidebarScreenViewModel? _selectedSidebarScreen;
private ReadOnlyObservableCollection<SidebarCategoryViewModel> _sidebarCategories = new(new ObservableCollection<SidebarCategoryViewModel>());
public SidebarViewModel(IScreen hostScreen,
IContainer container,
IProfileService profileService,
IWindowService windowService,
IProfileEditorService profileEditorService,
ISidebarVmFactory sidebarVmFactory,
IProfileEditorVmFactory profileEditorVmFactory)
public SidebarViewModel(IRouter router, IProfileService profileService, IWindowService windowService, ISidebarVmFactory sidebarVmFactory)
{
_hostScreen = hostScreen;
_container = container;
_router = router;
_windowService = windowService;
_profileEditorService = profileEditorService;
_profileEditorVmFactory = profileEditorVmFactory;
SidebarScreens = new ObservableCollection<SidebarScreenViewModel>
{
new SidebarScreenViewModel<HomeViewModel>(MaterialIconKind.Home, "Home"),
new(MaterialIconKind.Home, "Home", "home"),
#if DEBUG
new SidebarScreenViewModel<WorkshopViewModel>(MaterialIconKind.TestTube, "Workshop"),
new(MaterialIconKind.TestTube, "Workshop", "workshop"),
#endif
new SidebarScreenViewModel<SurfaceEditorViewModel>(MaterialIconKind.Devices, "Surface Editor"),
new SidebarScreenViewModel<SettingsViewModel>(MaterialIconKind.Cog, "Settings")
new(MaterialIconKind.Devices, "Surface Editor", "surface-editor"),
new(MaterialIconKind.Cog, "Settings", "settings")
};
AddCategory = ReactiveCommand.CreateFromTask(ExecuteAddCategory);
SourceList<ProfileCategory> profileCategories = new();
this.WhenAnyValue(vm => vm.SelectedSidebarScreen).WhereNotNull().Subscribe(NavigateToScreen);
this.WhenActivated(d =>
{
this.WhenAnyObservable(vm => vm._hostScreen.Router.CurrentViewModel).WhereNotNull()
.Subscribe(c => SelectedSidebarScreen = SidebarScreens.FirstOrDefault(s => s.ScreenType == c.GetType()))
.DisposeWith(d);
this.WhenAnyValue(vm => vm.SelectedSidebarScreen).WhereNotNull().Subscribe(NavigateToScreen);
this.WhenAnyObservable(vm => vm._profileEditorService.ProfileConfiguration).Subscribe(NavigateToProfile).DisposeWith(d);
_router.CurrentPath.WhereNotNull().Subscribe(r => SelectedSidebarScreen = SidebarScreens.FirstOrDefault(s => s.Matches(r))).DisposeWith(d);
Observable.FromEventPattern<ProfileCategoryEventArgs>(x => profileService.ProfileCategoryAdded += x, x => profileService.ProfileCategoryAdded -= x)
.Subscribe(e => profileCategories.Add(e.EventArgs.ProfileCategory))
@@ -127,21 +106,18 @@ public class SidebarViewModel : ActivatableViewModelBase
.ShowAsync();
}
private void NavigateToProfile(ProfileConfiguration? profile)
{
if (profile == null && _hostScreen.Router.GetCurrentViewModel() is ProfileEditorViewModel)
SelectedSidebarScreen = SidebarScreens.FirstOrDefault();
else if (profile != null && _hostScreen.Router.GetCurrentViewModel() is not ProfileEditorViewModel)
_hostScreen.Router.Navigate.Execute(_profileEditorVmFactory.ProfileEditorViewModel(_hostScreen));
}
private void NavigateToScreen(SidebarScreenViewModel sidebarScreenViewModel)
{
// If the current screen changed through external means and already matches, don't navigate again
if (_hostScreen.Router.GetCurrentViewModel()?.GetType() == sidebarScreenViewModel.ScreenType)
return;
_hostScreen.Router.Navigate.Execute(sidebarScreenViewModel.CreateInstance(_container, _hostScreen));
_profileEditorService.ChangeCurrentProfileConfiguration(null);
Dispatcher.UIThread.Invoke(async () =>
{
try
{
await _router.Navigate(sidebarScreenViewModel.Path, new RouterNavigationOptions {IgnoreOnPartialMatch = true});
}
catch (Exception e)
{
_windowService.ShowExceptionDialog("Navigation failed", e);
}
});
}
}