You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
186 lines
6.4 KiB
186 lines
6.4 KiB
using System; |
|
using System.Collections.ObjectModel; |
|
using System.IO; |
|
using System.Reflection; |
|
using System.Threading.Tasks; |
|
using Avalonia; |
|
using Avalonia.Controls.Notifications; |
|
using Avalonia.Styling; |
|
using CommunityToolkit.Mvvm.ComponentModel; |
|
using CommunityToolkit.Mvvm.Input; |
|
using FluentAvalonia.UI.Controls; |
|
using NLog; |
|
using StabilityMatrix.Avalonia.Services; |
|
using StabilityMatrix.Avalonia.Views; |
|
using StabilityMatrix.Core.Attributes; |
|
using StabilityMatrix.Core.Extensions; |
|
using StabilityMatrix.Core.Helper; |
|
using StabilityMatrix.Core.Python; |
|
using StabilityMatrix.Core.Services; |
|
using Symbol = FluentIcons.Common.Symbol; |
|
using SymbolIconSource = FluentIcons.FluentAvalonia.SymbolIconSource; |
|
|
|
namespace StabilityMatrix.Avalonia.ViewModels; |
|
|
|
[View(typeof(SettingsPage))] |
|
public partial class SettingsViewModel : PageViewModelBase |
|
{ |
|
private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); |
|
|
|
private readonly INotificationService notificationService; |
|
private readonly ISettingsManager settingsManager; |
|
private readonly IPrerequisiteHelper prerequisiteHelper; |
|
private readonly IPyRunner pyRunner; |
|
|
|
public override string Title => "Settings"; |
|
public override IconSource IconSource => new SymbolIconSource {Symbol = Symbol.Settings, IsFilled = true}; |
|
|
|
// Theme panel |
|
[ObservableProperty] private string? selectedTheme; |
|
|
|
public ObservableCollection<string> AvailableThemes { get; } = new() |
|
{ |
|
"Light", |
|
"Dark", |
|
"System", |
|
}; |
|
|
|
public SettingsViewModel( |
|
INotificationService notificationService, |
|
ISettingsManager settingsManager, |
|
IPrerequisiteHelper prerequisiteHelper, |
|
IPyRunner pyRunner) |
|
{ |
|
this.notificationService = notificationService; |
|
this.settingsManager = settingsManager; |
|
this.prerequisiteHelper = prerequisiteHelper; |
|
this.pyRunner = pyRunner; |
|
|
|
SelectedTheme = AvailableThemes[1]; |
|
} |
|
|
|
partial void OnSelectedThemeChanged(string? value) |
|
{ |
|
// In case design / tests |
|
if (Application.Current is null) return; |
|
// Change theme |
|
Application.Current.RequestedThemeVariant = value switch |
|
{ |
|
"Dark" => ThemeVariant.Dark, |
|
"Light" => ThemeVariant.Light, |
|
_ => ThemeVariant.Default |
|
}; |
|
} |
|
|
|
// Debug info |
|
[ObservableProperty] private string? debugPaths; |
|
[ObservableProperty] private string? debugCompatInfo; |
|
[ObservableProperty] private string? debugGpuInfo; |
|
|
|
public void LoadDebugInfo() |
|
{ |
|
var assembly = Assembly.GetExecutingAssembly(); |
|
var appData = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData); |
|
DebugPaths = $""" |
|
Current Working Directory [Environment.CurrentDirectory] |
|
"{Environment.CurrentDirectory}" |
|
App Directory [Assembly.GetExecutingAssembly().Location] |
|
"{assembly.Location}" |
|
App Directory [AppContext.BaseDirectory] |
|
"{AppContext.BaseDirectory}" |
|
AppData Directory [SpecialFolder.ApplicationData] |
|
"{appData}" |
|
"""; |
|
|
|
// 1. Check portable mode |
|
var appDir = Compat.AppCurrentDir; |
|
var expectedPortableFile = Path.Combine(appDir, "Data", ".sm-portable"); |
|
var isPortableMode = File.Exists(expectedPortableFile); |
|
|
|
DebugCompatInfo = $""" |
|
Platform: {Compat.Platform} |
|
AppData: {Compat.AppData} |
|
AppDataHome: {Compat.AppDataHome} |
|
AppCurrentDir: {Compat.AppCurrentDir} |
|
ExecutableName: {Compat.GetExecutableName()} |
|
-- Settings -- |
|
Expected Portable Marker file: {expectedPortableFile} |
|
Portable Marker file exists: {isPortableMode} |
|
IsLibraryDirSet = {settingsManager.IsLibraryDirSet} |
|
IsPortableMode = {settingsManager.IsPortableMode} |
|
"""; |
|
|
|
// Get Gpu info |
|
var gpuInfo = ""; |
|
foreach (var (i, gpu) in HardwareHelper.IterGpuInfo().Enumerate()) |
|
{ |
|
gpuInfo += $"[{i+1}] {gpu}\n"; |
|
} |
|
DebugGpuInfo = gpuInfo; |
|
} |
|
|
|
// Debug buttons |
|
[RelayCommand] |
|
private void DebugNotification() |
|
{ |
|
notificationService.Show(new Notification( |
|
title: "Test Notification", |
|
message: "Here is some message", |
|
type: NotificationType.Information)); |
|
} |
|
|
|
[RelayCommand] |
|
private async Task DebugContentDialog() |
|
{ |
|
var dialog = new ContentDialog |
|
{ |
|
DefaultButton = ContentDialogButton.Primary, |
|
Title = "Test title", |
|
PrimaryButtonText = "OK", |
|
CloseButtonText = "Close" |
|
}; |
|
|
|
var result = await dialog.ShowAsync(); |
|
notificationService.Show(new Notification("Content dialog closed", |
|
$"Result: {result}")); |
|
} |
|
|
|
[RelayCommand] |
|
private void DebugThrowException() |
|
{ |
|
// Use try-catch to generate traceback information |
|
throw new OperationCanceledException("Example Message"); |
|
} |
|
|
|
[RelayCommand] |
|
private async Task CheckPythonVersion() |
|
{ |
|
var isInstalled = prerequisiteHelper.IsPythonInstalled; |
|
Logger.Debug($"Check python installed: {isInstalled}"); |
|
// Ensure python installed |
|
if (!prerequisiteHelper.IsPythonInstalled) |
|
{ |
|
// Need 7z as well for site packages repack |
|
Logger.Debug("Python not installed, unpacking resources..."); |
|
await prerequisiteHelper.UnpackResourcesIfNecessary(); |
|
Logger.Debug("Unpacked resources, installing python..."); |
|
await prerequisiteHelper.InstallPythonIfNecessary(); |
|
} |
|
|
|
// Get python version |
|
await pyRunner.Initialize(); |
|
var result = await pyRunner.GetVersionInfo(); |
|
// Show dialog box |
|
var dialog = new ContentDialog |
|
{ |
|
Title = "Python version info", |
|
Content = result, |
|
PrimaryButtonText = "Ok", |
|
IsPrimaryButtonEnabled = true |
|
}; |
|
dialog.Title = "Python version info"; |
|
dialog.Content = result; |
|
dialog.PrimaryButtonText = "Ok"; |
|
await dialog.ShowAsync(); |
|
} |
|
}
|
|
|