Browse Source

Merge pull request #149 from ionite34/model-browser-features

pull/55/head
Ionite 1 year ago committed by GitHub
parent
commit
ad9ce6797d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 10
      StabilityMatrix/CheckpointBrowserPage.xaml
  2. 5
      StabilityMatrix/CheckpointBrowserPage.xaml.cs
  3. 52
      StabilityMatrix/DesignData/MockCheckpointBrowserViewModel.cs
  4. 34
      StabilityMatrix/Helper/Expressions.cs
  5. 55
      StabilityMatrix/Helper/ISettingsManager.cs
  6. 203
      StabilityMatrix/Helper/SettingsManager.cs
  7. 14
      StabilityMatrix/MainWindow.xaml.cs
  8. 27
      StabilityMatrix/Models/Settings/Settings.cs
  9. 35
      StabilityMatrix/Models/Settings/SettingsTransaction.cs
  10. 2
      StabilityMatrix/Services/NotificationBarService.cs
  11. 18
      StabilityMatrix/ViewModels/CheckpointBrowserCardViewModel.cs
  12. 39
      StabilityMatrix/ViewModels/CheckpointBrowserViewModel.cs
  13. 5
      StabilityMatrix/ViewModels/CheckpointManagerViewModel.cs
  14. 12
      StabilityMatrix/ViewModels/DataDirectoryMigrationViewModel.cs
  15. 5
      StabilityMatrix/ViewModels/InstallerViewModel.cs
  16. 30
      StabilityMatrix/ViewModels/LaunchViewModel.cs
  17. 5
      StabilityMatrix/ViewModels/OneClickInstallViewModel.cs
  18. 6
      StabilityMatrix/ViewModels/PackageManagerViewModel.cs
  19. 15
      StabilityMatrix/ViewModels/SettingsViewModel.cs

10
StabilityMatrix/CheckpointBrowserPage.xaml

@ -1,20 +1,19 @@
<Page
Foreground="{DynamicResource TextFillColorPrimaryBrush}"
Loaded="CheckpointBrowserPage_OnLoaded"
d:DataContext="{d:DesignInstance designData:MockCheckpointBrowserViewModel,
IsDesignTimeCreatable=True}"
d:DesignHeight="600"
d:DesignWidth="650"
d:DesignHeight="650"
d:DesignWidth="750"
mc:Ignorable="d"
ui:Design.Background="{DynamicResource ApplicationBackgroundBrush}"
ui:Design.Foreground="{DynamicResource TextFillColorPrimaryBrush}"
x:Class="StabilityMatrix.CheckpointBrowserPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:api="clr-namespace:StabilityMatrix.Models.Api"
xmlns:converters="clr-namespace:StabilityMatrix.Converters"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:designData="clr-namespace:StabilityMatrix.DesignData"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:models="clr-namespace:StabilityMatrix.Models"
xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml"
xmlns:viewModels="clr-namespace:StabilityMatrix.ViewModels"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
@ -25,7 +24,6 @@
<BooleanToVisibilityConverter />
</converters:ValueConverterGroup>
<converters:UriToBitmapConverter x:Key="UriToBitmapConverter" />
<BooleanToVisibilityConverter x:Key="BoolToVisibilityConverter" />
<DataTemplate DataType="{x:Type viewModels:CheckpointBrowserCardViewModel}" x:Key="CivitModelTemplate">
@ -45,7 +43,7 @@
FontSize="11"
Foreground="{DynamicResource TextFillColorTertiaryBrush}"
Margin="0,2,0,0"
Text="{Binding CivitModel.ModelVersions[0].Name}"
Text="{Binding CivitModel.ModelVersions[0].Name, FallbackValue=''}"
VerticalAlignment="Center" />
<Grid>
<Image

5
StabilityMatrix/CheckpointBrowserPage.xaml.cs

@ -33,4 +33,9 @@ public partial class CheckpointBrowserPage : Page
{
e.Handled = true;
}
private void CheckpointBrowserPage_OnLoaded(object sender, RoutedEventArgs e)
{
(DataContext as CheckpointBrowserViewModel)?.OnLoaded();
}
}

52
StabilityMatrix/DesignData/MockCheckpointBrowserViewModel.cs

@ -1,6 +1,8 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Windows.Data;
using System.Windows.Media.Imaging;
using StabilityMatrix.Models.Api;
using StabilityMatrix.ViewModels;
@ -14,30 +16,56 @@ public class MockCheckpointBrowserViewModel : CheckpointBrowserViewModel
{
ModelCards = new ObservableCollection<CheckpointBrowserCardViewModel>
{
new(null!, null!, null!, null!)
new(null!, null!, null!, null!,
fixedImage: new BitmapImage(new Uri("https://image.civitai.com/xG1nkqKTMzGDvpLrqFT7WA/01bb1e4b-f88b-441a-b2bf-c1ec0bd91727/width=450/00015-1007989405.jpeg")))
{
CivitModel = new()
CivitModel = new CivitModel
{
Name = "bb95 Furry Mix",
ModelVersions = new()
Name = "Ghibli Background",
Type = CivitModelType.Checkpoint,
ModelVersions = new List<CivitModelVersion>
{
new CivitModelVersion
new()
{
Name = "v7.0",
Images = new()
Name = "v5.0",
Files = new List<CivitFile>
{
new CivitImage
new()
{
Url =
"https://image.civitai.com/xG1nkqKTMzGDvpLrqFT7WA/1547f350-461a-4cd0-a753-0544aa81e4fc/width=450/00000-4137473915.jpeg"
Name = "File",
SizeKb = 844110,
}
}
}
}
},
},
new(null!, null!, null!, null!,
fixedImage: new BitmapImage(new Uri("https://image.civitai.com/xG1nkqKTMzGDvpLrqFT7WA/fcb56b61-2cd6-40f4-a75d-e9448c0822d6/width=1152/29933-2136606019-masterpiece.jpeg")))
{
CivitModel = new CivitModel
{
Name = "Indigo Furry mix",
Type = CivitModelType.Checkpoint,
Nsfw = false,
ModelVersions = new List<CivitModelVersion>
{
new()
{
Name = "v45_hybrid",
Files = new List<CivitFile>
{
new()
{
Name = "Pruned Model fp16",
SizeKb = 1990000,
}
}
}
}
},
CardImage = new BitmapImage(new Uri(
"https://image.civitai.com/xG1nkqKTMzGDvpLrqFT7WA/1547f350-461a-4cd0-a753-0544aa81e4fc/width=450/00000-4137473915.jpeg"))
}
};
ModelCardsView = CollectionViewSource.GetDefaultView(ModelCards);
}
}

34
StabilityMatrix/Helper/Expressions.cs

@ -0,0 +1,34 @@
using System;
using System.Linq.Expressions;
using System.Reflection;
namespace StabilityMatrix.Helper;
public static class Expressions
{
public static (string propertyName, Expression<Action<T, TValue>> assigner)
GetAssigner<T, TValue>(Expression<Func<T, TValue>> propertyAccessor)
{
if (propertyAccessor.Body is not MemberExpression memberExpression)
{
throw new ArgumentException(
$"Expression must be a member expression, not {propertyAccessor.Body.NodeType}");
}
var propertyInfo = memberExpression.Member as PropertyInfo;
if (propertyInfo == null)
{
throw new ArgumentException(
$"Expression member must be a property, not {memberExpression.Member.MemberType}");
}
var propertyName = propertyInfo.Name;
var typeParam = Expression.Parameter(typeof(T));
var valueParam = Expression.Parameter(typeof(TValue));
var expr = Expression.Lambda<Action<T, TValue>>(
Expression.Assign(
Expression.MakeMemberAccess(typeParam, propertyInfo),
valueParam), typeParam, valueParam);
return (propertyName, expr);
}
}

55
StabilityMatrix/Helper/ISettingsManager.cs

@ -1,5 +1,7 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq.Expressions;
using StabilityMatrix.Models;
using StabilityMatrix.Models.Settings;
using Wpf.Ui.Controls.Window;
@ -11,28 +13,56 @@ public interface ISettingsManager
Settings Settings { get; }
// Events
event EventHandler<bool>? ModelBrowserNsfwEnabledChanged;
event EventHandler<string>? LibraryDirChanged;
// Library settings
bool IsPortableMode { get; }
string LibraryDir { get; }
bool IsLibraryDirSet { get; }
bool TryFindLibrary();
// Dynamic paths from library
string DatabasePath { get; }
string ModelsDirectory { get; }
/// <summary>
/// Return a SettingsTransaction that can be used to modify Settings
/// Saves on Dispose.
/// </summary>
public SettingsTransaction BeginTransaction();
/// <summary>
/// Execute a function that modifies Settings
/// Commits changes after the function returns.
/// </summary>
/// <param name="func">Function accepting Settings to modify</param>
public void Transaction(Action<Settings> func);
/// <summary>
/// Modify a settings property by expression and commit changes.
/// This will notify listeners of SettingsPropertyChanged.
/// </summary>
public void Transaction<TValue>(Expression<Func<Settings, TValue>> expression, TValue value);
/// <summary>
/// Register a source observable object and property to be relayed to Settings
/// </summary>
public void RelayPropertyFor<T, TValue>(
T source,
Expression<Func<T, TValue>> sourceProperty,
Expression<Func<Settings, TValue>> settingsProperty) where T : INotifyPropertyChanged;
/// <summary>
/// Register an Action to be called on change of the settings property.
/// </summary>
public void RegisterPropertyChangedHandler<T>(
Expression<Func<Settings, T>> settingsProperty,
Action<T> onPropertyChanged);
// Migration
IEnumerable<InstalledPackage> GetOldInstalledPackages();
void SetTheme(string theme);
void AddInstalledPackage(InstalledPackage p);
void RemoveInstalledPackage(InstalledPackage p);
void SetActiveInstalledPackage(InstalledPackage? p);
void SetNavExpanded(bool navExpanded);
void AddPathExtension(string pathExtension);
string GetPathExtensionsAsString();
/// <summary>
/// Insert path extensions to the front of the PATH environment variable
@ -43,14 +73,8 @@ public interface ISettingsManager
void SetLastUpdateCheck(InstalledPackage package);
List<LaunchOption> GetLaunchArgs(Guid packageId);
void SaveLaunchArgs(Guid packageId, List<LaunchOption> launchArgs);
void SetWindowBackdropType(WindowBackdropType backdropType);
void SetHasSeenWelcomeNotification(bool hasSeenWelcomeNotification);
string? GetActivePackageHost();
string? GetActivePackagePort();
void SetWebApiHost(string? host);
void SetWebApiPort(string? port);
void SetFirstLaunchSetupComplete(bool firstLaunchSetupCompleted);
void SetModelBrowserNsfwEnabled(bool value);
void SetSharedFolderCategoryVisible(SharedFolderType type, bool visible);
bool IsSharedFolderCategoryVisible(SharedFolderType type);
bool IsEulaAccepted();
@ -66,10 +90,5 @@ public interface ISettingsManager
/// Creates the ./Data directory and the `.sm-portable` marker file
/// </summary>
void SetPortableMode();
void SetPlacement(string placementStr);
void SetSearchOptions(ModelSearchOptions options);
Guid GetOldActivePackageId();
void SetActiveInstalledPackage(Guid guid);
void SetIsImportAsConnected(bool value);
void SetKeepFolderLinksOnShutdown(bool value);
}

203
StabilityMatrix/Helper/SettingsManager.cs

@ -1,10 +1,15 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Threading;
using System.Threading.Tasks;
using AsyncAwaitBestPractices;
using NLog;
using Refit;
using StabilityMatrix.Models;
@ -44,6 +49,7 @@ public class SettingsManager : ISettingsManager
LibraryDirChanged?.Invoke(this, value);
}
}
public bool IsLibraryDirSet => !string.IsNullOrWhiteSpace(libraryDir);
// Dynamic paths from library
public string DatabasePath => Path.Combine(LibraryDir, "StabilityMatrix.db");
@ -52,9 +58,100 @@ public class SettingsManager : ISettingsManager
public Settings Settings { get; private set; } = new();
// Events
public event EventHandler<bool>? ModelBrowserNsfwEnabledChanged;
public event EventHandler<string>? LibraryDirChanged;
public event EventHandler<PropertyChangedEventArgs>? SettingsPropertyChanged;
/// <inheritdoc />
public SettingsTransaction BeginTransaction()
{
return new SettingsTransaction(this, SaveSettingsAsync);
}
/// <inheritdoc />
public void Transaction(Action<Settings> func)
{
using var transaction = BeginTransaction();
func(transaction.Settings);
transaction.Dispose();
}
/// <inheritdoc />
public void Transaction<TValue>(Expression<Func<Settings, TValue>> expression, TValue value)
{
if (expression.Body is not MemberExpression memberExpression)
{
throw new ArgumentException(
$"Expression must be a member expression, not {expression.Body.NodeType}");
}
var propertyInfo = memberExpression.Member as PropertyInfo;
if (propertyInfo == null)
{
throw new ArgumentException(
$"Expression member must be a property, not {memberExpression.Member.MemberType}");
}
var name = propertyInfo.Name;
// Set value
using var transaction = BeginTransaction();
propertyInfo.SetValue(transaction.Settings, value);
// Invoke property changed event
SettingsPropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
/// <inheritdoc />
public void RelayPropertyFor<T, TValue>(
T source,
Expression<Func<T, TValue>> sourceProperty,
Expression<Func<Settings, TValue>> settingsProperty) where T : INotifyPropertyChanged
{
var sourceGetter = sourceProperty.Compile();
var (propertyName, assigner) = Expressions.GetAssigner(sourceProperty);
var sourceSetter = assigner.Compile();
var settingsGetter = settingsProperty.Compile();
var (_, settingsAssigner) = Expressions.GetAssigner(settingsProperty);
var settingsSetter = settingsAssigner.Compile();
// Update source when settings change
SettingsPropertyChanged += (_, args) =>
{
if (args.PropertyName != propertyName) return;
sourceSetter(source, settingsGetter(Settings));
};
// Set and Save settings when source changes
source.PropertyChanged += (_, args) =>
{
if (args.PropertyName != propertyName) return;
settingsSetter(Settings, sourceGetter(source));
SaveSettingsAsync().SafeFireAndForget();
// Invoke property changed event
SettingsPropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
};
}
/// <inheritdoc />
public void RegisterPropertyChangedHandler<T>(
Expression<Func<Settings, T>> settingsProperty,
Action<T> onPropertyChanged)
{
var settingsGetter = settingsProperty.Compile();
var (propertyName, _) = Expressions.GetAssigner(settingsProperty);
// Invoke handler when settings change
SettingsPropertyChanged += (_, args) =>
{
if (args.PropertyName != propertyName) return;
onPropertyChanged(settingsGetter(Settings));
};
}
/// <summary>
/// Attempts to locate and set the library path
@ -191,54 +288,6 @@ public class SettingsManager : ISettingsManager
return oldSettings.ActiveInstalledPackage ?? default;
}
public void SetTheme(string theme)
{
Settings.Theme = theme;
SaveSettings();
}
public void AddInstalledPackage(InstalledPackage p)
{
Settings.InstalledPackages.Add(p);
SaveSettings();
}
public void RemoveInstalledPackage(InstalledPackage p)
{
Settings.InstalledPackages.Remove(p);
SetActiveInstalledPackage(Settings.InstalledPackages.Any() ? Settings.InstalledPackages.First() : null);
}
public void SetActiveInstalledPackage(InstalledPackage? p)
{
Settings.ActiveInstalledPackage = p?.Id;
SaveSettings();
}
public void SetActiveInstalledPackage(Guid guid)
{
Settings.ActiveInstalledPackage = guid;
SaveSettings();
}
public void SetNavExpanded(bool navExpanded)
{
Settings.IsNavExpanded = navExpanded;
SaveSettings();
}
public void SetIsImportAsConnected(bool value)
{
Settings.IsImportAsConnected = value;
SaveSettings();
}
public void SetKeepFolderLinksOnShutdown(bool value)
{
Settings.KeepFolderLinksOnShutdown = value;
SaveSettings();
}
public void AddPathExtension(string pathExtension)
{
Settings.PathExtensions ??= new List<string>();
@ -309,18 +358,6 @@ public class SettingsManager : ISettingsManager
SaveSettings();
}
public void SetWindowBackdropType(WindowBackdropType backdropType)
{
Settings.WindowBackdropType = backdropType;
SaveSettings();
}
public void SetHasSeenWelcomeNotification(bool hasSeenWelcomeNotification)
{
Settings.HasSeenWelcomeNotification = hasSeenWelcomeNotification;
SaveSettings();
}
public string? GetActivePackageHost()
{
var package = Settings.InstalledPackages.FirstOrDefault(x => x.Id == Settings.ActiveInstalledPackage);
@ -345,31 +382,6 @@ public class SettingsManager : ISettingsManager
return portOption?.DefaultValue as string;
}
public void SetWebApiHost(string? host)
{
Settings.WebApiHost = host;
SaveSettings();
}
public void SetWebApiPort(string? port)
{
Settings.WebApiPort = port;
SaveSettings();
}
public void SetFirstLaunchSetupComplete(bool value)
{
Settings.FirstLaunchSetupComplete = value;
SaveSettings();
}
public void SetModelBrowserNsfwEnabled(bool value)
{
Settings.ModelBrowserNsfwEnabled = value;
ModelBrowserNsfwEnabledChanged?.Invoke(this, value);
SaveSettings();
}
public void SetSharedFolderCategoryVisible(SharedFolderType type, bool visible)
{
Settings.SharedFolderVisibleCategories ??= new SharedFolderType();
@ -413,18 +425,6 @@ public class SettingsManager : ISettingsManager
File.WriteAllText(GlobalSettingsPath, json);
}
public void SetPlacement(string placementStr)
{
Settings.Placement = placementStr;
SaveSettings();
}
public void SetSearchOptions(ModelSearchOptions options)
{
Settings.ModelSearchOptions = options;
SaveSettings();
}
/// <summary>
/// Loads settings from the settings file
/// If the settings file does not exist, it will be created with default values
@ -480,4 +480,9 @@ public class SettingsManager : ISettingsManager
FileLock.ExitWriteLock();
}
}
private Task SaveSettingsAsync()
{
return Task.Run(SaveSettings);
}
}

14
StabilityMatrix/MainWindow.xaml.cs

@ -61,17 +61,17 @@ namespace StabilityMatrix
private void RootNavigation_OnPaneOpened(NavigationView sender, RoutedEventArgs args)
{
if (settingsManager.TryFindLibrary())
if (settingsManager.IsLibraryDirSet)
{
settingsManager.SetNavExpanded(true);
settingsManager.Transaction(s => s.IsNavExpanded = true);
}
}
private void RootNavigation_OnPaneClosed(NavigationView sender, RoutedEventArgs args)
{
if (settingsManager.TryFindLibrary())
if (settingsManager.IsLibraryDirSet)
{
settingsManager.SetNavExpanded(false);
settingsManager.Transaction(s => s.IsNavExpanded = false);
}
}
@ -97,7 +97,7 @@ namespace StabilityMatrix
var interopHelper = new WindowInteropHelper(this);
var placement = ScreenExtensions.GetPlacement(interopHelper.Handle);
settingsManager.SetPlacement(placement.ToString());
settingsManager.Transaction(s => s.Placement = placement.ToString());
});
}
@ -106,9 +106,9 @@ namespace StabilityMatrix
var interopHelper = new WindowInteropHelper(this);
var placement = ScreenExtensions.GetPlacement(interopHelper.Handle);
if (settingsManager.TryFindLibrary())
if (settingsManager.IsLibraryDirSet)
{
settingsManager.SetPlacement(placement.ToString());
settingsManager.Transaction(s => s.Placement = placement.ToString());
}
}
}

27
StabilityMatrix/Models/Settings/Settings.cs

@ -39,4 +39,31 @@ public class Settings
{
return InstalledPackages.FirstOrDefault(x => x.Id == ActiveInstalledPackage);
}
public void RemoveInstalledPackageAndUpdateActive(InstalledPackage package)
{
RemoveInstalledPackageAndUpdateActive(package.Id);
}
public void RemoveInstalledPackageAndUpdateActive(Guid id)
{
InstalledPackages.RemoveAll(x => x.Id == id);
UpdateActiveInstalledPackage();
}
// Update ActiveInstalledPackage if not valid
// uses first package or null if no packages
private void UpdateActiveInstalledPackage()
{
// Empty packages - set to null
if (InstalledPackages.Count == 0)
{
ActiveInstalledPackage = null;
}
// Active package is not in package - set to first package
else if (InstalledPackages.All(x => x.Id != ActiveInstalledPackage))
{
ActiveInstalledPackage = InstalledPackages[0].Id;
}
}
}

35
StabilityMatrix/Models/Settings/SettingsTransaction.cs

@ -0,0 +1,35 @@
using System;
using System.Threading.Tasks;
using AsyncAwaitBestPractices;
using StabilityMatrix.Helper;
namespace StabilityMatrix.Models.Settings;
/// <summary>
/// Transaction object which saves settings manager changes when disposed.
/// </summary>
public class SettingsTransaction : IDisposable, IAsyncDisposable
{
private readonly ISettingsManager settingsManager;
private readonly Func<Task> onCommit;
public Settings Settings => settingsManager.Settings;
public SettingsTransaction(ISettingsManager settingsManager, Func<Task> onCommit)
{
this.settingsManager = settingsManager;
this.onCommit = onCommit;
}
public void Dispose()
{
onCommit().SafeFireAndForget();
GC.SuppressFinalize(this);
}
public async ValueTask DisposeAsync()
{
await onCommit();
GC.SuppressFinalize(this);
}
}

2
StabilityMatrix/Services/NotificationBarService.cs

@ -28,6 +28,6 @@ public class NotificationBarService : SnackbarService, INotificationBarService
"You can join our Discord server for support and feedback.", linkIcon, ControlAppearance.Info);
snackbar.SafeFireAndForget();
settingsManager.SetHasSeenWelcomeNotification(true);
settingsManager.Transaction(s => s.HasSeenWelcomeNotification = true);
}
}

18
StabilityMatrix/ViewModels/CheckpointBrowserCardViewModel.cs

@ -33,15 +33,29 @@ public partial class CheckpointBrowserCardViewModel : ProgressViewModel
public override Visibility ProgressVisibility => Value > 0 ? Visibility.Visible : Visibility.Collapsed;
public override Visibility TextVisibility => Value > 0 ? Visibility.Visible : Visibility.Collapsed;
public CheckpointBrowserCardViewModel(CivitModel civitModel, IDownloadService downloadService, ISnackbarService snackbarService, ISettingsManager settingsManager)
public CheckpointBrowserCardViewModel(
CivitModel civitModel,
IDownloadService downloadService,
ISnackbarService snackbarService,
ISettingsManager settingsManager,
BitmapImage? fixedImage = null)
{
this.downloadService = downloadService;
this.snackbarService = snackbarService;
this.settingsManager = settingsManager;
CivitModel = civitModel;
if (fixedImage != null)
{
CardImage = fixedImage;
return;
}
CardImage = GetImage();
this.settingsManager.ModelBrowserNsfwEnabledChanged += OnNsfwModeChanged;
// Update image when nsfw setting changes
settingsManager.RegisterPropertyChangedHandler(
s => s.ModelBrowserNsfwEnabled,
_ => CardImage = GetImage());
}
// Choose and load image based on nsfw setting

39
StabilityMatrix/ViewModels/CheckpointBrowserViewModel.cs

@ -35,12 +35,12 @@ public partial class CheckpointBrowserViewModel : ObservableObject
[ObservableProperty] private ObservableCollection<CheckpointBrowserCardViewModel>? modelCards;
[ObservableProperty] private ICollectionView? modelCardsView;
[ObservableProperty] private string? searchQuery;
[ObservableProperty] private string searchQuery = string.Empty;
[ObservableProperty] private bool showNsfw;
[ObservableProperty] private bool showMainLoadingSpinner;
[ObservableProperty] private CivitPeriod selectedPeriod;
[ObservableProperty] private CivitSortMode sortMode;
[ObservableProperty] private CivitModelType selectedModelType;
[ObservableProperty] private CivitPeriod selectedPeriod = CivitPeriod.Month;
[ObservableProperty] private CivitSortMode sortMode = CivitSortMode.HighestRated;
[ObservableProperty] private CivitModelType selectedModelType = CivitModelType.Checkpoint;
[ObservableProperty] private int currentPageNumber;
[ObservableProperty] private int totalPages;
[ObservableProperty] private bool hasSearched;
@ -71,16 +71,22 @@ public partial class CheckpointBrowserViewModel : ObservableObject
this.settingsManager = settingsManager;
this.liteDbContext = liteDbContext;
CurrentPageNumber = 1;
CanGoToNextPage = true;
}
public void OnLoaded()
{
var searchOptions = settingsManager.Settings.ModelSearchOptions;
ShowNsfw = settingsManager.Settings.ModelBrowserNsfwEnabled;
SelectedPeriod = searchOptions?.SelectedPeriod ?? CivitPeriod.Month;
SortMode = searchOptions?.SortMode ?? CivitSortMode.HighestRated;
SelectedModelType = searchOptions?.SelectedModelType ?? CivitModelType.Checkpoint;
HasSearched = false;
CurrentPageNumber = 1;
CanGoToPreviousPage = false;
CanGoToNextPage = true;
ShowNsfw = settingsManager.Settings.ModelBrowserNsfwEnabled;
settingsManager.RelayPropertyFor(this, model => model.ShowNsfw,
settings => settings.ModelBrowserNsfwEnabled);
}
/// <summary>
@ -209,7 +215,6 @@ public partial class CheckpointBrowserViewModel : ObservableObject
[RelayCommand]
private async Task SearchModels()
{
if (string.IsNullOrWhiteSpace(SearchQuery)) return;
var timer = Stopwatch.StartNew();
if (SearchQuery != previousSearchQuery)
@ -314,7 +319,7 @@ public partial class CheckpointBrowserViewModel : ObservableObject
partial void OnShowNsfwChanged(bool value)
{
settingsManager.SetModelBrowserNsfwEnabled(value);
settingsManager.Transaction(s => s.ModelBrowserNsfwEnabled = value);
ModelCardsView?.Refresh();
if (!HasSearched)
@ -326,22 +331,22 @@ public partial class CheckpointBrowserViewModel : ObservableObject
partial void OnSelectedPeriodChanged(CivitPeriod oldValue, CivitPeriod newValue)
{
TrySearchAgain().SafeFireAndForget();
settingsManager.SetSearchOptions(new ModelSearchOptions(newValue, SortMode,
SelectedModelType));
settingsManager.Transaction(s => s.ModelSearchOptions = new ModelSearchOptions(
newValue, SortMode, SelectedModelType));
}
partial void OnSortModeChanged(CivitSortMode oldValue, CivitSortMode newValue)
{
TrySearchAgain().SafeFireAndForget();
settingsManager.SetSearchOptions(new ModelSearchOptions(SelectedPeriod, newValue,
SelectedModelType));
settingsManager.Transaction(s => s.ModelSearchOptions = new ModelSearchOptions(
SelectedPeriod, newValue, SelectedModelType));
}
partial void OnSelectedModelTypeChanged(CivitModelType oldValue, CivitModelType newValue)
{
TrySearchAgain().SafeFireAndForget();
settingsManager.SetSearchOptions(new ModelSearchOptions(SelectedPeriod, SortMode,
newValue));
settingsManager.Transaction(s => s.ModelSearchOptions = new ModelSearchOptions(
SelectedPeriod, SortMode, newValue));
}
private async Task TrySearchAgain(bool shouldUpdatePageNumber = true)

5
StabilityMatrix/ViewModels/CheckpointManagerViewModel.cs

@ -25,9 +25,10 @@ public partial class CheckpointManagerViewModel : ObservableObject
partial void OnIsImportAsConnectedChanged(bool value)
{
if (value != settingsManager.Settings.IsImportAsConnected)
if (settingsManager.IsLibraryDirSet &&
value != settingsManager.Settings.IsImportAsConnected)
{
settingsManager.SetIsImportAsConnected(value);
settingsManager.Transaction(s => s.IsImportAsConnected = value);
}
}

12
StabilityMatrix/ViewModels/DataDirectoryMigrationViewModel.cs

@ -155,9 +155,12 @@ public partial class DataDirectoryMigrationViewModel : ObservableObject
var oldPackages = settingsManager.GetOldInstalledPackages().ToArray();
MigrateProgressText = "Migrating Packages...";
await using var st = settingsManager.BeginTransaction();
foreach (var package in oldPackages)
{
settingsManager.RemoveInstalledPackage(package);
st.Settings.RemoveInstalledPackageAndUpdateActive(package);
#pragma warning disable CS0618
Logger.Info($"Migrating package {MigrateProgressCount} of {oldPackages.Length} at path {package.Path}");
@ -165,18 +168,21 @@ public partial class DataDirectoryMigrationViewModel : ObservableObject
await package.MigratePath();
MigrateProgressCount++;
settingsManager.AddInstalledPackage(package);
settingsManager.SetActiveInstalledPackage(package);
st.Settings.InstalledPackages.Add(package);
st.Settings.ActiveInstalledPackage = package.Id;
if (oldLibraryPath != libraryPath)
{
// setup model links again
if (!string.IsNullOrWhiteSpace(package.PackageName))
{
var basePackage = packageFactory.FindPackageByName(package.PackageName);
if (basePackage != default)
{
sharedFolders.SetupLinksForPackage(basePackage, package.FullPath!);
}
}
}
// Also recreate the venv
var venvPath = Path.Combine(libraryPath, package.FullPath!);

5
StabilityMatrix/ViewModels/InstallerViewModel.cs

@ -339,8 +339,9 @@ public partial class InstallerViewModel : ObservableObject
LaunchCommand = SelectedPackage.LaunchCommand,
LastUpdateCheck = DateTimeOffset.Now
};
settingsManager.AddInstalledPackage(package);
settingsManager.SetActiveInstalledPackage(package);
await using var st = settingsManager.BeginTransaction();
st.Settings.InstalledPackages.Add(package);
st.Settings.ActiveInstalledPackage = package.Id;
ProgressValue = 0;
}

30
StabilityMatrix/ViewModels/LaunchViewModel.cs

@ -33,7 +33,8 @@ public partial class LaunchViewModel : ObservableObject
private readonly ISharedFolders sharedFolders;
private BasePackage? runningPackage;
private bool clearingPackages = false;
private bool clearingPackages;
private string webUiUrl = string.Empty;
[ObservableProperty] private string consoleInput = "";
[ObservableProperty] private Visibility launchButtonVisibility;
@ -42,26 +43,7 @@ public partial class LaunchViewModel : ObservableObject
[ObservableProperty] private bool showWebUiButton;
[ObservableProperty] private ObservableCollection<string>? consoleHistory;
private string webUiUrl = string.Empty;
private InstalledPackage? selectedPackage;
public InstalledPackage? SelectedPackage
{
get => selectedPackage;
set
{
if (value == selectedPackage) return;
selectedPackage = value;
if (!clearingPackages)
{
settingsManager.SetActiveInstalledPackage(value);
}
OnPropertyChanged();
}
}
[ObservableProperty] private InstalledPackage? selectedPackage;
[ObservableProperty] private ObservableCollection<InstalledPackage> installedPackages = new();
public LaunchViewModel(ISettingsManager settingsManager,
@ -91,6 +73,12 @@ public partial class LaunchViewModel : ObservableObject
ToastNotificationManagerCompat.OnActivated += ToastNotificationManagerCompatOnOnActivated;
}
partial void OnSelectedPackageChanged(InstalledPackage? value)
{
if (clearingPackages) return;
settingsManager.Transaction(s => s.ActiveInstalledPackage = value?.Id);
}
private void OnTeachingTooltipNeeded(object? sender, EventArgs e)
{
IsLaunchTeachingTipsOpen = true;

5
StabilityMatrix/ViewModels/OneClickInstallViewModel.cs

@ -137,8 +137,9 @@ public partial class OneClickInstallViewModel : ObservableObject
LaunchCommand = a1111.LaunchCommand,
LastUpdateCheck = DateTimeOffset.Now
};
settingsManager.AddInstalledPackage(package);
settingsManager.SetActiveInstalledPackage(package);
await using var st = settingsManager.BeginTransaction();
st.Settings.InstalledPackages.Add(package);
st.Settings.ActiveInstalledPackage = package.Id;
EventManager.Instance.OnInstalledPackagesChanged();
HeaderText = "Installation complete!";

6
StabilityMatrix/ViewModels/PackageManagerViewModel.cs

@ -185,7 +185,11 @@ public partial class PackageManagerViewModel : ObservableObject
{
snackbarService.ShowSnackbarAsync($"Package {SelectedPackage.DisplayName} uninstalled", "Success",
ControlAppearance.Success).SafeFireAndForget();
settingsManager.RemoveInstalledPackage(SelectedPackage);
settingsManager.Transaction(settings =>
{
settings.RemoveInstalledPackageAndUpdateActive(SelectedPackage);
});
}
await OnLoaded();
IsUninstalling = false;

15
StabilityMatrix/ViewModels/SettingsViewModel.cs

@ -74,13 +74,13 @@ public partial class SettingsViewModel : ObservableObject
partial void OnWebApiHostChanged(string? value)
{
settingsManager.SetWebApiHost(value);
settingsManager.Transaction(s => s.WebApiHost = value);
a3WebApiManager.ResetClient();
}
partial void OnWebApiPortChanged(string? value)
{
settingsManager.SetWebApiPort(value);
settingsManager.Transaction(s => s.WebApiPort = value);
a3WebApiManager.ResetClient();
}
@ -90,7 +90,7 @@ public partial class SettingsViewModel : ObservableObject
{
if (value != settingsManager.Settings.KeepFolderLinksOnShutdown)
{
settingsManager.SetKeepFolderLinksOnShutdown(value);
settingsManager.Transaction(s => s.KeepFolderLinksOnShutdown = value);
}
}
@ -142,13 +142,14 @@ public partial class SettingsViewModel : ObservableObject
partial void OnSelectedThemeChanged(string value)
{
settingsManager.SetTheme(value);
using var st = settingsManager.BeginTransaction();
st.Settings.Theme = value;
ApplyTheme(value);
}
partial void OnWindowBackdropTypeChanged(WindowBackdropType oldValue, WindowBackdropType newValue)
{
settingsManager.SetWindowBackdropType(newValue);
settingsManager.Transaction(s => s.WindowBackdropType = newValue);
if (Application.Current.MainWindow != null)
{
WindowBackdrop.ApplyBackdrop(Application.Current.MainWindow, newValue);
@ -221,13 +222,15 @@ public partial class SettingsViewModel : ObservableObject
{
Id = Guid.NewGuid(),
DisplayName = Path.GetFileName(path),
#pragma warning disable CS0618 // Type or member is obsolete
Path = path,
#pragma warning restore CS0618 // Type or member is obsolete
PackageName = "dank-diffusion",
PackageVersion = "v1.0.0",
};
// Add package to settings
settingsManager.AddInstalledPackage(package);
settingsManager.Transaction(s => s.InstalledPackages.Add(package));
});
// Debug card commands

Loading…
Cancel
Save