Improve EditServerConfigurationViewModel mostly cleanup by using ReactiveUI CodeGeneration.
This commit is contained in:
parent
4ff9b78db8
commit
114542b317
4 changed files with 127 additions and 73 deletions
|
|
@ -1,35 +1,18 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using System.Reactive;
|
||||
using System.Reactive;
|
||||
using System.Reactive.Linq;
|
||||
using Npgsql;
|
||||
using pgLabII.Model;
|
||||
using pgLabII.PgUtils.ConnectionStrings;
|
||||
using pgLabII.Services;
|
||||
using ReactiveUI;
|
||||
using ReactiveUI.SourceGenerators;
|
||||
|
||||
namespace pgLabII.ViewModels;
|
||||
|
||||
public class EditServerConfigurationViewModel : ViewModelBase
|
||||
public partial class EditServerConfigurationViewModel : ViewModelBase
|
||||
{
|
||||
// Prefer new UI VM; keep old model for compatibility by wrapping when needed
|
||||
public ServerConfigurationViewModel Configuration { get; set; }
|
||||
|
||||
// Connection string IO
|
||||
private string _inputConnectionString = string.Empty;
|
||||
public string InputConnectionString
|
||||
{
|
||||
get => _inputConnectionString;
|
||||
set
|
||||
{
|
||||
this.RaiseAndSetIfChanged(ref _inputConnectionString, value);
|
||||
// auto-detect when input changes and we are in Auto mode
|
||||
if (ForcedFormat == ForcedFormatOption.Auto)
|
||||
{
|
||||
DetectFormat();
|
||||
}
|
||||
}
|
||||
}
|
||||
private readonly IConnectionStringService _service;
|
||||
// Store original for reverting changes
|
||||
private ServerConfigurationViewModel? _originalConfiguration;
|
||||
|
||||
public enum ForcedFormatOption
|
||||
{
|
||||
|
|
@ -40,50 +23,27 @@ public class EditServerConfigurationViewModel : ViewModelBase
|
|||
Jdbc
|
||||
}
|
||||
|
||||
private ForcedFormatOption _forcedFormat = ForcedFormatOption.Auto;
|
||||
public ForcedFormatOption ForcedFormat
|
||||
{
|
||||
get => _forcedFormat;
|
||||
set
|
||||
{
|
||||
this.RaiseAndSetIfChanged(ref _forcedFormat, value);
|
||||
// When forcing off Auto, clear detected label; when switching to Auto, re-detect
|
||||
if (value == ForcedFormatOption.Auto)
|
||||
DetectFormat();
|
||||
else
|
||||
DetectedFormat = null;
|
||||
}
|
||||
}
|
||||
public Interaction<bool, bool?> CloseInteraction { get; } = new();
|
||||
// Prefer new UI VM; keep old model for compatibility by wrapping when needed
|
||||
public ServerConfigurationViewModel Configuration { get; set; }
|
||||
|
||||
private ConnStringFormat? _detectedFormat;
|
||||
public ConnStringFormat? DetectedFormat
|
||||
{
|
||||
get => _detectedFormat;
|
||||
private set => this.RaiseAndSetIfChanged(ref _detectedFormat, value);
|
||||
}
|
||||
// Connection string IO
|
||||
[Reactive] public partial string InputConnectionString { get; set; }
|
||||
|
||||
private ConnStringFormat _outputFormat = ConnStringFormat.Url;
|
||||
public ConnStringFormat OutputFormat
|
||||
{
|
||||
get => _outputFormat;
|
||||
set => this.RaiseAndSetIfChanged(ref _outputFormat, value);
|
||||
}
|
||||
[Reactive] public partial ForcedFormatOption ForcedFormat { get; set; }
|
||||
|
||||
private string _outputConnectionString = string.Empty;
|
||||
public string OutputConnectionString
|
||||
{
|
||||
get => _outputConnectionString;
|
||||
set => this.RaiseAndSetIfChanged(ref _outputConnectionString, value);
|
||||
}
|
||||
[ObservableAsProperty] private ConnStringFormat? _detectedFormat;
|
||||
[Reactive] public partial ConnStringFormat OutputFormat { get; set; }
|
||||
|
||||
[Reactive] public partial string OutputConnectionString { get; set; }
|
||||
|
||||
public ReactiveCommand<Unit, Unit> ParseConnectionStringCommand { get; }
|
||||
public ReactiveCommand<Unit, Unit> GenerateConnectionStringCommand { get; }
|
||||
public ReactiveCommand<Unit, Unit> CopyOutputConnectionStringCommand { get; }
|
||||
|
||||
public ReactiveCommand<Unit, Unit> SaveAndCloseCommand { get; }
|
||||
public ReactiveCommand<Unit, Unit> CloseCommand { get; }
|
||||
public ReactiveCommand<Unit, Unit> SaveCommand { get; }
|
||||
public ReactiveCommand<Unit, Unit> RevertCommand { get; }
|
||||
|
||||
private readonly IConnectionStringService _service;
|
||||
|
||||
public EditServerConfigurationViewModel()
|
||||
{
|
||||
|
|
@ -94,25 +54,31 @@ public class EditServerConfigurationViewModel : ViewModelBase
|
|||
GenerateConnectionStringCommand = ReactiveCommand.Create(GenerateConnectionString);
|
||||
CopyOutputConnectionStringCommand = ReactiveCommand.Create(() => { /* no-op placeholder */ });
|
||||
|
||||
SaveAndCloseCommand = ReactiveCommand.Create(() => { });
|
||||
CloseCommand = ReactiveCommand.Create(() => { });
|
||||
SaveCommand = ReactiveCommand.CreateFromTask(Save);
|
||||
RevertCommand = ReactiveCommand.CreateFromTask(Revert);
|
||||
|
||||
_detectedFormatHelper = this.WhenAnyValue(x => x.ForcedFormat, x => x.InputConnectionString,
|
||||
DetectFormat)
|
||||
.ToProperty(this, x => x.DetectedFormat);
|
||||
}
|
||||
|
||||
public EditServerConfigurationViewModel(ServerConfigurationViewModel configuration)
|
||||
: this()
|
||||
{
|
||||
Configuration = configuration;
|
||||
InitializeFromCopy();
|
||||
}
|
||||
|
||||
private void DetectFormat()
|
||||
private ConnStringFormat? DetectFormat(ForcedFormatOption format, string input)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(InputConnectionString))
|
||||
{
|
||||
DetectedFormat = null;
|
||||
return;
|
||||
}
|
||||
if (format != ForcedFormatOption.Auto)
|
||||
return null;
|
||||
|
||||
if (string.IsNullOrWhiteSpace(input))
|
||||
return null;
|
||||
|
||||
var res = _service.DetectFormat(InputConnectionString);
|
||||
DetectedFormat = res.IsSuccess ? res.Value : null;
|
||||
return res.IsSuccess ? res.Value : null;
|
||||
}
|
||||
|
||||
private void ParseConnectionString()
|
||||
|
|
@ -173,4 +139,73 @@ public class EditServerConfigurationViewModel : ViewModelBase
|
|||
if (r.IsSuccess)
|
||||
OutputConnectionString = r.Value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a deep copy of the configuration for editing.
|
||||
/// This ensures changes are isolated until Save is called.
|
||||
/// </summary>
|
||||
private void InitializeFromCopy()
|
||||
{
|
||||
_originalConfiguration = Configuration;
|
||||
|
||||
// Create a copy of the entity
|
||||
var copiedEntity = new ServerConfigurationEntity
|
||||
{
|
||||
Id = _originalConfiguration.Entity.Id,
|
||||
Name = _originalConfiguration.Entity.Name,
|
||||
Host = _originalConfiguration.Entity.Host,
|
||||
Port = _originalConfiguration.Entity.Port,
|
||||
InitialDatabase = _originalConfiguration.Entity.InitialDatabase,
|
||||
SslMode = _originalConfiguration.Entity.SslMode,
|
||||
ColorEnabled = _originalConfiguration.Entity.ColorEnabled,
|
||||
ColorArgb = _originalConfiguration.Entity.ColorArgb,
|
||||
UserName = _originalConfiguration.Entity.UserName,
|
||||
Password = _originalConfiguration.Entity.Password
|
||||
};
|
||||
|
||||
// Create a new ViewModel wrapping the copied entity
|
||||
Configuration = new ServerConfigurationViewModel(copiedEntity);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copies changes from the edited configuration back to the original.
|
||||
/// </summary>
|
||||
private async Task Save()
|
||||
{
|
||||
if (_originalConfiguration == null) return;
|
||||
|
||||
// Copy all properties from the edited configuration back to the original
|
||||
_originalConfiguration.Name = Configuration.Name;
|
||||
_originalConfiguration.Host = Configuration.Host;
|
||||
_originalConfiguration.Port = Configuration.Port;
|
||||
_originalConfiguration.InitialDatabase = Configuration.InitialDatabase;
|
||||
_originalConfiguration.DefaultSslMode = Configuration.DefaultSslMode;
|
||||
_originalConfiguration.ColorEnabled = Configuration.ColorEnabled;
|
||||
_originalConfiguration.Color = Configuration.Color;
|
||||
_originalConfiguration.UserName = Configuration.UserName;
|
||||
_originalConfiguration.Password = Configuration.Password;
|
||||
|
||||
await CloseInteraction.Handle(true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reverts to the original configuration, discarding all changes.
|
||||
/// </summary>
|
||||
private async Task Revert()
|
||||
{
|
||||
if (_originalConfiguration == null) return;
|
||||
|
||||
// Copy all properties from the original back to the working configuration
|
||||
Configuration.Name = _originalConfiguration.Name;
|
||||
Configuration.Host = _originalConfiguration.Host;
|
||||
Configuration.Port = _originalConfiguration.Port;
|
||||
Configuration.InitialDatabase = _originalConfiguration.InitialDatabase;
|
||||
Configuration.DefaultSslMode = _originalConfiguration.DefaultSslMode;
|
||||
Configuration.ColorEnabled = _originalConfiguration.ColorEnabled;
|
||||
Configuration.Color = _originalConfiguration.Color;
|
||||
Configuration.UserName = _originalConfiguration.UserName;
|
||||
Configuration.Password = _originalConfiguration.Password;
|
||||
|
||||
await CloseInteraction.Handle(false);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@
|
|||
<vm:EditServerConfigurationViewModel />
|
||||
</Design.DataContext>
|
||||
|
||||
<Grid Margin="12" RowDefinitions="Auto,Auto,Auto,Auto,Auto" ColumnDefinitions="*">
|
||||
<Grid Margin="12" RowDefinitions="Auto,Auto,Auto,Auto" ColumnDefinitions="*">
|
||||
<!-- Basic Details -->
|
||||
<StackPanel Grid.Row="0" Spacing="6">
|
||||
<TextBlock FontWeight="Bold" Text="Details" Margin="0,0,0,4"/>
|
||||
|
|
@ -93,6 +93,10 @@
|
|||
<TextBox TextWrapping="Wrap" AcceptsReturn="True" MinHeight="60" IsReadOnly="True" Text="{Binding OutputConnectionString}"/>
|
||||
</StackPanel>
|
||||
|
||||
<!-- Spacer / Future buttons row could go here -->
|
||||
<!-- Buttons Row -->
|
||||
<StackPanel Grid.Row="3" Orientation="Horizontal" Spacing="8" Margin="0,12,0,0" HorizontalAlignment="Right">
|
||||
<Button Content="Revert" Command="{Binding RevertCommand}" MinWidth="80"/>
|
||||
<Button Content="Save" Command="{Binding SaveCommand}" MinWidth="80"/>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Window>
|
||||
|
|
|
|||
|
|
@ -1,24 +1,38 @@
|
|||
using Avalonia;
|
||||
using System.Reactive.Disposables;
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Markup.Xaml;
|
||||
using Avalonia.ReactiveUI;
|
||||
using pgLabII.ViewModels;
|
||||
using ReactiveUI;
|
||||
|
||||
namespace pgLabII.Views;
|
||||
|
||||
public partial class EditServerConfigurationWindow : Window
|
||||
public partial class EditServerConfigurationWindow : ReactiveWindow<EditServerConfigurationWindow>
|
||||
{
|
||||
private readonly EditServerConfigurationViewModel _viewModel;
|
||||
public EditServerConfigurationWindow()
|
||||
: this(null)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public EditServerConfigurationWindow(EditServerConfigurationViewModel? viewModel)
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
DataContext = viewModel ?? new EditServerConfigurationViewModel(
|
||||
DataContext = _viewModel = viewModel ?? new EditServerConfigurationViewModel(
|
||||
new(new()));
|
||||
|
||||
this.WhenActivated(disposables =>
|
||||
{
|
||||
// Subscribe to the CloseInteraction
|
||||
_viewModel!.CloseInteraction.RegisterHandler(interaction =>
|
||||
{
|
||||
//DialogResult = interaction.Input; // true/false/null
|
||||
Close();
|
||||
interaction.SetOutput(true);
|
||||
}).DisposeWith(disposables);
|
||||
});
|
||||
}
|
||||
|
||||
public bool New { get; set; }
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
<TargetFramework>net9.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<AvaloniaUseCompiledBindingsByDefault>true</AvaloniaUseCompiledBindingsByDefault>
|
||||
<Platforms>AnyCPU;x64</Platforms>
|
||||
</PropertyGroup>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue