Browse Source

Merge pull request #365 from LykosAI/main

v2.7.6
dependabot/nuget/DeviceId.Linux-and-DeviceId-6.4.0
JT 11 months ago committed by GitHub
parent
commit
a9c48b8072
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 11
      CHANGELOG.md
  2. 20
      StabilityMatrix.Avalonia/Assets/hf-packages.json
  3. 38
      StabilityMatrix.Avalonia/StabilityMatrix.Avalonia.csproj
  4. 16
      StabilityMatrix.Avalonia/ViewModels/CheckpointBrowser/HuggingFacePageViewModel.cs
  5. 19
      StabilityMatrix.Avalonia/ViewModels/Inference/Modules/ControlNetModule.cs
  6. 21
      StabilityMatrix.Avalonia/ViewModels/Inference/SelectImageCardViewModel.cs
  7. 72
      StabilityMatrix.Avalonia/Views/MainWindow.axaml.cs
  8. 29
      StabilityMatrix.Core/Models/HybridModelFile.cs
  9. 4
      StabilityMatrix.Core/Models/Packages/BaseGitPackage.cs
  10. 1
      StabilityMatrix.Core/Python/PipPackageInfo.cs
  11. 8
      StabilityMatrix.Core/Python/PipShowResult.cs
  12. 31
      StabilityMatrix.Core/Services/SettingsManager.cs

11
CHANGELOG.md

@ -5,6 +5,17 @@ All notable changes to Stability Matrix will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning 2.0](https://semver.org/spec/v2.0.0.html).
## v2.7.6
### Added
- Added SDXL Turbo and Stable Video Diffusion to the Hugging Face tab
### Changed
- ControlNet model selector will now show the parent directory of a model when relevant
### Fixed
- Fixed Python Packages dialog crash due to pip commands including warnings
- Fixed Base Model downloads from the Hugging Face tab downloading to the wrong folder
- Fixed InvokeAI `! [rejected] v3.4.0post2 -> v3.4.0post2 (would clobber existing tag)` error on updating to the latest version
- Fixed settings not saving in some scenarios, such as when the `settings.json` file existed but was empty
## v2.7.5
### Fixed
- Fixed Python Packages manager crash when pip list returns warnings in json

20
StabilityMatrix.Avalonia/Assets/hf-packages.json

@ -38,6 +38,26 @@
"LicenseType": "Open RAIL++",
"LicensePath": "LICENSE.md"
},
{
"ModelCategory": "BaseModel",
"ModelName": "SDXL Turbo",
"RepositoryPath": "stabilityai/sdxl-turbo",
"Files": [
"sd_xl_turbo_1.0_fp16.safetensors"
],
"LicenseType": "SAI-NC-Community",
"LicensePath": "LICENSE.TXT"
},
{
"ModelCategory": "BaseModel",
"ModelName": "Stable Video Diffusion",
"RepositoryPath": "stabilityai/stable-video-diffusion-img2vid",
"Files": [
"svd.safetensors"
],
"LicenseType": "Stable-Video-Diffusion-NC-Community",
"LicensePath": "LICENSE"
},
{
"ModelCategory": "ControlNet",
"ModelName": "Canny",

38
StabilityMatrix.Avalonia/StabilityMatrix.Avalonia.csproj

@ -23,29 +23,29 @@
<PackageReference Include="AsyncImageLoader.Avalonia" Version="3.2.1" />
<PackageReference Include="AutoComplete.Net" Version="1.2211.2014.42"/>
<PackageReference Include="Avalonia.AvaloniaEdit" Version="11.0.5" />
<PackageReference Include="Avalonia.Controls.PanAndZoom" Version="11.0.0" />
<PackageReference Include="Avalonia" Version="11.0.5" />
<PackageReference Include="Avalonia.Desktop" Version="11.0.5" />
<PackageReference Include="Avalonia.Fonts.Inter" Version="11.0.5" />
<PackageReference Include="Avalonia.Controls.PanAndZoom" Version="11.0.0.2" />
<PackageReference Include="Avalonia" Version="11.0.6" />
<PackageReference Include="Avalonia.Desktop" Version="11.0.6" />
<PackageReference Include="Avalonia.Fonts.Inter" Version="11.0.6" />
<!--Condition below is needed to remove Avalonia.Diagnostics package from build output in Release configuration.-->
<PackageReference Condition="'$(Configuration)' == 'Debug'" Include="Avalonia.Diagnostics" Version="11.0.5" />
<PackageReference Condition="'$(Configuration)' == 'Debug'" Include="Avalonia.Diagnostics" Version="11.0.6" />
<PackageReference Include="Avalonia.HtmlRenderer" Version="11.0.0" />
<PackageReference Include="Avalonia.Xaml.Behaviors" Version="11.0.5" />
<PackageReference Include="Avalonia.Xaml.Behaviors" Version="11.0.6" />
<PackageReference Include="AvaloniaEdit.TextMate" Version="11.0.5" />
<PackageReference Include="bodong.Avalonia.PropertyGrid" Version="11.0.5.1" />
<PackageReference Include="bodong.PropertyModels" Version="11.0.5.1" />
<PackageReference Include="bodong.Avalonia.PropertyGrid" Version="11.0.6.1" />
<PackageReference Include="bodong.PropertyModels" Version="11.0.6.1" />
<PackageReference Include="CommandLineParser" Version="2.9.1" />
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.2.2" />
<PackageReference Include="DiscordRichPresence" Version="1.2.1.24" />
<PackageReference Include="Dock.Avalonia" Version="11.0.0.3" />
<PackageReference Include="Dock.Model.Avalonia" Version="11.0.0.3" />
<PackageReference Include="Dock.Serializer" Version="11.0.0.3" />
<PackageReference Include="DynamicData" Version="8.1.1" />
<PackageReference Include="Dock.Avalonia" Version="11.0.0.5" />
<PackageReference Include="Dock.Model.Avalonia" Version="11.0.0.5" />
<PackageReference Include="Dock.Serializer" Version="11.0.0.5" />
<PackageReference Include="DynamicData" Version="8.3.27" />
<PackageReference Include="Exceptionless.DateTimeExtensions" Version="3.4.3" />
<PackageReference Include="FluentAvalonia.BreadcrumbBar" Version="2.0.2" />
<PackageReference Include="FluentAvaloniaUI" Version="2.0.4" />
<PackageReference Include="FluentIcons.Avalonia" Version="1.1.222" />
<PackageReference Include="FluentIcons.FluentAvalonia" Version="1.1.222" />
<PackageReference Include="FluentIcons.Avalonia" Version="1.1.224" />
<PackageReference Include="FluentIcons.FluentAvalonia" Version="1.1.224" />
<PackageReference Include="FuzzySharp" Version="2.0.2" />
<PackageReference Include="JetBrains.Annotations" Version="2023.3.0" />
<PackageReference Include="Markdown.Avalonia" Version="11.0.2" />
@ -59,16 +59,16 @@
<PackageReference Include="Microsoft.Extensions.Http.Polly" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="8.0.0" />
<PackageReference Include="Nito.AsyncEx" Version="5.1.2" />
<PackageReference Include="NLog" Version="5.2.5" />
<PackageReference Include="NLog.Extensions.Logging" Version="5.3.5" />
<PackageReference Include="NLog" Version="5.2.7" />
<PackageReference Include="NLog.Extensions.Logging" Version="5.3.7" />
<PackageReference Include="NSubstitute" Version="5.1.0" />
<PackageReference Include="Polly" Version="8.2.0" />
<PackageReference Include="Polly.Contrib.WaitAndRetry" Version="1.1.1" />
<PackageReference Include="Polly.Extensions.Http" Version="3.0.0" />
<PackageReference Include="Projektanker.Icons.Avalonia.FontAwesome" Version="8.3.0" />
<PackageReference Include="Projektanker.Icons.Avalonia.FontAwesome" Version="9.0.1" />
<PackageReference Include="RockLib.Reflection.Optimized" Version="2.0.0" />
<PackageReference Include="Sentry" Version="3.41.0" />
<PackageReference Include="Sentry.NLog" Version="3.41.0" />
<PackageReference Include="Sentry" Version="3.41.3" />
<PackageReference Include="Sentry.NLog" Version="3.41.3" />
<PackageReference Include="SpacedGrid-Avalonia" Version="11.0.0" />
<PackageReference Include="Sylvan.Common" Version="0.4.3" />
<PackageReference Include="Sylvan.Data" Version="0.2.12" />

16
StabilityMatrix.Avalonia/ViewModels/CheckpointBrowser/HuggingFacePageViewModel.cs

@ -41,7 +41,8 @@ public partial class HuggingFacePageViewModel : TabViewModelBase
private readonly ISettingsManager settingsManager;
private readonly INotificationService notificationService;
public SourceCache<HuggingfaceItem, string> ItemsCache { get; } = new(i => i.RepositoryPath + i.ModelName);
public SourceCache<HuggingfaceItem, string> ItemsCache { get; } =
new(i => i.RepositoryPath + i.ModelName);
public IObservableCollection<CategoryViewModel> Categories { get; set; } =
new ObservableCollectionExtended<CategoryViewModel>();
@ -76,7 +77,13 @@ public partial class HuggingFacePageViewModel : TabViewModelBase
.Connect()
.DeferUntilLoaded()
.Group(i => i.ModelCategory)
.Transform(g => new CategoryViewModel(g.Cache.Items) { Title = g.Key.GetDescription() ?? g.Key.ToString() })
.Transform(
g =>
new CategoryViewModel(g.Cache.Items)
{
Title = g.Key.GetDescription() ?? g.Key.ToString()
}
)
.SortBy(vm => vm.Title)
.Bind(Categories)
.WhenAnyPropertyChanged()
@ -137,12 +144,13 @@ public partial class HuggingFacePageViewModel : TabViewModelBase
{
foreach (var file in viewModel.Item.Files)
{
var url = $"https://huggingface.co/{viewModel.Item.RepositoryPath}/resolve/main/{file}?download=true";
var url =
$"https://huggingface.co/{viewModel.Item.RepositoryPath}/resolve/main/{file}?download=true";
var sharedFolderType = viewModel.Item.ModelCategory.ConvertTo<SharedFolderType>();
var downloadPath = new FilePath(
Path.Combine(
settingsManager.ModelsDirectory,
sharedFolderType.GetDescription() ?? sharedFolderType.ToString(),
sharedFolderType.ToString(),
viewModel.Item.Subfolder ?? string.Empty,
file
)

19
StabilityMatrix.Avalonia/ViewModels/Inference/Modules/ControlNetModule.cs

@ -42,9 +42,8 @@ public class ControlNetModule : ModuleBase
{
Name = e.Nodes.GetUniqueName("ControlNet_LoadImage"),
Image =
card.SelectImageCardViewModel.ImageSource?.GetHashGuidFileNameCached(
"Inference"
) ?? throw new ValidationException("No ImageSource")
card.SelectImageCardViewModel.ImageSource?.GetHashGuidFileNameCached("Inference")
?? throw new ValidationException("No ImageSource")
}
);
@ -53,8 +52,7 @@ public class ControlNetModule : ModuleBase
{
Name = e.Nodes.GetUniqueName("ControlNetLoader"),
ControlNetName =
card.SelectedModel?.FileName
?? throw new ValidationException("No SelectedModel"),
card.SelectedModel?.RelativePath ?? throw new ValidationException("No SelectedModel"),
}
);
@ -64,10 +62,8 @@ public class ControlNetModule : ModuleBase
Name = e.Nodes.GetUniqueName("ControlNetApply"),
Image = imageLoad.Output1,
ControlNet = controlNetLoader.Output,
Positive =
e.Temp.Conditioning?.Positive ?? throw new ArgumentException("No Conditioning"),
Negative =
e.Temp.Conditioning?.Negative ?? throw new ArgumentException("No Conditioning"),
Positive = e.Temp.Conditioning?.Positive ?? throw new ArgumentException("No Conditioning"),
Negative = e.Temp.Conditioning?.Negative ?? throw new ArgumentException("No Conditioning"),
Strength = card.Strength,
StartPercent = card.StartPercent,
EndPercent = card.EndPercent,
@ -93,10 +89,7 @@ public class ControlNetModule : ModuleBase
}
);
e.Temp.RefinerConditioning = (
controlNetRefinerApply.Output1,
controlNetRefinerApply.Output2
);
e.Temp.RefinerConditioning = (controlNetRefinerApply.Output1, controlNetRefinerApply.Output2);
}
}
}

21
StabilityMatrix.Avalonia/ViewModels/Inference/SelectImageCardViewModel.cs

@ -71,7 +71,9 @@ public partial class SelectImageCardViewModel(INotificationService notificationS
{
e.Builder.SetupImagePrimarySource(
ImageSource ?? throw new ValidationException("Input Image is required"),
!CurrentBitmapSize.IsEmpty ? CurrentBitmapSize : throw new ValidationException("CurrentBitmapSize is null"),
!CurrentBitmapSize.IsEmpty
? CurrentBitmapSize
: throw new ValidationException("CurrentBitmapSize is null"),
e.Builder.Connections.BatchIndex
);
}
@ -98,7 +100,10 @@ public partial class SelectImageCardViewModel(INotificationService notificationS
private async Task SelectImageFromFilePickerAsync()
{
var files = await App.StorageProvider.OpenFilePickerAsync(
new FilePickerOpenOptions { FileTypeFilter = [FilePickerFileTypes.ImagePng, FilePickerFileTypes.ImageJpg] }
new FilePickerOpenOptions
{
FileTypeFilter = [FilePickerFileTypes.ImagePng, FilePickerFileTypes.ImageJpg]
}
);
if (files.FirstOrDefault()?.TryGetLocalPath() is { } path)
@ -112,7 +117,10 @@ public partial class SelectImageCardViewModel(INotificationService notificationS
/// </summary>
public void DragOver(object? sender, DragEventArgs e)
{
if (e.Data.GetDataFormats().Contains(DataFormats.Files) || e.Data.GetContext<LocalImageFile>() is not null)
if (
e.Data.GetDataFormats().Contains(DataFormats.Files)
|| e.Data.GetContext<LocalImageFile>() is not null
)
{
e.Handled = true;
return;
@ -134,7 +142,10 @@ public partial class SelectImageCardViewModel(INotificationService notificationS
return;
}
// 2. OS Files
if (e.Data.GetFiles() is { } files && files.Select(f => f.TryGetLocalPath()).FirstOrDefault() is { } path)
if (
e.Data.GetFiles() is { } files
&& files.Select(f => f.TryGetLocalPath()).FirstOrDefault() is { } path
)
{
e.Handled = true;
@ -154,7 +165,7 @@ public partial class SelectImageCardViewModel(INotificationService notificationS
catch (Exception e)
{
Logger.Warn(e, "Error loading image");
notificationService.ShowPersistent("Error loading image", e.Message);
notificationService.Show("Error loading image", e.Message);
}
}

72
StabilityMatrix.Avalonia/Views/MainWindow.axaml.cs

@ -132,15 +132,16 @@ public partial class MainWindow : AppWindowBase
return;
// Navigate to first page
Dispatcher
.UIThread
.Post(
() =>
navigationService.NavigateTo(
vm.Pages[0],
new BetterSlideNavigationTransition { Effect = SlideNavigationTransitionEffect.FromBottom }
)
);
Dispatcher.UIThread.Post(
() =>
navigationService.NavigateTo(
vm.Pages[0],
new BetterSlideNavigationTransition
{
Effect = SlideNavigationTransitionEffect.FromBottom
}
)
);
// Check show update teaching tip
if (vm.UpdateViewModel.IsUpdateAvailable)
@ -165,27 +166,24 @@ public partial class MainWindow : AppWindowBase
var mainViewModel = (MainWindowViewModel)DataContext!;
mainViewModel.SelectedCategory = mainViewModel
.Pages
.Concat(mainViewModel.FooterPages)
.Pages.Concat(mainViewModel.FooterPages)
.FirstOrDefault(x => x.GetType() == e.ViewModelType);
}
private void OnUpdateAvailable(object? sender, UpdateInfo? updateInfo)
{
Dispatcher
.UIThread
.Post(() =>
Dispatcher.UIThread.Post(() =>
{
if (DataContext is MainWindowViewModel vm && vm.ShouldShowUpdateAvailableTeachingTip(updateInfo))
{
if (DataContext is MainWindowViewModel vm && vm.ShouldShowUpdateAvailableTeachingTip(updateInfo))
{
var target = this.FindControl<NavigationViewItem>("FooterUpdateItem")!;
var tip = this.FindControl<TeachingTip>("UpdateAvailableTeachingTip")!;
var target = this.FindControl<NavigationViewItem>("FooterUpdateItem")!;
var tip = this.FindControl<TeachingTip>("UpdateAvailableTeachingTip")!;
tip.Target = target;
tip.Subtitle = $"{Compat.AppVersion.ToDisplayString()} -> {updateInfo.Version}";
tip.IsOpen = true;
}
});
tip.Target = target;
tip.Subtitle = $"{Compat.AppVersion.ToDisplayString()} -> {updateInfo.Version}";
tip.IsOpen = true;
}
});
}
public void SetDefaultFonts()
@ -282,18 +280,16 @@ public partial class MainWindow : AppWindowBase
private void OnImageLoadFailed(object? sender, ImageLoadFailedEventArgs e)
{
Dispatcher
.UIThread
.Post(() =>
{
var fileName = Path.GetFileName(e.Url);
var displayName = string.IsNullOrEmpty(fileName) ? e.Url : fileName;
notificationService.ShowPersistent(
"Failed to load image",
$"Could not load '{displayName}'\n({e.Exception.Message})",
NotificationType.Warning
);
});
Dispatcher.UIThread.Post(() =>
{
var fileName = Path.GetFileName(e.Url);
var displayName = string.IsNullOrEmpty(fileName) ? e.Url : fileName;
notificationService.Show(
"Failed to load image",
$"Could not load '{displayName}'\n({e.Exception.Message})",
NotificationType.Warning
);
});
}
private void TryEnableMicaEffect()
@ -319,7 +315,11 @@ public partial class MainWindow : AppWindowBase
else if (ActualThemeVariant == ThemeVariant.Light)
{
// Similar effect here
var color = this.TryFindResource("SolidBackgroundFillColorBase", ThemeVariant.Light, out var value)
var color = this.TryFindResource(
"SolidBackgroundFillColorBase",
ThemeVariant.Light,
out var value
)
? (Color2)(Color)value!
: new Color2(243, 243, 243);

29
StabilityMatrix.Core/Models/HybridModelFile.cs

@ -1,6 +1,7 @@
using System.Diagnostics.CodeAnalysis;
using System.Text.Json.Serialization;
using StabilityMatrix.Core.Models.Database;
using StabilityMatrix.Core.Models.FileInterfaces;
namespace StabilityMatrix.Core.Models;
@ -67,7 +68,27 @@ public record HybridModelFile
return "Default";
}
return Path.GetFileNameWithoutExtension(RelativePath);
var fileName = Path.GetFileNameWithoutExtension(RelativePath);
if (
!fileName.Equals("diffusion_pytorch_model", StringComparison.OrdinalIgnoreCase)
&& !fileName.Equals("ip_adapter", StringComparison.OrdinalIgnoreCase)
)
{
return Path.GetFileNameWithoutExtension(RelativePath);
}
// show a friendlier name when models have the same name like ip_adapter or diffusion_pytorch_model
var directoryName = Path.GetDirectoryName(RelativePath);
if (directoryName is null)
return Path.GetFileNameWithoutExtension(RelativePath);
var lastIndex = directoryName.LastIndexOf(Path.DirectorySeparatorChar);
if (lastIndex < 0)
return $"{fileName} ({directoryName})";
var parentDirectoryName = directoryName.Substring(lastIndex + 1);
return $"{fileName} ({parentDirectoryName})";
}
}
@ -83,11 +104,7 @@ public record HybridModelFile
public static HybridModelFile FromDownloadable(RemoteResource resource)
{
return new HybridModelFile
{
DownloadableResource = resource,
Type = HybridModelType.Downloadable
};
return new HybridModelFile { DownloadableResource = resource, Type = HybridModelType.Downloadable };
}
public string GetId()

4
StabilityMatrix.Core/Models/Packages/BaseGitPackage.cs

@ -319,7 +319,7 @@ public abstract class BaseGitPackage : BasePackage
{
progress?.Report(new ProgressReport(-1f, "Fetching tags...", isIndeterminate: true));
await PrerequisiteHelper
.RunGit(new[] { "fetch", "--tags" }, onConsoleOutput, installedPackage.FullPath)
.RunGit(new[] { "fetch", "--tags", "--force" }, onConsoleOutput, installedPackage.FullPath)
.ConfigureAwait(false);
progress?.Report(
@ -353,7 +353,7 @@ public abstract class BaseGitPackage : BasePackage
// fetch
progress?.Report(new ProgressReport(-1f, "Fetching data...", isIndeterminate: true));
await PrerequisiteHelper
.RunGit("fetch", onConsoleOutput, installedPackage.FullPath)
.RunGit(new[] { "fetch", "--force" }, onConsoleOutput, installedPackage.FullPath)
.ConfigureAwait(false);
if (versionOptions.IsLatest)

1
StabilityMatrix.Core/Python/PipPackageInfo.cs

@ -10,4 +10,5 @@ public readonly record struct PipPackageInfo(
[JsonSourceGenerationOptions(PropertyNamingPolicy = JsonKnownNamingPolicy.SnakeCaseLower)]
[JsonSerializable(typeof(PipPackageInfo))]
[JsonSerializable(typeof(List<PipPackageInfo>))]
internal partial class PipPackageInfoSerializerContext : JsonSerializerContext;

8
StabilityMatrix.Core/Python/PipShowResult.cs

@ -29,7 +29,9 @@ public record PipShowResult
// Decode each line by splitting on first ":" to key and value
var lines = output
.SplitLines(StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries)
.Select(line => line.Split(new[] { ':' }, 2))
// Filter warning lines
.Where(line => !line.StartsWith("WARNING", StringComparison.OrdinalIgnoreCase))
.Select(line => line.Split(':', 2))
.Where(split => split.Length == 2)
.Select(split => new KeyValuePair<string, string>(split[0].Trim(), split[1].Trim()))
.ToDictionary(pair => pair.Key, pair => pair.Value);
@ -46,11 +48,11 @@ public record PipShowResult
Location = lines.GetValueOrDefault("Location"),
Requires = lines
.GetValueOrDefault("Requires")
?.Split(new[] { ',' }, StringSplitOptions.TrimEntries)
?.Split(',', StringSplitOptions.TrimEntries)
.ToList(),
RequiredBy = lines
.GetValueOrDefault("Required-by")
?.Split(new[] { ',' }, StringSplitOptions.TrimEntries)
?.Split(',', StringSplitOptions.TrimEntries)
.ToList()
};
}

31
StabilityMatrix.Core/Services/SettingsManager.cs

@ -134,7 +134,9 @@ public class SettingsManager : ISettingsManager
{
if (expression.Body is not MemberExpression memberExpression)
{
throw new ArgumentException($"Expression must be a member expression, not {expression.Body.NodeType}");
throw new ArgumentException(
$"Expression must be a member expression, not {expression.Body.NodeType}"
);
}
var propertyInfo = memberExpression.Member as PropertyInfo;
@ -226,7 +228,10 @@ public class SettingsManager : ISettingsManager
}
// Invoke property changed event, passing along sender
SettingsPropertyChanged?.Invoke(sender, new RelayPropertyChangedEventArgs(targetPropertyName, true));
SettingsPropertyChanged?.Invoke(
sender,
new RelayPropertyChangedEventArgs(targetPropertyName, true)
);
};
// Set initial value if requested
@ -331,7 +336,10 @@ public class SettingsManager : ISettingsManager
var libraryJsonFile = Compat.AppDataHome.JoinFile("library.json");
var library = new LibrarySettings { LibraryPath = path };
var libraryJson = JsonSerializer.Serialize(library, new JsonSerializerOptions { WriteIndented = true });
var libraryJson = JsonSerializer.Serialize(
library,
new JsonSerializerOptions { WriteIndented = true }
);
libraryJsonFile.WriteAllText(libraryJson);
// actually create the LibraryPath directory
@ -481,7 +489,9 @@ public class SettingsManager : ISettingsManager
public string? GetActivePackageHost()
{
var package = Settings.InstalledPackages.FirstOrDefault(x => x.Id == Settings.ActiveInstalledPackageId);
var package = Settings.InstalledPackages.FirstOrDefault(
x => x.Id == Settings.ActiveInstalledPackageId
);
if (package == null)
return null;
var hostOption = package.LaunchArgs?.FirstOrDefault(x => x.Name.ToLowerInvariant() == "host");
@ -494,7 +504,9 @@ public class SettingsManager : ISettingsManager
public string? GetActivePackagePort()
{
var package = Settings.InstalledPackages.FirstOrDefault(x => x.Id == Settings.ActiveInstalledPackageId);
var package = Settings.InstalledPackages.FirstOrDefault(
x => x.Id == Settings.ActiveInstalledPackageId
);
if (package == null)
return null;
var portOption = package.LaunchArgs?.FirstOrDefault(x => x.Name.ToLowerInvariant() == "port");
@ -615,11 +627,13 @@ public class SettingsManager : ISettingsManager
if (fileStream.Length == 0)
{
Logger.Warn("Settings file is empty, using default settings");
isLoaded = true;
return;
}
if (
JsonSerializer.Deserialize(fileStream, SettingsSerializerContext.Default.Settings) is { } loadedSettings
JsonSerializer.Deserialize(fileStream, SettingsSerializerContext.Default.Settings) is
{ } loadedSettings
)
{
Settings = loadedSettings;
@ -656,7 +670,10 @@ public class SettingsManager : ISettingsManager
return;
}
var jsonBytes = JsonSerializer.SerializeToUtf8Bytes(Settings, SettingsSerializerContext.Default.Settings);
var jsonBytes = JsonSerializer.SerializeToUtf8Bytes(
Settings,
SettingsSerializerContext.Default.Settings
);
File.WriteAllBytes(SettingsPath, jsonBytes);
}

Loading…
Cancel
Save