diff --git a/CHANGELOG.md b/CHANGELOG.md index 2287c1e8b..0a2669171 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,25 @@ 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.12.4 +### Added +- Added new package - [CogVideo](https://github.com/THUDM/CogVideo) - many thanks to @NullDev for the contribution! +- Added more formatting options for Inference output filenames - thanks to @yansigit! +### Changed +- Model browser base model types are now loaded dynamically from CivitAI, reducing the need for updates to add new types +### Fixed +- Fixed crash when clicking "Remind me Later" on the update dialog +- Fixed some cases of crashing when GitHub API rate limits are exceeded +- Fixed Git missing from env vars when running SwarmUI +- Fixed missing package thumbnails due to moved or inaccessible urls +- Fixed an issue with updating FluxGym in certain cases - thanks to @NullDev! +- Fixed a typo in the Japanese translation - thanks to @mattyatea! +### Supporters +#### Visionaries +- A huge thank you to our dedicated Visionary-tier Patreon supporter, **Waterclouds**! We’re thrilled to have your ongoing support! +#### Pioneers +- Shoutout to our great Pioneer-tier patrons: **tankfox**, **tanangular**, **Mr. Unknown**, **Szir777**, and our newest Pioneer, **Tigon**!. Your continued support is greatly appreciated! + ## v2.12.3 ### Added - Added new package - [SimpleSDXL](https://github.com/metercai/SimpleSDXL) - many thanks to @NullDev for the contribution! diff --git a/Directory.Build.props b/Directory.Build.props index ebef34b63..3b07e6b68 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -2,4 +2,10 @@ 11.1.4 + + + + $(NoWarn);CsWinRT1028 + diff --git a/StabilityMatrix.Avalonia/Behaviors/TextEditorToolTipBehavior.cs b/StabilityMatrix.Avalonia/Behaviors/TextEditorToolTipBehavior.cs index d04e2f741..90c860db2 100644 --- a/StabilityMatrix.Avalonia/Behaviors/TextEditorToolTipBehavior.cs +++ b/StabilityMatrix.Avalonia/Behaviors/TextEditorToolTipBehavior.cs @@ -1,6 +1,8 @@ using System; using System.Diagnostics.CodeAnalysis; using System.Linq; +using System.Reactive.Linq; +using System.Threading; using Avalonia; using Avalonia.Controls; using Avalonia.Input; @@ -29,9 +31,7 @@ public class TextEditorToolTipBehavior : Behavior private ToolTip? toolTip; public static readonly StyledProperty TokenizerProviderProperty = - AvaloniaProperty.Register( - "TokenizerProvider" - ); + AvaloniaProperty.Register("TokenizerProvider"); public ITokenizerProvider? TokenizerProvider { @@ -137,6 +137,7 @@ private void TextEditor_OnPointerHover(object? sender, PointerEventArgs e) toolTip .GetPropertyChangedObservable(ToolTip.IsOpenProperty) + .ObserveOn(SynchronizationContext.Current) .Subscribe(c => { if (c.NewValue as bool? != true) @@ -159,10 +160,7 @@ private void TextEditor_OnPointerHover(object? sender, PointerEventArgs e) private ToolTipData? GetCaretToolTipData(TextViewPosition position) { var logicalPosition = position.Location; - var pointerOffset = textEditor.Document.GetOffset( - logicalPosition.Line, - logicalPosition.Column - ); + var pointerOffset = textEditor.Document.GetOffset(logicalPosition.Line, logicalPosition.Column); var line = textEditor.Document.GetLineByOffset(pointerOffset); var lineText = textEditor.Document.GetText(line.Offset, line.Length); @@ -227,10 +225,7 @@ private void TextEditor_OnPointerHover(object? sender, PointerEventArgs e) if (result.Tokens.ElementAtOrDefault(currentTokenIndex + tokenOffset) is { } token) { // Check supported scopes - if ( - token.Scopes.Where(s => s.Contains("invalid")).ToArray() is - { Length: > 0 } results - ) + if (token.Scopes.Where(s => s.Contains("invalid")).ToArray() is { Length: > 0 } results) { // Special cases if (results.Contains("invalid.illegal.mismatched.parenthesis.closing.prompt")) diff --git a/StabilityMatrix.Avalonia/Collections/SearchCollection.cs b/StabilityMatrix.Avalonia/Collections/SearchCollection.cs index 6a268ec2f..c2b4b9531 100644 --- a/StabilityMatrix.Avalonia/Collections/SearchCollection.cs +++ b/StabilityMatrix.Avalonia/Collections/SearchCollection.cs @@ -3,6 +3,7 @@ using System.Reactive; using System.Reactive.Disposables; using System.Reactive.Linq; +using System.Threading; using DynamicData; using DynamicData.Binding; using JetBrains.Annotations; @@ -72,6 +73,7 @@ public SearchCollection( .Filter(dynamicPredicate) .Sort(SortComparer) .Bind(FilteredItems) + .ObserveOn(SynchronizationContext.Current) .Subscribe(); } @@ -114,6 +116,7 @@ public SearchCollection( .Sort(SearchItemSortComparer, SortOptimisations.ComparesImmutableValuesOnly) .Transform(searchItem => searchItem.Item) .Bind(FilteredItems) + .ObserveOn(SynchronizationContext.Current) .Subscribe() ); } diff --git a/StabilityMatrix.Avalonia/Controls/BetterComboBox.cs b/StabilityMatrix.Avalonia/Controls/BetterComboBox.cs index 2c54ac385..b6bbbf370 100644 --- a/StabilityMatrix.Avalonia/Controls/BetterComboBox.cs +++ b/StabilityMatrix.Avalonia/Controls/BetterComboBox.cs @@ -2,6 +2,7 @@ using System.Linq; using System.Reactive.Linq; using System.Reactive.Subjects; +using System.Threading; using Avalonia; using Avalonia.Controls; using Avalonia.Controls.Presenters; @@ -48,7 +49,9 @@ public BetterComboBox() .Select(_ => currentInput); // Subscribe to the observable to filter the ComboBox items - subscription = inputObservable.Subscribe(OnInputReceived, _ => ResetPopupText()); + subscription = inputObservable + .ObserveOn(SynchronizationContext.Current) + .Subscribe(OnInputReceived, _ => ResetPopupText()); // Initialize the popup inputPopup = new Popup diff --git a/StabilityMatrix.Avalonia/Controls/BetterMarkdownScrollViewer.cs b/StabilityMatrix.Avalonia/Controls/BetterMarkdownScrollViewer.cs new file mode 100644 index 000000000..024bef8fa --- /dev/null +++ b/StabilityMatrix.Avalonia/Controls/BetterMarkdownScrollViewer.cs @@ -0,0 +1,16 @@ +using Markdown.Avalonia; +using StabilityMatrix.Avalonia.Styles.Markdown; + +namespace StabilityMatrix.Avalonia.Controls; + +/// +/// Fix MarkdownScrollViewer IBrush errors and not working with Avalonia 11.2.0 +/// +public class BetterMarkdownScrollViewer : MarkdownScrollViewer +{ + public BetterMarkdownScrollViewer() + { + MarkdownStyleName = "Empty"; + MarkdownStyle = new MarkdownStyleFluentAvalonia(); + } +} diff --git a/StabilityMatrix.Avalonia/Controls/Inference/SelectImageCard.axaml.cs b/StabilityMatrix.Avalonia/Controls/Inference/SelectImageCard.axaml.cs index d7890c9ed..c743b028e 100644 --- a/StabilityMatrix.Avalonia/Controls/Inference/SelectImageCard.axaml.cs +++ b/StabilityMatrix.Avalonia/Controls/Inference/SelectImageCard.axaml.cs @@ -1,4 +1,6 @@ using System; +using System.Reactive.Linq; +using System.Threading; using Avalonia.Controls; using Avalonia.Controls.Primitives; using DynamicData.Binding; @@ -24,6 +26,7 @@ protected override void OnApplyTemplate(TemplateAppliedEventArgs e) imageControl .WhenPropertyChanged(x => x.CurrentImage) + .ObserveOn(SynchronizationContext.Current) .Subscribe(propertyValue => { if (propertyValue.Value is { } image) diff --git a/StabilityMatrix.Avalonia/Controls/Painting/PaintCanvas.axaml.cs b/StabilityMatrix.Avalonia/Controls/Painting/PaintCanvas.axaml.cs index 57012561b..85cd915e9 100644 --- a/StabilityMatrix.Avalonia/Controls/Painting/PaintCanvas.axaml.cs +++ b/StabilityMatrix.Avalonia/Controls/Painting/PaintCanvas.axaml.cs @@ -3,6 +3,8 @@ using System.Collections.Immutable; using System.Diagnostics; using System.Linq; +using System.Reactive.Linq; +using System.Threading; using System.Threading.Tasks; using Avalonia; using Avalonia.Controls; @@ -108,6 +110,7 @@ protected override void OnDataContextChanged(EventArgs e) viewModelSubscription?.Dispose(); viewModelSubscription = viewModel .WhenPropertyChanged(vm => vm.CanvasSize) + .ObserveOn(SynchronizationContext.Current) .Subscribe(change => { if (MainCanvas is not null && !change.Value.IsEmpty) diff --git a/StabilityMatrix.Avalonia/DialogHelper.cs b/StabilityMatrix.Avalonia/DialogHelper.cs index 0b98ddf13..f4c79278c 100644 --- a/StabilityMatrix.Avalonia/DialogHelper.cs +++ b/StabilityMatrix.Avalonia/DialogHelper.cs @@ -81,7 +81,11 @@ public static BetterContentDialog CreateTextEntryDialog( IReadOnlyList textFields ) { - return CreateTextEntryDialog(title, new MarkdownScrollViewer { Markdown = description }, textFields); + return CreateTextEntryDialog( + title, + new BetterMarkdownScrollViewer { Markdown = description }, + textFields + ); } /// @@ -94,7 +98,7 @@ public static BetterContentDialog CreateTextEntryDialog( IReadOnlyList textFields ) { - var markdown = new MarkdownScrollViewer { Markdown = description }; + var markdown = new BetterMarkdownScrollViewer { Markdown = description }; var image = new BetterAdvancedImage((Uri?)null) { Source = imageSource, @@ -235,7 +239,7 @@ public static BetterContentDialog CreateMarkdownDialog( { Dispatcher.UIThread.VerifyAccess(); - var viewer = new MarkdownScrollViewer { Markdown = markdown }; + var viewer = new BetterMarkdownScrollViewer { Markdown = markdown }; // Apply syntax highlighting to code blocks if preset is provided if (editorPreset != default) diff --git a/StabilityMatrix.Avalonia/Services/InferenceClientManager.cs b/StabilityMatrix.Avalonia/Services/InferenceClientManager.cs index 21aa70245..352e8c983 100644 --- a/StabilityMatrix.Avalonia/Services/InferenceClientManager.cs +++ b/StabilityMatrix.Avalonia/Services/InferenceClientManager.cs @@ -3,6 +3,7 @@ using System.Diagnostics.CodeAnalysis; using System.IO; using System.Linq; +using System.Reactive.Linq; using System.Threading; using System.Threading.Tasks; using AsyncAwaitBestPractices; @@ -164,6 +165,7 @@ ICompletionProvider completionProvider ) .DeferUntilLoaded() .Bind(Models) + .ObserveOn(SynchronizationContext.Current) .Subscribe(); controlNetModelsSource @@ -176,6 +178,7 @@ ICompletionProvider completionProvider ) .DeferUntilLoaded() .Bind(ControlNetModels) + .ObserveOn(SynchronizationContext.Current) .Subscribe(); loraModelsSource @@ -185,6 +188,7 @@ ICompletionProvider completionProvider LoraModels, SortExpressionComparer.Ascending(f => f.Type).ThenByAscending(f => f.SortKey) ) + .ObserveOn(SynchronizationContext.Current) .Subscribe(); promptExpansionModelsSource @@ -197,6 +201,7 @@ ICompletionProvider completionProvider ) .DeferUntilLoaded() .Bind(PromptExpansionModels) + .ObserveOn(SynchronizationContext.Current) .Subscribe(); ultralyticsModelsSource @@ -209,6 +214,7 @@ ICompletionProvider completionProvider ) .DeferUntilLoaded() .Bind(UltralyticsModels) + .ObserveOn(SynchronizationContext.Current) .Subscribe(); samModelsSource @@ -221,6 +227,7 @@ ICompletionProvider completionProvider ) .DeferUntilLoaded() .Bind(SamModels) + .ObserveOn(SynchronizationContext.Current) .Subscribe(); unetModelsSource @@ -232,6 +239,7 @@ ICompletionProvider completionProvider ) .DeferUntilLoaded() .Bind(UnetModels) + .ObserveOn(SynchronizationContext.Current) .Subscribe(); clipModelsSource @@ -244,13 +252,24 @@ ICompletionProvider completionProvider ) .DeferUntilLoaded() .Bind(ClipModels) + .ObserveOn(SynchronizationContext.Current) .Subscribe(); vaeModelsDefaults.AddOrUpdate(HybridModelFile.Default); - vaeModelsDefaults.Connect().Or(vaeModelsSource.Connect()).Bind(VaeModels).Subscribe(); + vaeModelsDefaults + .Connect() + .Or(vaeModelsSource.Connect()) + .Bind(VaeModels) + .ObserveOn(SynchronizationContext.Current) + .Subscribe(); - samplersSource.Connect().DeferUntilLoaded().Bind(Samplers).Subscribe(); + samplersSource + .Connect() + .DeferUntilLoaded() + .Bind(Samplers) + .ObserveOn(SynchronizationContext.Current) + .Subscribe(); latentUpscalersSource .Connect() @@ -258,11 +277,22 @@ ICompletionProvider completionProvider .Or(downloadableUpscalersSource.Connect()) .Sort(SortExpressionComparer.Ascending(f => f.Type).ThenByAscending(f => f.Name)) .Bind(Upscalers) + .ObserveOn(SynchronizationContext.Current) .Subscribe(); - schedulersSource.Connect().DeferUntilLoaded().Bind(Schedulers).Subscribe(); + schedulersSource + .Connect() + .DeferUntilLoaded() + .Bind(Schedulers) + .ObserveOn(SynchronizationContext.Current) + .Subscribe(); - preprocessorsSource.Connect().DeferUntilLoaded().Bind(Preprocessors).Subscribe(); + preprocessorsSource + .Connect() + .DeferUntilLoaded() + .Bind(Preprocessors) + .ObserveOn(SynchronizationContext.Current) + .Subscribe(); settingsManager.RegisterOnLibraryDirSet(_ => { diff --git a/StabilityMatrix.Avalonia/StabilityMatrix.Avalonia.csproj b/StabilityMatrix.Avalonia/StabilityMatrix.Avalonia.csproj index 3a8b64f4d..d99372018 100644 --- a/StabilityMatrix.Avalonia/StabilityMatrix.Avalonia.csproj +++ b/StabilityMatrix.Avalonia/StabilityMatrix.Avalonia.csproj @@ -113,7 +113,7 @@ - + diff --git a/StabilityMatrix.Avalonia/Styles/Markdown/MarkdownStyleFluentAvalonia.axaml b/StabilityMatrix.Avalonia/Styles/Markdown/MarkdownStyleFluentAvalonia.axaml new file mode 100644 index 000000000..cf02c7d3e --- /dev/null +++ b/StabilityMatrix.Avalonia/Styles/Markdown/MarkdownStyleFluentAvalonia.axaml @@ -0,0 +1,210 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/StabilityMatrix.Avalonia/Styles/Markdown/MarkdownStyleFluentAvalonia.axaml.cs b/StabilityMatrix.Avalonia/Styles/Markdown/MarkdownStyleFluentAvalonia.axaml.cs new file mode 100644 index 000000000..e8ece0398 --- /dev/null +++ b/StabilityMatrix.Avalonia/Styles/Markdown/MarkdownStyleFluentAvalonia.axaml.cs @@ -0,0 +1,11 @@ +using Avalonia.Markup.Xaml; + +namespace StabilityMatrix.Avalonia.Styles.Markdown; + +public partial class MarkdownStyleFluentAvalonia : global::Avalonia.Styling.Styles +{ + public MarkdownStyleFluentAvalonia() + { + AvaloniaXamlLoader.Load(this); + } +} diff --git a/StabilityMatrix.Avalonia/ViewModels/CheckpointBrowser/CivitAiBrowserViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/CheckpointBrowser/CivitAiBrowserViewModel.cs index e08626b6b..d0126e7a7 100644 --- a/StabilityMatrix.Avalonia/ViewModels/CheckpointBrowser/CivitAiBrowserViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/CheckpointBrowser/CivitAiBrowserViewModel.cs @@ -5,6 +5,8 @@ using System.Linq; using System.Net.Http; using System.Reactive.Linq; +using System.Text.Json.Nodes; +using System.Threading; using System.Threading.Tasks; using AsyncAwaitBestPractices; using Avalonia.Controls; @@ -42,6 +44,7 @@ public sealed partial class CivitAiBrowserViewModel : TabViewModelBase, IInfinit private readonly ISettingsManager settingsManager; private readonly ILiteDbContext liteDbContext; private readonly INotificationService notificationService; + private bool dontSearch = false; private readonly SourceCache, int> modelCache = new(static ov => ov.Value.Id); @@ -80,7 +83,7 @@ public sealed partial class CivitAiBrowserViewModel : TabViewModelBase, IInfinit private string noResultsText = string.Empty; [ObservableProperty] - private string selectedBaseModelType = "All"; + private string selectedBaseModelType; [ObservableProperty] private bool showSantaHats = true; @@ -98,6 +101,11 @@ public sealed partial class CivitAiBrowserViewModel : TabViewModelBase, IInfinit [NotifyPropertyChangedFor(nameof(StatsResizeFactor))] private double resizeFactor; + private readonly SourceCache baseModelCache = new(static s => s); + + [ObservableProperty] + private IObservableCollection allBaseModels = new ObservableCollectionExtended(); + public double StatsResizeFactor => Math.Clamp(ResizeFactor, 0.75d, 1.25d); public IEnumerable AllCivitPeriods => @@ -111,9 +119,6 @@ public sealed partial class CivitAiBrowserViewModel : TabViewModelBase, IInfinit .Where(t => t == CivitModelType.All || t.ConvertTo() > 0) .OrderBy(t => t.ToString()); - public IEnumerable BaseModelOptions => - Enum.GetValues().Select(t => t.GetStringValue()); - public CivitAiBrowserViewModel( ICivitApi civitApi, IDownloadService downloadService, @@ -142,6 +147,7 @@ or nameof(HideEarlyAccessModels) .Throttle(TimeSpan.FromMilliseconds(50)) .Select(_ => (Func)FilterModelCardsPredicate) .StartWith(FilterModelCardsPredicate) + .ObserveOn(SynchronizationContext.Current) .AsObservable(); var sortPredicate = SortExpressionComparer.Ascending( @@ -163,8 +169,18 @@ or nameof(HideEarlyAccessModels) .DisposeMany() .Filter(filterPredicate) .SortAndBind(ModelCards, sortPredicate) + .ObserveOn(SynchronizationContext.Current) .Subscribe(); + baseModelCache + .Connect() + .DeferUntilLoaded() + .SortAndBind(AllBaseModels) + .ObserveOn(SynchronizationContext.Current) + .Subscribe(); + + baseModelCache.AddOrUpdate(Enum.GetValues().Select(t => t.GetStringValue())); + settingsManager.RelayPropertyFor( this, model => model.ShowNsfw, @@ -230,10 +246,38 @@ public override void OnLoaded() SelectedModelType = searchOptions?.SelectedModelType ?? CivitModelType.Checkpoint; SelectedBaseModelType = searchOptions?.SelectedBaseModelType ?? "All"; + base.OnLoaded(); + } + + protected override async Task OnInitialLoadedAsync() + { + await base.OnInitialLoadedAsync(); if (settingsManager.Settings.AutoLoadCivitModels) { - SearchModelsCommand.ExecuteAsync(false); + await SearchModelsCommand.ExecuteAsync(false); + } + + var baseModels = await GetBaseModelList(); + if (baseModels.Count == 0) + { + LoadSelectedBaseModelType(); + return; } + + dontSearch = true; + baseModelCache.AddOrUpdate(baseModels); + dontSearch = false; + + LoadSelectedBaseModelType(); + } + + private void LoadSelectedBaseModelType() + { + var searchOptions = settingsManager.Settings.ModelSearchOptions; + dontSearch = true; + SelectedBaseModelType = "All"; + SelectedBaseModelType = searchOptions is null ? "All" : searchOptions.SelectedBaseModelType; + dontSearch = false; } /// @@ -340,7 +384,22 @@ private async Task CivitModelQuery(CivitModelsRequest request, bool isInfiniteSc } ); - UpdateModelCards(models, isInfiniteScroll); + if (cacheNew) + { + var doesBaseModelTypeMatch = + SelectedBaseModelType == "All" + ? string.IsNullOrWhiteSpace(request.BaseModel) + : SelectedBaseModelType == request.BaseModel; + var doesModelTypeMatch = + SelectedModelType == CivitModelType.All + ? request.Types == null || request.Types.Length == 0 + : SelectedModelType == request.Types?.FirstOrDefault(); + + if (doesBaseModelTypeMatch && doesModelTypeMatch) + { + UpdateModelCards(models, isInfiniteScroll); + } + } NextPageCursor = modelsResponse?.Metadata?.NextCursor; } @@ -615,6 +674,9 @@ partial void OnSelectedModelTypeChanged(CivitModelType value) partial void OnSelectedBaseModelTypeChanged(string value) { + if (dontSearch) + return; + TrySearchAgain().SafeFireAndForget(); settingsManager.Transaction( s => @@ -632,6 +694,7 @@ private async Task TrySearchAgain(bool shouldUpdatePageNumber = true) { if (!HasSearched) return; + modelCache.Clear(); if (shouldUpdatePageNumber) @@ -649,5 +712,35 @@ private void UpdateResultsText() NoResultsText = "No results found"; } + [Localizable(false)] + private async Task> GetBaseModelList() + { + try + { + var baseModelsResponse = await civitApi.GetBaseModelList(); + var jsonContent = await baseModelsResponse.Content.ReadAsStringAsync(); + var baseModels = JsonNode.Parse(jsonContent); + + var jArray = + baseModels?["error"]?["issues"]?[0]?["unionErrors"]?[0]?["issues"]?[0]?["options"] + as JsonArray; + var civitBaseModels = jArray?.GetValues().ToList() ?? []; + + civitBaseModels.Insert(0, CivitBaseModelType.All.ToString()); + + var filteredResults = civitBaseModels + .Where(s => s.Equals("odor", StringComparison.OrdinalIgnoreCase) == false) + .OrderBy(s => s) + .ToList(); + + return filteredResults; + } + catch (Exception e) + { + Logger.Error(e, "Failed to get base model list"); + return []; + } + } + public override string Header => Resources.Label_CivitAi; } diff --git a/StabilityMatrix.Avalonia/ViewModels/CheckpointBrowser/HuggingFacePageViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/CheckpointBrowser/HuggingFacePageViewModel.cs index 3ab3c6b44..58c0e86eb 100644 --- a/StabilityMatrix.Avalonia/ViewModels/CheckpointBrowser/HuggingFacePageViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/CheckpointBrowser/HuggingFacePageViewModel.cs @@ -6,6 +6,7 @@ using System.Reactive.Linq; using System.Text.Json; using System.Text.Json.Serialization; +using System.Threading; using System.Threading.Tasks; using Avalonia.Controls; using Avalonia.Controls.Notifications; @@ -86,6 +87,7 @@ INotificationService notificationService .Bind(Categories) .WhenAnyPropertyChanged() .Throttle(TimeSpan.FromMilliseconds(50)) + .ObserveOn(SynchronizationContext.Current) .Subscribe(_ => NumSelected = Categories.Sum(c => c.NumSelected)); progressTimer.Tick += (_, _) => diff --git a/StabilityMatrix.Avalonia/ViewModels/CheckpointsPageViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/CheckpointsPageViewModel.cs index f9ce925a7..1083f9a5c 100644 --- a/StabilityMatrix.Avalonia/ViewModels/CheckpointsPageViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/CheckpointsPageViewModel.cs @@ -6,6 +6,7 @@ using System.IO; using System.Linq; using System.Reactive.Linq; +using System.Threading; using System.Threading.Tasks; using AsyncAwaitBestPractices; using Avalonia.Controls; @@ -196,6 +197,7 @@ protected override void OnInitialLoaded() ) ) ) + .ObserveOn(SynchronizationContext.Current) .AsObservable(); var filterPredicate = Observable @@ -209,6 +211,7 @@ or nameof(SelectedBaseModels) ) .Throttle(TimeSpan.FromMilliseconds(50)) .Select(_ => (Func)FilterModels) + .ObserveOn(SynchronizationContext.Current) .AsObservable(); var comparerObservable = Observable @@ -282,6 +285,7 @@ or nameof(SortConnectedModelsFirst) return comparer; }) + .ObserveOn(SynchronizationContext.Current) .AsObservable(); ModelsCache @@ -304,6 +308,7 @@ or nameof(SortConnectedModelsFirst) .SortAndBind(Models, comparerObservable) .WhenPropertyChanged(p => p.IsSelected) .Throttle(TimeSpan.FromMilliseconds(50)) + .ObserveOn(SynchronizationContext.Current) .Subscribe(_ => { NumItemsSelected = Models.Count(o => o.IsSelected); @@ -315,6 +320,7 @@ or nameof(SortConnectedModelsFirst) .Throttle(TimeSpan.FromMilliseconds(50)) .Select(_ => (Func)FilterCategories) .StartWith(FilterCategories) + .ObserveOn(SynchronizationContext.Current) .AsObservable(); categoriesCache @@ -327,6 +333,7 @@ or nameof(SortConnectedModelsFirst) .Descending(x => x.Name == "All Models") .ThenByAscending(x => x.Name) ) + .ObserveOn(SynchronizationContext.Current) .Subscribe(); settingsManager.RelayPropertyFor( diff --git a/StabilityMatrix.Avalonia/ViewModels/Dialogs/NewOneClickInstallViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Dialogs/NewOneClickInstallViewModel.cs index f390b3fd7..f8da3be6a 100644 --- a/StabilityMatrix.Avalonia/ViewModels/Dialogs/NewOneClickInstallViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/Dialogs/NewOneClickInstallViewModel.cs @@ -3,6 +3,7 @@ using System.IO; using System.Linq; using System.Reactive.Linq; +using System.Threading; using System.Threading.Tasks; using AsyncAwaitBestPractices; using Avalonia.Threading; @@ -70,6 +71,7 @@ INotificationService notificationService var incompatiblePredicate = this.WhenPropertyChanged(vm => vm.ShowIncompatiblePackages) .Select(_ => new Func(p => p.IsCompatible || ShowIncompatiblePackages)) + .ObserveOn(SynchronizationContext.Current) .AsObservable(); AllPackagesCache @@ -83,6 +85,7 @@ INotificationService notificationService .Ascending(p => p.InstallerSortOrder) .ThenByAscending(p => p.DisplayName) ) + .ObserveOn(SynchronizationContext.Current) .Subscribe(); AllPackagesCache.AddOrUpdate(packageFactory.GetAllAvailablePackages()); diff --git a/StabilityMatrix.Avalonia/ViewModels/Dialogs/RecommendedModelsViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Dialogs/RecommendedModelsViewModel.cs index b91336c86..97ada3ec4 100644 --- a/StabilityMatrix.Avalonia/ViewModels/Dialogs/RecommendedModelsViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/Dialogs/RecommendedModelsViewModel.cs @@ -1,6 +1,8 @@ using System; using System.IO; using System.Linq; +using System.Reactive.Linq; +using System.Threading; using System.Threading.Tasks; using Avalonia.Controls; using CommunityToolkit.Mvvm.ComponentModel; @@ -73,6 +75,7 @@ IModelImportService modelImportService .DeferUntilLoaded() .Filter(f => f.ModelVersion.BaseModel == "SD 1.5") .Bind(Sd15Models) + .ObserveOn(SynchronizationContext.Current) .Subscribe(); CivitModels @@ -80,6 +83,7 @@ IModelImportService modelImportService .DeferUntilLoaded() .Filter(f => f.ModelVersion.BaseModel == "SDXL 1.0" || f.ModelVersion.BaseModel == "Pony") .Bind(SdxlModels) + .ObserveOn(SynchronizationContext.Current) .Subscribe(); } diff --git a/StabilityMatrix.Avalonia/ViewModels/HuggingFacePage/CategoryViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/HuggingFacePage/CategoryViewModel.cs index 755153f70..7a46dc116 100644 --- a/StabilityMatrix.Avalonia/ViewModels/HuggingFacePage/CategoryViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/HuggingFacePage/CategoryViewModel.cs @@ -1,6 +1,8 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Reactive.Linq; +using System.Threading; using CommunityToolkit.Mvvm.ComponentModel; using DynamicData; using DynamicData.Binding; @@ -35,6 +37,7 @@ public CategoryViewModel(IEnumerable items, string modelsDir) .Transform(i => new HuggingfaceItemViewModel { Item = i, ModelsDir = modelsDir }) .Bind(Items) .WhenPropertyChanged(p => p.IsSelected) + .ObserveOn(SynchronizationContext.Current) .Subscribe(_ => NumSelected = Items.Count(i => i.IsSelected)); ItemsCache.EditDiff(items, (a, b) => a.RepositoryPath == b.RepositoryPath); diff --git a/StabilityMatrix.Avalonia/ViewModels/Inference/ControlNetCardViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Inference/ControlNetCardViewModel.cs index ae75414fb..41eaa811c 100644 --- a/StabilityMatrix.Avalonia/ViewModels/Inference/ControlNetCardViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/Inference/ControlNetCardViewModel.cs @@ -1,5 +1,7 @@ using System; using System.ComponentModel.DataAnnotations; +using System.Reactive.Linq; +using System.Threading; using System.Threading.Tasks; using Avalonia.Threading; using CommunityToolkit.Mvvm.ComponentModel; @@ -75,6 +77,7 @@ ServiceManager vmFactory // Update our width and height when the image changes SelectImageCardViewModel .WhenPropertyChanged(card => card.CurrentBitmapSize) + .ObserveOn(SynchronizationContext.Current) .Subscribe(propertyValue => { if (!propertyValue.Value.IsEmpty) diff --git a/StabilityMatrix.Avalonia/ViewModels/Inference/ImageFolderCardViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Inference/ImageFolderCardViewModel.cs index d92bed140..84dc2fc51 100644 --- a/StabilityMatrix.Avalonia/ViewModels/Inference/ImageFolderCardViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/Inference/ImageFolderCardViewModel.cs @@ -1,6 +1,7 @@ using System; using System.IO; using System.Reactive.Linq; +using System.Threading; using System.Threading.Tasks; using AsyncAwaitBestPractices; using AsyncImageLoader; @@ -76,6 +77,7 @@ ServiceManager vmFactory var searchPredicate = this.WhenPropertyChanged(vm => vm.SearchQuery) .Throttle(TimeSpan.FromMilliseconds(50))! .Select(property => searcher.GetPredicate(property.Value)) + .ObserveOn(SynchronizationContext.Current) .AsObservable(); imageIndexService @@ -84,6 +86,7 @@ ServiceManager vmFactory .Filter(searchPredicate) .SortBy(file => file.LastModifiedAt, SortDirection.Descending) .Bind(LocalImages) + .ObserveOn(SynchronizationContext.Current) .Subscribe(); AddDisposable( @@ -191,6 +194,7 @@ private async Task OnImageClick(LocalImageFile item) vm, nameof(ImageViewerViewModel.NavigationRequested) ) + .ObserveOn(SynchronizationContext.Current) .Subscribe(ctx => { Dispatcher diff --git a/StabilityMatrix.Avalonia/ViewModels/Inference/InferenceTextToImageViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Inference/InferenceTextToImageViewModel.cs index daf355508..dc49664de 100644 --- a/StabilityMatrix.Avalonia/ViewModels/Inference/InferenceTextToImageViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/Inference/InferenceTextToImageViewModel.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Reactive.Linq; using System.Text.Json.Nodes; using System.Text.Json.Serialization; using System.Threading; @@ -114,6 +115,7 @@ RunningPackageService runningPackageService AddDisposable( ModelCardViewModel .WhenPropertyChanged(x => x.IsRefinerSelectionEnabled) + .ObserveOn(SynchronizationContext.Current) .Subscribe(e => { SamplerCardViewModel.IsRefinerStepsEnabled = diff --git a/StabilityMatrix.Avalonia/ViewModels/InstalledWorkflowsViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/InstalledWorkflowsViewModel.cs index c821d305a..0cd1a8564 100644 --- a/StabilityMatrix.Avalonia/ViewModels/InstalledWorkflowsViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/InstalledWorkflowsViewModel.cs @@ -2,7 +2,9 @@ using System.IO; using System.Linq; using System.Text.Json; +using System.Threading; using System.Threading.Tasks; +using System.Reactive.Linq; using AsyncAwaitBestPractices; using Avalonia.Controls; using Avalonia.Platform.Storage; @@ -45,7 +47,7 @@ protected override async Task OnInitialLoadedAsync() { await base.OnInitialLoadedAsync(); - workflowsCache.Connect().DeferUntilLoaded().Bind(DisplayedWorkflows).Subscribe(); + workflowsCache.Connect().DeferUntilLoaded().Bind(DisplayedWorkflows).ObserveOn(SynchronizationContext.Current).Subscribe(); if (Design.IsDesignMode) return; diff --git a/StabilityMatrix.Avalonia/ViewModels/OpenArtBrowserViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/OpenArtBrowserViewModel.cs index cc13e869a..0897932a6 100644 --- a/StabilityMatrix.Avalonia/ViewModels/OpenArtBrowserViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/OpenArtBrowserViewModel.cs @@ -2,6 +2,8 @@ using System.Collections.Generic; using System.ComponentModel; using System.Linq; +using System.Reactive.Linq; +using System.Threading; using System.Threading.Tasks; using AsyncAwaitBestPractices; using Avalonia.Controls.Notifications; @@ -86,7 +88,12 @@ IPackageFactory packageFactory protected override void OnInitialLoaded() { - searchResultsCache.Connect().DeferUntilLoaded().Bind(SearchResults).Subscribe(); + searchResultsCache + .Connect() + .DeferUntilLoaded() + .Bind(SearchResults) + .ObserveOn(SynchronizationContext.Current) + .Subscribe(); SelectedSortMode = AllSortModes.First(); DoSearch().SafeFireAndForget(); } diff --git a/StabilityMatrix.Avalonia/ViewModels/OutputsPageViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/OutputsPageViewModel.cs index c35b94984..f53c8844f 100644 --- a/StabilityMatrix.Avalonia/ViewModels/OutputsPageViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/OutputsPageViewModel.cs @@ -134,6 +134,7 @@ ServiceManager vmFactory var searchPredicate = this.WhenPropertyChanged(vm => vm.SearchQuery) .Throttle(TimeSpan.FromMilliseconds(100))! .Select(property => searcher.GetPredicate(property.Value)) + .ObserveOn(SynchronizationContext.Current) .AsObservable(); OutputsCache @@ -149,12 +150,18 @@ ServiceManager vmFactory .Bind(Outputs) .WhenPropertyChanged(p => p.IsSelected) .Throttle(TimeSpan.FromMilliseconds(50)) + .ObserveOn(SynchronizationContext.Current) .Subscribe(_ => { NumItemsSelected = Outputs.Count(o => o.IsSelected); }); - categoriesCache.Connect().DeferUntilLoaded().Bind(Categories).Subscribe(); + categoriesCache + .Connect() + .DeferUntilLoaded() + .Bind(Categories) + .ObserveOn(SynchronizationContext.Current) + .Subscribe(); settingsManager.RelayPropertyFor( this, @@ -268,6 +275,7 @@ public async Task ShowImageDialog(OutputImageViewModel item) vm, nameof(ImageViewerViewModel.NavigationRequested) ) + .ObserveOn(SynchronizationContext.Current) .Subscribe(ctx => { Dispatcher diff --git a/StabilityMatrix.Avalonia/ViewModels/PackageManager/MainPackageManagerViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/PackageManager/MainPackageManagerViewModel.cs index ca4527e30..65dd3b763 100644 --- a/StabilityMatrix.Avalonia/ViewModels/PackageManager/MainPackageManagerViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/PackageManager/MainPackageManagerViewModel.cs @@ -3,6 +3,8 @@ using System.Collections.Immutable; using System.IO; using System.Linq; +using System.Reactive.Linq; +using System.Threading; using System.Threading.Tasks; using AsyncAwaitBestPractices; using Avalonia.Controls; @@ -101,6 +103,7 @@ RunningPackageService runningPackageService }) ) .Bind(PackageCards) + .ObserveOn(SynchronizationContext.Current) .Subscribe(); timer = new DispatcherTimer { Interval = TimeSpan.FromMinutes(60), IsEnabled = true }; diff --git a/StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageExtensionBrowserViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageExtensionBrowserViewModel.cs index b4951cdb8..3a6db87bc 100644 --- a/StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageExtensionBrowserViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageExtensionBrowserViewModel.cs @@ -102,6 +102,7 @@ ServiceManager vmFactory .AutoRefresh(item => item.IsSelected) .Filter(item => item.IsSelected) .Bind(SelectedAvailableItems) + .ObserveOn(SynchronizationContext.Current) .Subscribe(); var installedItemsChangeSet = installedExtensionsSource @@ -114,6 +115,7 @@ ServiceManager vmFactory .AutoRefresh(item => item.IsSelected) .Filter(item => item.IsSelected) .Bind(SelectedInstalledItems) + .ObserveOn(SynchronizationContext.Current) .Subscribe(); cleanUp = new CompositeDisposable( diff --git a/StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageInstallBrowserViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageInstallBrowserViewModel.cs index 841c7408f..e3bfeaa8a 100644 --- a/StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageInstallBrowserViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/PackageManager/PackageInstallBrowserViewModel.cs @@ -1,5 +1,6 @@ using System; using System.Reactive.Linq; +using System.Threading; using Avalonia.Threading; using CommunityToolkit.Mvvm.ComponentModel; using DynamicData; @@ -71,6 +72,7 @@ IAnalyticsHelper analyticsHelper var incompatiblePredicate = this.WhenPropertyChanged(vm => vm.ShowIncompatiblePackages) .Select(_ => new Func(p => p.IsCompatible || ShowIncompatiblePackages)) + .ObserveOn(SynchronizationContext.Current) .AsObservable(); var searchPredicate = this.WhenPropertyChanged(vm => vm.SearchFilter) @@ -80,6 +82,7 @@ IAnalyticsHelper analyticsHelper p => p.DisplayName.Contains(SearchFilter, StringComparison.OrdinalIgnoreCase) ) ) + .ObserveOn(SynchronizationContext.Current) .AsObservable(); packageSource @@ -94,6 +97,7 @@ IAnalyticsHelper analyticsHelper .ThenByAscending(p => p.DisplayName) ) .Bind(InferencePackages) + .ObserveOn(SynchronizationContext.Current) .Subscribe(); packageSource @@ -108,6 +112,7 @@ IAnalyticsHelper analyticsHelper .ThenByAscending(p => p.DisplayName) ) .Bind(TrainingPackages) + .ObserveOn(SynchronizationContext.Current) .Subscribe(); packageSource.EditDiff( diff --git a/StabilityMatrix.Avalonia/ViewModels/Settings/InferenceSettingsViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Settings/InferenceSettingsViewModel.cs index 55e8b488c..dc5cc078b 100644 --- a/StabilityMatrix.Avalonia/ViewModels/Settings/InferenceSettingsViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/Settings/InferenceSettingsViewModel.cs @@ -4,6 +4,7 @@ using System.ComponentModel.DataAnnotations; using System.Linq; using System.Reactive.Linq; +using System.Threading; using System.Threading.Tasks; using Avalonia.Controls.Notifications; using Avalonia.Platform.Storage; @@ -122,6 +123,7 @@ ISettingsManager settingsManager this.WhenPropertyChanged(vm => vm.OutputImageFileNameFormat) .Throttle(TimeSpan.FromMilliseconds(50)) + .ObserveOn(SynchronizationContext.Current) .Subscribe(formatProperty => { var provider = FileNameFormatProvider.GetSample(); diff --git a/StabilityMatrix.Avalonia/Views/CivitAiBrowserPage.axaml b/StabilityMatrix.Avalonia/Views/CivitAiBrowserPage.axaml index 2e6f01856..7d7cda10d 100644 --- a/StabilityMatrix.Avalonia/Views/CivitAiBrowserPage.axaml +++ b/StabilityMatrix.Avalonia/Views/CivitAiBrowserPage.axaml @@ -492,8 +492,14 @@ Grid.Column="3" MinWidth="100" Margin="4,0,4,8" - ItemsSource="{Binding BaseModelOptions}" - SelectedItem="{Binding SelectedBaseModelType}" /> + ItemsSource="{Binding AllBaseModels}" + SelectedItem="{Binding SelectedBaseModelType}"> + + + + + + - - + + + Watermark="{x:Static lang:Resources.Label_Email}" /> - - - + + - + Severity="Error" /> + - + NavigateUri="{x:Static sm:Assets.LykosForgotPasswordUrl}" /> + + Content="Sign in with Google" /> - + - - + + + Watermark="{x:Static lang:Resources.Label_Email}" /> + Watermark="{x:Static lang:Resources.Label_Username}" /> - + Watermark="{x:Static lang:Resources.Label_Password}" /> - - - + + - - + + - + Markdown="{Binding SignupFooterMarkdown}" + TextElement.Foreground="{DynamicResource TextFillColorTertiaryBrush}"> + - - + + - + diff --git a/StabilityMatrix.Avalonia/Views/Dialogs/UpdateDialog.axaml b/StabilityMatrix.Avalonia/Views/Dialogs/UpdateDialog.axaml index c463e833c..88aa3a8be 100644 --- a/StabilityMatrix.Avalonia/Views/Dialogs/UpdateDialog.axaml +++ b/StabilityMatrix.Avalonia/Views/Dialogs/UpdateDialog.axaml @@ -1,107 +1,120 @@ - + - + - - - - + + + + - + - + FontSize="15" + IconVariant="Filled" + Symbol="ArrowRight" /> + - - - - - - - - - - + + + + + + + + + + - - - - -