Storage - Replace LiteDB with SQLite + EF Core (#843)

Storage - Added LiteDB to SQLite migration
UI - Try to die a bit more gracefully
Core - Delay start watching plugins for hot reload after initializing
UI - Simplify category management logic
UI - Avoid crash during profile icon load
Storage - Fix entry metadata retrieval
This commit is contained in:
RobertBeekman authored and GitHub committed 2024-03-13 20:19:21 +01:00
1 parent 9132301dbf
commit 551921db9f
130 files changed
+2965 -1135

No files matched your search

@@ -186,7 +186,7 @@ public partial class ProfileEditorViewModel : RoutableScreen<ProfileEditorViewMo
/// <inheritdoc />
public override async Task OnNavigating(ProfileEditorViewModelParameters parameters, NavigationArguments args, CancellationToken cancellationToken)
{
ProfileConfiguration? profileConfiguration = _profileService.ProfileConfigurations.FirstOrDefault(c => c.ProfileId == parameters.ProfileId);
ProfileConfiguration? profileConfiguration = _profileService.ProfileCategories.SelectMany(c => c.ProfileConfigurations).FirstOrDefault(c => c.ProfileId == parameters.ProfileId);
// If the profile doesn't exist, cancel navigation
if (profileConfiguration == null)
+24 -12
View File
@@ -19,6 +19,7 @@ using Avalonia.Controls;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Threading;
using ReactiveUI;
using Serilog;
namespace Artemis.UI.Screens.Root;
@@ -28,13 +29,15 @@ public class RootViewModel : RoutableHostScreen<RoutableScreen>, IMainWindowProv
private readonly IDebugService _debugService;
private readonly DefaultTitleBarViewModel _defaultTitleBarViewModel;
private readonly IClassicDesktopStyleApplicationLifetime _lifeTime;
private readonly ILogger _logger;
private readonly IRouter _router;
private readonly ISettingsService _settingsService;
private readonly IUpdateService _updateService;
private readonly IWindowService _windowService;
private readonly ObservableAsPropertyHelper<ViewModelBase?> _titleBarViewModel;
public RootViewModel(IRouter router,
public RootViewModel(ILogger logger,
IRouter router,
ICoreService coreService,
ISettingsService settingsService,
IRegistrationService registrationService,
@@ -50,6 +53,7 @@ public class RootViewModel : RoutableHostScreen<RoutableScreen>, IMainWindowProv
WindowSizeSetting = settingsService.GetSetting<WindowSize?>("WindowSize");
SidebarViewModel = sidebarViewModel;
_logger = logger;
_router = router;
_coreService = coreService;
_settingsService = settingsService;
@@ -81,19 +85,27 @@ public class RootViewModel : RoutableHostScreen<RoutableScreen>, IMainWindowProv
Task.Run(() =>
{
// Before doing heavy lifting, initialize the update service which may prompt a restart
// Only initialize with an update check if we're not going to show the UI
if (_updateService.Initialize(!ShouldShowUI()))
return;
try
{
// Before doing heavy lifting, initialize the update service which may prompt a restart
// Only initialize with an update check if we're not going to show the UI
if (_updateService.Initialize(!ShouldShowUI()))
return;
// Workshop service goes first so it has a chance to clean up old workshop entries and introduce new ones
workshopService.Initialize();
// Core is initialized now that everything is ready to go
coreService.Initialize();
// Workshop service goes first so it has a chance to clean up old workshop entries and introduce new ones
workshopService.Initialize();
// Core is initialized now that everything is ready to go
coreService.Initialize();
registrationService.RegisterBuiltInDataModelDisplays();
registrationService.RegisterBuiltInDataModelInputs();
registrationService.RegisterBuiltInPropertyEditors();
registrationService.RegisterBuiltInDataModelDisplays();
registrationService.RegisterBuiltInDataModelInputs();
registrationService.RegisterBuiltInPropertyEditors();
}
catch (Exception e)
{
_logger.Fatal(e, "Error during initialization");
_windowService.ShowExceptionDialog("Fatal error occured during initialization", e);
}
});
}
@@ -174,16 +174,15 @@
<StackPanel Grid.Row="0" Grid.Column="0">
<TextBlock Classes="library-name">Avalonia</TextBlock>
<TextBlock Classes="library-name">DryIoc</TextBlock>
<TextBlock Classes="library-name">Entity Framework Core</TextBlock>
<TextBlock Classes="library-name">FluentAvalonia</TextBlock>
<TextBlock Classes="library-name">EmbedIO</TextBlock>
<TextBlock Classes="library-name">Humanizer</TextBlock>
<TextBlock Classes="library-name">LiteDB</TextBlock>
<TextBlock Classes="library-name">McMaster.NETCore.Plugins</TextBlock>
<TextBlock Classes="library-name">Newtonsoft.Json</TextBlock>
<TextBlock Classes="library-name">RGB.NET</TextBlock>
<TextBlock Classes="library-name">Serilog</TextBlock>
<TextBlock Classes="library-name">SkiaSharp</TextBlock>
<TextBlock Classes="library-name">Unclassified.NetRevisionTask</TextBlock>
<TextBlock Classes="library-name">SQLite</TextBlock>
</StackPanel>
<StackPanel Grid.Column="1">
<controls:HyperlinkButton NavigateUri="https://avaloniaui.net/">
@@ -192,6 +191,9 @@
<controls:HyperlinkButton NavigateUri="https://github.com/dadhi/DryIoc">
https://github.com/dadhi/DryIoc
</controls:HyperlinkButton>
<controls:HyperlinkButton NavigateUri="https://learn.microsoft.com/en-us/ef/core/">
https://learn.microsoft.com/en-us/ef/core/
</controls:HyperlinkButton>
<controls:HyperlinkButton NavigateUri="https://github.com/amwx/FluentAvalonia">
https://github.com/amwx/FluentAvalonia
</controls:HyperlinkButton>
@@ -201,15 +203,9 @@
<controls:HyperlinkButton NavigateUri="https://github.com/Humanizr/Humanizer">
https://github.com/Humanizr/Humanizer
</controls:HyperlinkButton>
<controls:HyperlinkButton NavigateUri="https://www.litedb.org/">
https://www.litedb.org/
</controls:HyperlinkButton>
<controls:HyperlinkButton NavigateUri="https://github.com/natemcmaster/DotNetCorePlugins">
https://github.com/natemcmaster/DotNetCorePlugins
</controls:HyperlinkButton>
<controls:HyperlinkButton NavigateUri="https://www.newtonsoft.com/json">
https://www.newtonsoft.com/json
</controls:HyperlinkButton>
<controls:HyperlinkButton NavigateUri="https://github.com/DarthAffe/RGB.NET">
https://github.com/DarthAffe/RGB.NET
</controls:HyperlinkButton>
@@ -218,9 +214,9 @@
</controls:HyperlinkButton>
<controls:HyperlinkButton NavigateUri="https://github.com/mono/SkiaSharp">
https://github.com/mono/SkiaSharp
</controls:HyperlinkButton>
<controls:HyperlinkButton NavigateUri="https://unclassified.software/en/apps/netrevisiontask">
https://unclassified.software/en/apps/netrevisiontask
</controls:HyperlinkButton>
<controls:HyperlinkButton NavigateUri="https://www.sqlite.org/">
https://www.sqlite.org/
</controls:HyperlinkButton>
</StackPanel>
</Grid>
@@ -162,7 +162,7 @@ public class GeneralTabViewModel : RoutableScreen
public PluginSetting<bool> ProfileEditorShowDataModelValues => _settingsService.GetSetting("ProfileEditor.ShowDataModelValues", false);
public PluginSetting<LogEventLevel> CoreLoggingLevel => _settingsService.GetSetting("Core.LoggingLevel", LogEventLevel.Information);
public PluginSetting<string> CorePreferredGraphicsContext => _settingsService.GetSetting("Core.PreferredGraphicsContext", "Software");
public PluginSetting<double> CoreRenderScale => _settingsService.GetSetting("Core.RenderScale", 0.25);
public PluginSetting<double> CoreRenderScale => _settingsService.GetSetting("Core.RenderScale", 0.5);
public PluginSetting<int> CoreTargetFrameRate => _settingsService.GetSetting("Core.TargetFrameRate", 30);
public PluginSetting<bool> WebServerEnabled => _settingsService.GetSetting("WebServer.Enabled", true);
public PluginSetting<int> WebServerPort => _settingsService.GetSetting("WebServer.Port", 9696);
@@ -68,8 +68,8 @@ public class SidebarCategoryViewDropHandler : DropHandlerBase
{
int index = vm.ProfileConfigurations.IndexOf(targetItem);
if (!before)
index++;
vm.AddProfileConfiguration(sourceItem.ProfileConfiguration, index);
targetItem = index < vm.ProfileConfigurations.Count - 1 ? vm.ProfileConfigurations[index + 1] : null;
vm.AddProfileConfiguration(sourceItem.ProfileConfiguration, targetItem?.ProfileConfiguration);
}
else
{
@@ -122,8 +122,8 @@ public partial class ProfileConfigurationEditViewModel : DialogViewModelBase<Pro
ProfileConfiguration.FadeInAndOut = FadeInAndOut;
await SaveIcon();
ProfileConfiguration.Save();
_profileService.SaveProfileConfigurationIcon(ProfileConfiguration);
_profileService.SaveProfileCategory(_profileCategory);
Close(ProfileConfiguration);
}
@@ -144,7 +144,7 @@ public partial class ProfileConfigurationEditViewModel : DialogViewModelBase<Pro
{
try
{
Stream? iconStream = _profileConfiguration.Icon.GetIconStream();
Stream? iconStream = _profileConfiguration.Icon.IconBytes != null ? new MemoryStream(_profileConfiguration.Icon.IconBytes) : null;
SelectedBitmapSource = iconStream != null ? new Bitmap(iconStream) : null;
}
catch (Exception e)
@@ -103,10 +103,10 @@ public partial class SidebarCategoryViewModel : ActivatableViewModelBase
public bool IsCollapsed => _isCollapsed?.Value ?? false;
public bool IsSuspended => _isSuspended?.Value ?? false;
public void AddProfileConfiguration(ProfileConfiguration profileConfiguration, int? index)
public void AddProfileConfiguration(ProfileConfiguration profileConfiguration, ProfileConfiguration? target)
{
ProfileCategory oldCategory = profileConfiguration.Category;
ProfileCategory.AddProfileConfiguration(profileConfiguration, index);
ProfileCategory.AddProfileConfiguration(profileConfiguration, target);
_profileService.SaveProfileCategory(ProfileCategory);
// If the profile moved to a new category, also save the old category
@@ -40,15 +40,6 @@ public class SidebarProfileConfigurationViewModel : ActivatableViewModelBase
.Select(p => p == null)
.ToProperty(this, vm => vm.IsDisabled)
.DisposeWith(d));
try
{
_profileService.LoadProfileConfigurationIcon(ProfileConfiguration);
}
catch (Exception)
{
// ignored, too bad but don't crash over corrupt icons
}
}
public ProfileConfiguration ProfileConfiguration { get; }
@@ -97,7 +97,7 @@ public partial class SurfaceDeviceViewModel : ActivatableViewModelBase
if (x < 0 || y < 0)
return false;
double maxTextureSize = 4096 / _settingsService.GetSetting("Core.RenderScale", 0.25).Value;
double maxTextureSize = 4096 / _settingsService.GetSetting("Core.RenderScale", 0.5).Value;
if (x + Device.Rectangle.Width > maxTextureSize || y + Device.Rectangle.Height > maxTextureSize)
return false;
@@ -87,7 +87,7 @@ public partial class SurfaceEditorViewModel : RoutableScreen, IMainScreenViewMod
public ReactiveCommand<ArtemisDevice, Unit> SendToBack { get; }
public ReactiveCommand<ArtemisDevice, Unit> SendBackward { get; }
public double MaxTextureSize => 4096 / _settingsService.GetSetting("Core.RenderScale", 0.25).Value;
public double MaxTextureSize => 4096 / _settingsService.GetSetting("Core.RenderScale", 0.5).Value;
public void UpdateSelection(List<SurfaceDeviceViewModel> devices, bool expand, bool invert)
{
@@ -1,5 +1,6 @@
using System;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using System.Reactive.Disposables;
using System.Reactive.Linq;
@@ -27,10 +28,7 @@ public partial class ProfileSelectionStepViewModel : SubmissionViewModel
_profileService = profileService;
// Use copies of the profiles, the originals are used by the core and could be disposed
Profiles = new ObservableCollection<ProfileConfiguration>(_profileService.ProfileConfigurations.Select(_profileService.CloneProfileConfiguration));
foreach (ProfileConfiguration profileConfiguration in Profiles)
_profileService.LoadProfileConfigurationIcon(profileConfiguration);
Profiles = new ObservableCollection<ProfileConfiguration>(_profileService.ProfileCategories.SelectMany(c => c.ProfileConfigurations).Select(_profileService.CloneProfileConfiguration));
ProfilePreview = profilePreviewViewModel;
GoBack = ReactiveCommand.Create(() => State.ChangeScreen<EntryTypeStepViewModel>());
@@ -70,7 +68,7 @@ public partial class ProfileSelectionStepViewModel : SubmissionViewModel
State.EntrySource = new ProfileEntrySource(SelectedProfile, SelectedProfile.GetFeatureDependencies().Distinct().ToList());
State.Name = SelectedProfile.Name;
State.Icon = SelectedProfile.Icon.GetIconStream();
State.Icon = SelectedProfile.Icon.IconBytes != null ? new MemoryStream(SelectedProfile.Icon.IconBytes) : null;
// Render the material icon of the profile
if (State.Icon == null && SelectedProfile.Icon.IconName != null)