using System; using System.Threading.Tasks; using Avalonia; using Avalonia.Controls; using Avalonia.Layout; using Avalonia.Media; using ClaudeDo.Ui.Services; using ClaudeDo.Ui.ViewModels; using ClaudeDo.Ui.ViewModels.Conflicts; using ClaudeDo.Ui.ViewModels.Islands; using ClaudeDo.Ui.ViewModels.Modals; using ClaudeDo.Ui.Views.Conflicts; using ClaudeDo.Ui.Views.MissionControl; using ClaudeDo.Ui.Views.Modals; namespace ClaudeDo.Ui.Views; /// /// Window-backed . Owns every modal-view construction, the /// shared Confirm/Error dialogs, and the worktrees-overview sub-callbacks that reach back /// into the shell (jump-to-task, merge, conflict resolution). Created by /// with itself as the owner window; the shell resolves lazily from the owner's DataContext so /// the service and shell don't form a construction cycle. /// public sealed class WindowDialogService : IDialogService { private readonly Window _owner; private MissionControlWindow? _missionControl; public WindowDialogService(Window owner) => _owner = owner; private IslandsShellViewModel? Shell => _owner.DataContext as IslandsShellViewModel; public async Task ShowAboutAsync(AboutModalViewModel vm) { var dlg = new AboutModalView { DataContext = vm }; vm.CloseAction = () => dlg.Close(); await dlg.ShowDialog(_owner); } public async Task ShowWeeklyReportAsync(WeeklyReportModalViewModel vm) { var dlg = new WeeklyReportModalView { DataContext = vm }; vm.CloseAction = () => dlg.Close(); await dlg.ShowDialog(_owner); } public async Task ShowSettingsAsync(SettingsModalViewModel vm) { var dlg = new SettingsModalView { DataContext = vm }; await dlg.ShowDialog(_owner); } public async Task ShowListSettingsAsync(ListSettingsModalViewModel vm) { var dlg = new ListSettingsModalView { DataContext = vm }; vm.CloseAction = () => dlg.Close(); vm.ConfirmAsync = ConfirmAsync; vm.ShowErrorAsync = ShowErrorAsync; await dlg.ShowDialog(_owner); } public async Task ShowRepoImportAsync(RepoImportModalViewModel vm) { var dlg = new RepoImportModalView { DataContext = vm }; vm.CloseAction = () => dlg.Close(); await dlg.ShowDialog(_owner); } public async Task ShowWorktreesOverviewAsync(WorktreesOverviewModalViewModel vm) { var dlg = new WorktreesOverviewModalView { DataContext = vm }; vm.CloseAction = () => dlg.Close(); vm.JumpToTaskAction = (listId, taskId) => { if (Shell is { } s) _ = JumpToTaskHelper.SelectAsync(s, listId, taskId); }; vm.ShowDiffAction = diffVm => { var diffDlg = new DiffViewerView { DataContext = diffVm }; diffVm.CloseAction = () => diffDlg.Close(); _ = diffVm.LoadAsync(); _ = diffDlg.ShowDialog(_owner); }; vm.ConfirmAction = ConfirmAsync; if (Shell is { } shell) { vm.ResolveMergeVm = shell.ResolveMergeVm; vm.ShowMergeAction = async mergeVm => { var mergeDlg = new MergeModalView { DataContext = mergeVm }; await mergeDlg.ShowDialog(_owner); }; } await dlg.ShowDialog(_owner); } public async Task ShowWorkerConnectionAsync(WorkerConnectionModalViewModel vm) { var dlg = new WorkerConnectionModalView { DataContext = vm }; vm.CloseAction = () => dlg.Close(); await dlg.ShowDialog(_owner); } public async Task ShowConflictResolverAsync(ConflictResolverViewModel vm) { var dlg = new ConflictResolverView { DataContext = vm }; await dlg.ShowDialog(_owner); } public async Task ShowLogVisualizerAsync(LogVisualizerViewModel vm) { var dlg = new LogVisualizerView { DataContext = vm }; vm.CloseAction = () => dlg.Close(); await dlg.ShowDialog(_owner); } public void ShowMissionControl(MissionControlViewModel vm) { _missionControl ??= new MissionControlWindow { DataContext = vm }; if (!_missionControl.IsVisible) _missionControl.Show(); // modeless, independent top-level window _missionControl.Activate(); // bring to front / focus } public void ShowDetachedMonitor(TaskMonitorViewModel monitor, Action onClosed) { var win = new TaskMonitorWindow { DataContext = monitor }; win.Closed += (_, _) => onClosed(); // closing re-docks into the grid win.Show(); // modeless, independent } public Task ConfirmAsync(string message) { var tcs = new TaskCompletionSource(); var cancel = new Button { Content = "Cancel", MinWidth = 90 }; var confirm = new Button { Content = "Confirm", MinWidth = 90, Classes = { "danger" } }; var dialog = NoticeWindow("Confirm", 380, message, new StackPanel { Orientation = Orientation.Horizontal, HorizontalAlignment = HorizontalAlignment.Right, Spacing = 8, Children = { cancel, confirm }, }); cancel.Click += (_, _) => { tcs.TrySetResult(false); dialog.Close(); }; confirm.Click += (_, _) => { tcs.TrySetResult(true); dialog.Close(); }; dialog.Closed += (_, _) => tcs.TrySetResult(false); _ = dialog.ShowDialog(_owner); return tcs.Task; } public Task ShowErrorAsync(string message) { var ok = new Button { Content = "OK", MinWidth = 90 }; var dialog = NoticeWindow("Error", 360, message, new StackPanel { Orientation = Orientation.Horizontal, HorizontalAlignment = HorizontalAlignment.Right, Spacing = 8, Children = { ok }, }); ok.Click += (_, _) => dialog.Close(); return dialog.ShowDialog(_owner); } private Window NoticeWindow(string title, double width, string message, StackPanel buttons) => new() { Title = title, Width = width, SizeToContent = SizeToContent.Height, CanResize = false, WindowStartupLocation = WindowStartupLocation.CenterOwner, ShowInTaskbar = false, Background = _owner.FindResource("SurfaceBrush") as IBrush, Content = new StackPanel { Margin = new Thickness(20), Spacing = 16, Children = { new TextBlock { Text = message, TextWrapping = TextWrapping.Wrap }, buttons, }, }, }; }