Settings management started

This commit is contained in:
2025-11-29 16:49:14 -06:00
parent c64386b985
commit aae22e57cf
8 changed files with 408 additions and 8 deletions

View File

@@ -9,6 +9,7 @@ public static class AppManager
public static ICogwheelConsole SzConsole { get; } = new SessionZeroConsole();
public static CommandsManager CommandsManager { get; } = new();
public static ConsoleControl ConsoleControl { get; } = new();
public static AppSettings Settings { get; } = new();
public static void ShowConsole()
{
@@ -27,4 +28,10 @@ public static class AppManager
{
MainWindow.ChangePage(pageName);
}
[Command(Name = "test")]
private static void Test()
{
COGWHEEL.LogWarning($"Trim size is: {ConsoleControl.OutputTrimSize}");
}
}

326
SessionZero/AppSettings.cs Normal file
View File

@@ -0,0 +1,326 @@
using System;
using System.Collections.Generic;
using System.IO;
using Avalonia.Media;
using Cogwheel;
namespace SessionZero;
public class AppSettings
{
public string SettingsFilePath { get; set; } = "";
public Dictionary<string, AppSetting> Settings { get; set; } = new();
public AppSetting CreateSetting(string settingName, Type settingType)
{
return new AppSetting(settingName, settingType);
}
public void AddSetting(AppSetting setting)
{
if (!Settings.TryAdd(setting.SettingName, setting))
{
COGWHEEL.LogError($"Cannot add setting: '{setting.SettingName}'. Setting already exists.");
}
}
public AppSetting? GetSetting(string settingName)
{
if (!Settings.TryGetValue(settingName, out var setting))
{
COGWHEEL.LogError($"Cannot get setting: '{settingName}'. Setting does not exist.");
return null;
}
return setting;
}
public void RemoveSetting(string settingName)
{
if (!Settings.Remove(settingName))
{
COGWHEEL.LogError($"Cannot remove setting: '{settingName}. It may not exist.");
}
}
public bool SetSettingValue<T>(string settingName, T value)
{
if (Settings.TryGetValue(settingName, out var setting))
{
return setting.SetValue(value);
}
COGWHEEL.LogError($"Cannot set setting: '{settingName}'. Setting does not exist.");
return false;
}
public bool SetSettingValue(string settingName, string value)
{
if (Settings.TryGetValue(settingName, out var setting))
{
return setting.SetValue(value);
}
COGWHEEL.LogError($"Cannot set setting: '{settingName}'. Setting does not exist.");
return false;
}
public T? GetValue<T>(string settingName)
{
if (Settings.TryGetValue(settingName, out var setting))
{
return setting.GetValue<T>();
}
return default;
}
public string GetValueAsString(string settingName)
{
if (!Settings.TryGetValue(settingName, out var setting) || setting == null)
{
COGWHEEL.LogError($"Cannot get setting '{settingName}'. Setting does not exist.");
return string.Empty;
}
var type = setting.SettingType;
try
{
var method = typeof(AppSetting).GetMethod(nameof(AppSetting.GetValue))!;
var generic = method.MakeGenericMethod(type);
var valueObj = generic.Invoke(setting, null);
if (valueObj == null)
return string.Empty;
if (type == typeof(string))
return (string)valueObj;
if (type.IsPrimitive || type.IsEnum || type == typeof(decimal))
return Convert.ToString(valueObj) ?? string.Empty;
return valueObj.ToString() ?? string.Empty;
}
catch (Exception ex)
{
COGWHEEL.LogError($"Failed to get setting '{settingName}' as string: {ex.Message}");
return string.Empty;
}
}
public void SaveToFile() {}
public void LoadFromFile() {}
}
public class AppSetting(string settingName, Type settingType)
{
public string SettingName { get; } = settingName;
public Type SettingType { get; } = settingType;
private object? _settingValue;
public T GetValue<T>()
{
if (typeof(T) != SettingType)
{
COGWHEEL.LogError($"Cannot get value of setting '{SettingName}': Setting is type '{SettingType.Name}' but GetValue was called with type '{typeof(T).Name}'.'");
}
return _settingValue is null ? default! : (T)_settingValue;
}
public bool SetValue<T>(T value)
{
if (typeof(T) != SettingType)
{
COGWHEEL.LogError($"Cannot set value of setting '{SettingName}': Setting is type '{SettingType.Name}' but SetValue was called with type '{typeof(T).Name}'.'");
return false;
}
_settingValue = value!;
return true;
}
public bool SetValue(object? value)
{
if (value == null)
{
_settingValue = null;
return true;
}
if (SettingType.IsInstanceOfType(value))
{
_settingValue = value;
return true;
}
try
{
var converted = Convert.ChangeType(value, SettingType);
_settingValue = converted;
return true;
}
catch
{
COGWHEEL.LogError($"Cannot convert value '{value}' to {SettingType.Name} for setting '{SettingName}'.");
return false;
}
}
public bool SetValue(string valueString)
{
try
{
object? parsedValue = null;
if (SettingType == typeof(string))
{
parsedValue = valueString;
}
else if (SettingType == typeof(int))
{
if (!int.TryParse(valueString, out var i))
{
COGWHEEL.LogError($"Cannot parse '{valueString}' as int for setting '{SettingName}'.");
return false;
}
parsedValue = i;
}
else if (SettingType == typeof(float))
{
if (!float.TryParse(valueString, out var f))
{
COGWHEEL.LogError($"Cannot parse '{valueString}' as float for setting '{SettingName}'.");
return false;
}
parsedValue = f;
}
else if (SettingType == typeof(bool))
{
if (!bool.TryParse(valueString, out var b))
{
COGWHEEL.LogError($"Cannot parse '{valueString}' as bool for setting '{SettingName}'.");
return false;
}
parsedValue = b;
}
else
{
COGWHEEL.LogError(
$"Unsupported setting type '{SettingType.Name}' in SetValue(string) for setting '{SettingName}'.");
return false;
}
_settingValue = parsedValue;
return true;
}
catch (Exception ex)
{
COGWHEEL.LogError($"Failed to set setting '{SettingName}' to '{valueString}': {ex.Message}");
return false;
}
}
}
static class AppSettingsCommands
{
[Command(Name = "setsetting")]
public static void SetSetting(string settingName, string value)
{
if (AppManager.Settings.SetSettingValue(settingName, value))
{
COGWHEEL.Log($"Setting '{settingName}' set to '{value}'.");
}
// else
// {
// COGWHEEL.LogError($"Could not set setting '{settingName}' to '{value}'.");
// }
}
[Command(Name = "getsetting")]
public static void GetSetting(string settingName)
{
var value = AppManager.Settings.GetValueAsString(settingName);
COGWHEEL.Log($"Setting '{settingName}' value is: ({AppManager.Settings.GetSetting(settingName)?.SettingType.Name}){value}.");
}
[Command(Name = "listsettings")]
public static void ListSettings(string settingName = "")
{
var outputString = $"-- Settings --\n";
if (string.IsNullOrEmpty(settingName))
{
foreach (var setting in AppManager.Settings.Settings)
{
outputString +=
$"{setting.Value.SettingName}: {setting.Value.SettingType.Name} = {AppManager.Settings.GetValueAsString(setting.Key)}\n";
}
AppManager.ConsoleControl.Log(outputString, Colors.CadetBlue);
}
else
{
COGWHEEL.LogWarning($"Searching for settings is not implemented yet.");
}
}
// TODO: Go update Cogwheel to accept array arguments somehow
// [Command(Name = "setting")]
// public static void SettingCommand(string[] args)
// {
// if (args.Length == 0)
// {
// COGWHEEL.LogError("No arguments supplied. Usage: 'setting <action>'");
// }
//
// var action = args[0];
// List<string> actionArgs = new();
// for (int i = 1; i < args.Length; i++)
// {
// actionArgs.Add(args[i]);
// }
//
// switch (action)
// {
// case "set":
// if (actionArgs.Count == 2)
// {
// var settingName = args[0];
// var settingValue = args[1];
//
// if (AppManager.Settings.SetSettingValue(settingName, settingValue))
// {
// COGWHEEL.Log($"Setting '{settingName}' successfully set to '{settingValue}'.");
// }
// }
// else
// {
// COGWHEEL.LogError($"Invalid number of arguments for '{action}'. Usage: 'setting set <settingName> <settingValue>'");
// }
// break;
// case "get":
// if (actionArgs.Count == 1)
// {
// var val = AppManager.Settings.GetValueAsString(args[0]);
// COGWHEEL.Log($"Value of Setting '{args[0]}' is '{val}'.");
// }
// else
// {
// COGWHEEL.LogError($"Invalid number of arguments for '{action}'. Usage: 'setting get <settingName>'");
// }
// break;
// case "add":
// break;
// case "remove":
// break;
// default:
// COGWHEEL.LogError($"Unknown argument '{action}' for 'setting' command. Options are 'set, get, add, remove'.");
// break;
// }
// }
}

View File

@@ -5,7 +5,9 @@
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="SessionZero.Cogwheel.ConsoleControl">
<Grid Background="Transparent" RowDefinitions="*, Auto, *" HorizontalAlignment="Stretch">
<TextBlock Grid.Row="0" Name="Output" Foreground="White" Background="#7F272727" HorizontalAlignment="Stretch" TextWrapping="Wrap"></TextBlock>
<ScrollViewer Name="OutputScrollView">
<TextBlock Grid.Row="0" Name="Output" Foreground="White" Background="#7F272727" HorizontalAlignment="Stretch" TextWrapping="Wrap"></TextBlock>
</ScrollViewer>
<TextBox Grid.Row="1" Name="Input" Background="#7F272727" Foreground="White" Height="30" AcceptsReturn="False" AcceptsTab="False"></TextBox>
</Grid>
</UserControl>

View File

@@ -10,8 +10,11 @@ namespace SessionZero.Cogwheel;
public partial class ConsoleControl : UserControl
{
public int OutputTrimSize { get; set; } = 200;
private TextBlock? _output;
private TextBox? _input;
private ScrollViewer? _outputScrollViewer;
public ConsoleControl()
{
@@ -19,6 +22,7 @@ public partial class ConsoleControl : UserControl
_output = this.FindControl<TextBlock>("Output");
_input = this.FindControl<TextBox>("Input");
_outputScrollViewer = this.FindControl<ScrollViewer>("OutputScrollView");
_input?.KeyDown += Input_OnKeyDown;
}
@@ -27,14 +31,37 @@ public partial class ConsoleControl : UserControl
{
if (e.Key == Key.Enter)
{
var inputText = _input!.Text ?? string.Empty;
Log(inputText);
if (inputText.Length > 0) COGWHEEL.RunCommand(inputText);
_input.Text = string.Empty;
SubmitInput();
e.Handled = true;
}
}
private void SubmitInput()
{
var inputText = _input!.Text ?? string.Empty;
Log(inputText);
if (inputText.Length > 0) COGWHEEL.RunCommand(inputText);
_input.Text = string.Empty;
TrimOutput();
ScrollToEnd();
}
private void TrimOutput()
{
var maxInLines = OutputTrimSize * 3;
while (_output?.Inlines?.Count > maxInLines)
{
if (_output?.Inlines?.Count >= 3)
{
_output?.Inlines?.RemoveRange(0,3);
}
else
{
_output?.Inlines?.RemoveAt(0);
}
}
}
public void Log(string text, Color? color = null)
{
if (_output == null)
@@ -58,4 +85,9 @@ public partial class ConsoleControl : UserControl
{
_output?.Inlines?.Clear();
}
public void ScrollToEnd()
{
_outputScrollViewer?.ScrollToEnd();
}
}

View File

@@ -28,6 +28,9 @@ public partial class MainWindow : Window
KeyDownEvent.AddClassHandler<TopLevel>(OnKeyDown, handledEventsToo: true);
ChangePage("Home");
AppManager.Settings.AddSetting(new AppSetting("test", typeof(int)));
AppManager.Settings.SetSettingValue("test", 1);
}
public void ChangePage(string pageName)

View File

@@ -6,5 +6,15 @@
x:Class="SessionZero.Pages.SettingsPage">
<StackPanel>
<Label FontSize="20">Settings</Label>
<StackPanel Orientation="Horizontal" Spacing="15">
<Label FontSize="15" VerticalAlignment="Center">Console Output Max Size</Label>
<Slider Name="ConsoleTrimSlider" Minimum="10" Maximum="1000" Width="200" HorizontalAlignment="Left"></Slider>
<TextBlock Name="ConsoleTrimSliderValue" VerticalAlignment="Center">10</TextBlock>
</StackPanel>
<StackPanel Orientation="Horizontal" Spacing="15">
<Label VerticalAlignment="Center" FontSize="15">Log To File</Label>
<CheckBox Name="LogToFileCheckbox"></CheckBox>
</StackPanel>
</StackPanel>
</UserControl>

View File

@@ -1,5 +1,6 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.Primitives;
using Avalonia.Markup.Xaml;
namespace SessionZero.Pages;
@@ -8,10 +9,28 @@ public partial class SettingsPage : UserControl, IPageBase
{
public string PageName { get; set; } = "Settings";
private Slider? _consoleTrimSlider;
private TextBlock? _consoleTrimSliderLabel;
public SettingsPage()
{
InitializeComponent();
_consoleTrimSlider = this.FindControl<Slider>("ConsoleTrimSlider");
_consoleTrimSliderLabel = this.FindControl<TextBlock>("ConsoleTrimSliderValue");
_consoleTrimSlider?.ValueChanged += ConsoleTrimSliderOnValueChanged;
}
public void Refresh() { }
private void ConsoleTrimSliderOnValueChanged(object? sender, RangeBaseValueChangedEventArgs e)
{
AppManager.ConsoleControl.OutputTrimSize = (int)e.NewValue;
_consoleTrimSliderLabel?.Text = AppManager.ConsoleControl.OutputTrimSize.ToString();
}
public void Refresh()
{
_consoleTrimSlider?.Value = AppManager.ConsoleControl.OutputTrimSize;
_consoleTrimSliderLabel?.Text = AppManager.ConsoleControl.OutputTrimSize.ToString();
}
}

View File

@@ -2,4 +2,5 @@
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ACOGWHEEL_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003Fhome_003Fchris_003F_002Econfig_003FJetBrains_003FRider2025_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F2ee8efbdf4144b7e9741475fab7c883d5800_003Fa0_003F83e60bea_003FCOGWHEEL_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ACommandsManager_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003Fhome_003Fchris_003F_002Econfig_003FJetBrains_003FRider2025_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F2ee8efbdf4144b7e9741475fab7c883d5800_003F6f_003F28a7ba06_003FCommandsManager_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AICogwheelConsole_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003Fhome_003Fchris_003F_002Econfig_003FJetBrains_003FRider2025_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F2ee8efbdf4144b7e9741475fab7c883d5800_003F77_003Fe0eaad3c_003FICogwheelConsole_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AMethodBaseInvoker_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003Fhome_003Fchris_003F_002Econfig_003FJetBrains_003FRider2025_002E3_003Fresharper_002Dhost_003FSourcesCache_003Fd6b757e154dd7f8c23e0e785431c97a76e4b9c6bdae38b978238421dbab55d_003FMethodBaseInvoker_002Ecs/@EntryIndexedValue">ForceIncluded</s:String></wpf:ResourceDictionary>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AMethodBaseInvoker_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003Fhome_003Fchris_003F_002Econfig_003FJetBrains_003FRider2025_002E3_003Fresharper_002Dhost_003FSourcesCache_003Fd6b757e154dd7f8c23e0e785431c97a76e4b9c6bdae38b978238421dbab55d_003FMethodBaseInvoker_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AString_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003Fhome_003Fchris_003F_002Econfig_003FJetBrains_003FRider2025_002E3_003Fresharper_002Dhost_003FSourcesCache_003Fdad3f0ebff0dd1f8e1d244c3c44c649be8228d5e25fb37ef1de7f3c0e261c_003FString_002Ecs/@EntryIndexedValue">ForceIncluded</s:String></wpf:ResourceDictionary>