diff --git a/CHANGELOG.md b/CHANGELOG.md index 1e60a65c..58f8a152 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning 2.0](https://semver.org/spec/v2 #### Model Browser - Right clicking anywhere on the model card will open the same menu as the three-dots button - New model downloads will save trigger words in metadata, if available +- Model author username and avatar display, with clickable link to their profile #### Checkpoints Page - Added "Copy Trigger Words" option to the three-dots menu on the Checkpoints page (when data is available) - Added trigger words on checkpoint card and tooltip @@ -20,6 +21,8 @@ and this project adheres to [Semantic Versioning 2.0](https://semver.org/spec/v2 - Animated zoom effect on hovering over model images #### Checkpoints Page - Rearranged top row layout to use CommandBar +### Fixed +- Improved startup time and window load time after exiting dialogs ## v2.7.0-dev.2 ### Added diff --git a/StabilityMatrix.Avalonia/DesignData/DesignData.cs b/StabilityMatrix.Avalonia/DesignData/DesignData.cs index e1b3bb9f..09f3a993 100644 --- a/StabilityMatrix.Avalonia/DesignData/DesignData.cs +++ b/StabilityMatrix.Avalonia/DesignData/DesignData.cs @@ -310,7 +310,12 @@ public static class DesignData Stats = new CivitModelStats { Rating = 3.5, RatingCount = 24 }, ModelVersions = [ new() { Name = "v1.2.2-Inpainting" } - ] + ], + Creator = new CivitCreator + { + Image = "https://gravatar.com/avatar/fe74084ae8a081dc2283f5bde4736756ad?f=y&d=retro", + Username = "creator-1" + } }; }), dialogFactory.Get(vm => @@ -334,7 +339,12 @@ public static class DesignData } } } - ] + ], + Creator = new CivitCreator + { + Image = "https://gravatar.com/avatar/205e460b479e2e5b48aec07710c08d50?f=y&d=retro", + Username = "creator-2" + } }; }) }; diff --git a/StabilityMatrix.Avalonia/Helpers/IOCommands.cs b/StabilityMatrix.Avalonia/Helpers/IOCommands.cs new file mode 100644 index 00000000..d60c7725 --- /dev/null +++ b/StabilityMatrix.Avalonia/Helpers/IOCommands.cs @@ -0,0 +1,19 @@ +using CommunityToolkit.Mvvm.Input; +using StabilityMatrix.Core.Processes; + +namespace StabilityMatrix.Avalonia.Helpers; + +public static class IOCommands +{ + public static RelayCommand OpenUrlCommand { get; } = + new( + url => + { + if (string.IsNullOrWhiteSpace(url)) + return; + + ProcessRunner.OpenUrl(url); + }, + url => !string.IsNullOrWhiteSpace(url) + ); +} diff --git a/StabilityMatrix.Avalonia/ViewModels/Base/ViewModelBase.cs b/StabilityMatrix.Avalonia/ViewModels/Base/ViewModelBase.cs index 0d9899cc..35a620ee 100644 --- a/StabilityMatrix.Avalonia/ViewModels/Base/ViewModelBase.cs +++ b/StabilityMatrix.Avalonia/ViewModels/Base/ViewModelBase.cs @@ -1,6 +1,7 @@ using System; using System.Threading.Tasks; using AsyncAwaitBestPractices; +using Avalonia.Threading; using CommunityToolkit.Mvvm.ComponentModel; using JetBrains.Annotations; using StabilityMatrix.Avalonia.Models; @@ -39,7 +40,10 @@ public class ViewModelBase : ObservableValidator, IRemovableListItem if (!ViewModelState.HasFlag(ViewModelState.InitialLoaded)) { ViewModelState |= ViewModelState.InitialLoaded; + OnInitialLoaded(); + + Dispatcher.UIThread.InvokeAsync(OnInitialLoadedAsync).SafeFireAndForget(); } } @@ -54,10 +58,13 @@ public class ViewModelBase : ObservableValidator, IRemovableListItem /// Runs on the UI thread via Dispatcher.UIThread.InvokeAsync. /// The view loading will not wait for this to complete. /// - public virtual Task OnLoadedAsync() - { - return Task.CompletedTask; - } + public virtual Task OnLoadedAsync() => Task.CompletedTask; + + /// + /// Called the first time the view's LoadedEvent is fired. + /// Sets the flag. + /// + protected virtual Task OnInitialLoadedAsync() => Task.CompletedTask; /// /// Called when the view's UnloadedEvent is fired. @@ -69,8 +76,5 @@ public class ViewModelBase : ObservableValidator, IRemovableListItem /// Runs on the UI thread via Dispatcher.UIThread.InvokeAsync. /// The view loading will not wait for this to complete. /// - public virtual Task OnUnloadedAsync() - { - return Task.CompletedTask; - } + public virtual Task OnUnloadedAsync() => Task.CompletedTask; } diff --git a/StabilityMatrix.Avalonia/ViewModels/CheckpointBrowserViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/CheckpointBrowserViewModel.cs index c3b97ec2..9c1f88c3 100644 --- a/StabilityMatrix.Avalonia/ViewModels/CheckpointBrowserViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/CheckpointBrowserViewModel.cs @@ -470,12 +470,14 @@ public partial class CheckpointBrowserViewModel : PageViewModelBase } // See if query is cached - var cachedQuery = await liteDbContext.CivitModelQueryCache - .IncludeAll() - .FindByIdAsync(ObjectHash.GetMd5Guid(modelRequest)); + var cachedQueryResult = await notificationService.TryAsync( + liteDbContext.CivitModelQueryCache + .IncludeAll() + .FindByIdAsync(ObjectHash.GetMd5Guid(modelRequest)) + ); // If cached, update model cards - if (cachedQuery is not null) + if (cachedQueryResult.Result is { } cachedQuery) { var elapsed = timer.Elapsed; Logger.Debug( diff --git a/StabilityMatrix.Avalonia/ViewModels/MainWindowViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/MainWindowViewModel.cs index c8c8befe..842df99e 100644 --- a/StabilityMatrix.Avalonia/ViewModels/MainWindowViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/MainWindowViewModel.cs @@ -78,7 +78,7 @@ public partial class MainWindowViewModel : ViewModelBase SelectedCategory ??= Pages.FirstOrDefault(); } - public override async Task OnLoadedAsync() + protected override async Task OnInitialLoadedAsync() { await base.OnLoadedAsync(); @@ -102,16 +102,20 @@ public partial class MainWindowViewModel : ViewModelBase // Index checkpoints if we dont have Task.Run(() => settingsManager.IndexCheckpoints()).SafeFireAndForget(); - if (!App.IsHeadlessMode) + // Disable preload for now, might be causing https://github.com/LykosAI/StabilityMatrix/issues/249 + /*if (!App.IsHeadlessMode) { PreloadPages(); - } + }*/ Program.StartupTimer.Stop(); var startupTime = CodeTimer.FormatTime(Program.StartupTimer.Elapsed); Logger.Info($"App started ({startupTime})"); - if (Program.Args.DebugOneClickInstall || !settingsManager.Settings.InstalledPackages.Any()) + if ( + Program.Args.DebugOneClickInstall + || settingsManager.Settings.InstalledPackages.Count == 0 + ) { var viewModel = dialogFactory.Get(); var dialog = new BetterContentDialog diff --git a/StabilityMatrix.Avalonia/Views/CheckpointBrowserPage.axaml b/StabilityMatrix.Avalonia/Views/CheckpointBrowserPage.axaml index 7bf3dde6..2d883b55 100644 --- a/StabilityMatrix.Avalonia/Views/CheckpointBrowserPage.axaml +++ b/StabilityMatrix.Avalonia/Views/CheckpointBrowserPage.axaml @@ -14,6 +14,7 @@ xmlns:vm="clr-namespace:StabilityMatrix.Avalonia.ViewModels.CheckpointManager" xmlns:converters="clr-namespace:StabilityMatrix.Avalonia.Converters" xmlns:asyncImageLoader="clr-namespace:AsyncImageLoader;assembly=AsyncImageLoader.Avalonia" + xmlns:helpers="clr-namespace:StabilityMatrix.Avalonia.Helpers" d:DataContext="{x:Static designData:DesignData.CheckpointBrowserViewModel}" d:DesignHeight="700" d:DesignWidth="800" @@ -137,7 +138,49 @@ - + + + + + + + + + Username is null ? null : $"https://civitai.com/user/{Username}"; }