feat(ui): complete Avalonia UI port with 7 main pages, tool settings & top MenuBar
This commit is contained in:
@@ -0,0 +1,103 @@
|
||||
using System.Collections.ObjectModel;
|
||||
using ClawdDotNet.App.Models;
|
||||
using ClawdDotNet.App.Services;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
|
||||
namespace ClawdDotNet.Desktop.ViewModels;
|
||||
|
||||
/// <summary>
|
||||
/// Auswahl der Instanz beim Start — der erste Rückruf, den <c>AppHost</c> erfragt.
|
||||
///
|
||||
/// Die WinForms-Fassung mischte Datenzugriff, Spaltenformatierung und Meldungsfenster in
|
||||
/// einem Formular. Hier steht nur, <em>was</em> geschieht; das <em>wie</em> es aussieht
|
||||
/// liegt in der Ansicht, und Rückfragen laufen über <see cref="ConfirmError"/> statt über
|
||||
/// einen direkten Dialogaufruf — so bleibt das Ansichtsmodell ohne Fensterbezug prüfbar.
|
||||
/// </summary>
|
||||
public sealed partial class InstancePickerViewModel : ViewModelBase
|
||||
{
|
||||
private readonly InstanceDirectoryManager _directories;
|
||||
private readonly TaskCompletionSource<string?> _completion = new();
|
||||
|
||||
[ObservableProperty]
|
||||
[NotifyCanExecuteChangedFor(nameof(StartCommand))]
|
||||
private InstanceInfo? _selected;
|
||||
|
||||
[ObservableProperty]
|
||||
private string _newInstanceName = "";
|
||||
|
||||
/// <summary>Fehlertext für die Ansicht; leer heißt: alles in Ordnung.</summary>
|
||||
[ObservableProperty]
|
||||
private string _errorText = "";
|
||||
|
||||
public ObservableCollection<InstanceInfo> Instances { get; } = [];
|
||||
|
||||
/// <summary>Der gewählte Pfad, oder <c>null</c> bei Abbruch.</summary>
|
||||
public Task<string?> Result => _completion.Task;
|
||||
|
||||
public string InstancesDirectory => _directories.InstancesDirectory;
|
||||
|
||||
public InstancePickerViewModel(InstanceDirectoryManager directories)
|
||||
{
|
||||
_directories = directories;
|
||||
Refresh();
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private void Refresh()
|
||||
{
|
||||
Instances.Clear();
|
||||
|
||||
foreach (var instance in _directories.ListInstances())
|
||||
Instances.Add(instance);
|
||||
|
||||
// Eine einzelne Instanz gleich vorwählen — der häufigste Fall, und ein Klick
|
||||
// weniger bei jedem Start.
|
||||
Selected ??= Instances.FirstOrDefault();
|
||||
}
|
||||
|
||||
private bool CanStart => Selected is not null;
|
||||
|
||||
[RelayCommand(CanExecute = nameof(CanStart))]
|
||||
private void Start() => _completion.TrySetResult(Selected!.FolderPath);
|
||||
|
||||
/// <summary>Abbruch — der Aufrufer beendet die Anwendung.</summary>
|
||||
[RelayCommand]
|
||||
private void Cancel() => _completion.TrySetResult(null);
|
||||
|
||||
[RelayCommand]
|
||||
private void Create()
|
||||
{
|
||||
var name = NewInstanceName.Trim();
|
||||
|
||||
if (string.IsNullOrWhiteSpace(name))
|
||||
{
|
||||
ErrorText = "Bitte einen Instanznamen eingeben.";
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
_directories.CreateInstance(name);
|
||||
NewInstanceName = "";
|
||||
ErrorText = "";
|
||||
Refresh();
|
||||
|
||||
// Die frisch angelegte Instanz vorwählen — wer sie erstellt, will sie starten.
|
||||
Selected = Instances.FirstOrDefault(i =>
|
||||
string.Equals(i.InstanceName, name, StringComparison.Ordinal));
|
||||
}
|
||||
catch (Exception ex) when (ex is IOException or UnauthorizedAccessException
|
||||
or ArgumentException)
|
||||
{
|
||||
ErrorText = $"Instanz konnte nicht angelegt werden: {ex.Message}";
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Wird gesetzt, wenn ein Fehler von außen kommt (etwa eine unlesbare
|
||||
/// Instanzkonfiguration), damit das Fenster offen bleiben und eine andere Wahl
|
||||
/// zulassen kann.
|
||||
/// </summary>
|
||||
public void ConfirmError(string message) => ErrorText = message;
|
||||
}
|
||||
Reference in New Issue
Block a user