Kontext: src/ClaudeDo.Ui/ViewModels/Islands/DetailsIslandViewModel.cs ist mit 1431 Zeilen ein God-VM mit ~12 Concerns (Log-Streaming, Titel/Description-Editing, Subtasks, Child-Outcomes, Merge-Preview/-Targets, Diff, Agent-Settings-Overrides, Notes-Mode, Prep-Mode, Tabs, Session-Outcome/Roadblocks, Worktree-Info). Jedes neue Feature landet dort. Änderungen — drei klar abgrenzbare Sektionen als ei ClaudeDo-Task: 483e419f-1ec8-46ba-986b-8b90d6596b49
103 lines
3.2 KiB
C#
103 lines
3.2 KiB
C#
using System.Collections.ObjectModel;
|
|
using System.Text;
|
|
using CommunityToolkit.Mvvm.ComponentModel;
|
|
using CommunityToolkit.Mvvm.Input;
|
|
using ClaudeDo.Ui.Helpers;
|
|
using ClaudeDo.Ui.Services;
|
|
|
|
namespace ClaudeDo.Ui.ViewModels.Islands;
|
|
|
|
public sealed partial class PrepPanelViewModel : ViewModelBase, IDisposable
|
|
{
|
|
private readonly IWorkerClient _worker;
|
|
private readonly StreamLineFormatter _formatter = new();
|
|
private readonly StringBuilder _prepClaudeBuf = new();
|
|
|
|
private readonly Action _onPrepStartedHandler;
|
|
private readonly Action<string> _onPrepLineHandler;
|
|
private readonly Action<bool> _onPrepFinishedHandler;
|
|
|
|
[ObservableProperty] private bool _isPrepRunning;
|
|
|
|
public ObservableCollection<LogLineViewModel> PrepLog { get; } = new();
|
|
|
|
public bool ShowPrepEmptyState => !IsPrepRunning && PrepLog.Count == 0;
|
|
|
|
partial void OnIsPrepRunningChanged(bool value) => OnPropertyChanged(nameof(ShowPrepEmptyState));
|
|
|
|
public PrepPanelViewModel(IWorkerClient worker)
|
|
{
|
|
_worker = worker;
|
|
_onPrepStartedHandler = OnPrepStarted;
|
|
_onPrepLineHandler = OnPrepLine;
|
|
_onPrepFinishedHandler = OnPrepFinished;
|
|
|
|
_worker.PrepStartedEvent += _onPrepStartedHandler;
|
|
_worker.PrepLineEvent += _onPrepLineHandler;
|
|
_worker.PrepFinishedEvent += _onPrepFinishedHandler;
|
|
|
|
PrepLog.CollectionChanged += (_, _) => OnPropertyChanged(nameof(ShowPrepEmptyState));
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
_worker.PrepStartedEvent -= _onPrepStartedHandler;
|
|
_worker.PrepLineEvent -= _onPrepLineHandler;
|
|
_worker.PrepFinishedEvent -= _onPrepFinishedHandler;
|
|
}
|
|
|
|
[RelayCommand]
|
|
private async System.Threading.Tasks.Task PlanDayAsync()
|
|
{
|
|
try { await _worker.RunDailyPrepNowAsync(); }
|
|
catch { }
|
|
}
|
|
|
|
public async System.Threading.Tasks.Task LoadLastPrepLogIfEmptyAsync()
|
|
{
|
|
if (IsPrepRunning || PrepLog.Count > 0) return;
|
|
string text;
|
|
try { text = await _worker.GetLastPrepLogAsync(); }
|
|
catch { return; }
|
|
if (IsPrepRunning || PrepLog.Count > 0) return;
|
|
foreach (var line in text.Split('\n'))
|
|
{
|
|
var trimmed = line.TrimEnd('\r');
|
|
if (trimmed.Length > 0) AppendStdoutLine(trimmed);
|
|
}
|
|
}
|
|
|
|
private void OnPrepStarted()
|
|
{
|
|
PrepLog.Clear();
|
|
IsPrepRunning = true;
|
|
}
|
|
|
|
private void OnPrepLine(string line) => AppendStdoutLine(line);
|
|
|
|
private void OnPrepFinished(bool success) => IsPrepRunning = false;
|
|
|
|
private void AppendStdoutLine(string line)
|
|
{
|
|
var formatted = _formatter.FormatLine(line);
|
|
if (formatted is null) return;
|
|
AppendClaudeText(formatted);
|
|
}
|
|
|
|
private void AppendClaudeText(string chunk)
|
|
{
|
|
_prepClaudeBuf.Append(chunk);
|
|
while (true)
|
|
{
|
|
var text = _prepClaudeBuf.ToString();
|
|
var nl = text.IndexOf('\n');
|
|
if (nl < 0) break;
|
|
var piece = text[..nl].TrimEnd('\r');
|
|
if (!string.IsNullOrWhiteSpace(piece))
|
|
PrepLog.Add(new LogLineViewModel { Kind = LogKind.Claude, Text = piece });
|
|
_prepClaudeBuf.Clear();
|
|
_prepClaudeBuf.Append(text[(nl + 1)..]);
|
|
}
|
|
}
|
|
}
|