[Phase48] 대형 파일 분할 리팩터링 4차 — 4개 신규 파셜 파일 생성
## 분할 대상 및 결과 ### ChatWindow.Controls.cs (595줄 → 372줄) - ChatWindow.TabSwitching.cs (232줄, 신규): _activeTab 필드, _tabConversationId 필드 TabChat/Cowork/Code_Checked, UpdateTabUI, BtnPlanMode_Click, UpdatePlanModeUI, SwitchToTabConversation, SaveCurrentTabConversationId, StopStreamingIfActive ### ChatWindow.SlashCommands.cs (579줄 → 406줄) - ChatWindow.DropActions.cs (160줄, 신규): DropActions 딕셔너리, CodeExtensions, DataExtensions, _dropActionPopup 필드, ShowDropActionMenu() 메서드 ### WorkflowAnalyzerWindow.Charts.cs (667줄 → 397줄) - WorkflowAnalyzerWindow.Timeline.cs (281줄, 신규): CreateTimelineNode, GetEventVisual, CreateBadge, ShowDetail, UpdateSummaryCards, FormatMs, Truncate, 윈도우 이벤트 핸들러, WndProc ### SkillGalleryWindow.xaml.cs (631줄 → ~430줄) - SkillGalleryWindow.SkillDetail.cs (197줄, 신규): ShowSkillDetail() 메서드 전체 (스킬 상세 보기 팝업 — 메타정보·프롬프트 미리보기·Action 버튼) ## 빌드 결과: 경고 0, 오류 0 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -369,227 +369,4 @@ public partial class ChatWindow
|
||||
MaximizeIcon.Text = WindowState == WindowState.Maximized ? "\uE923" : "\uE739"; // 복원/최대화 아이콘
|
||||
}
|
||||
private void BtnClose_Click(object sender, RoutedEventArgs e) => Close();
|
||||
|
||||
// ─── 탭 전환 ──────────────────────────────────────────────────────────
|
||||
|
||||
private string _activeTab = "Chat";
|
||||
|
||||
private void SaveCurrentTabConversationId()
|
||||
{
|
||||
lock (_convLock)
|
||||
{
|
||||
if (_currentConversation != null && _currentConversation.Messages.Count > 0)
|
||||
{
|
||||
_tabConversationId[_activeTab] = _currentConversation.Id;
|
||||
// 탭 전환 시 현재 대화를 즉시 저장 (스트리밍 중이어도 진행 중인 내용 보존)
|
||||
try { _storage.Save(_currentConversation); } catch (Exception) { /* 대화 저장 실패 — UI 차단 방지 */ }
|
||||
}
|
||||
}
|
||||
// 탭별 마지막 대화 ID를 설정에 영속 저장 (앱 재시작 시 복원용)
|
||||
SaveLastConversations();
|
||||
}
|
||||
|
||||
/// <summary>탭 전환 전 스트리밍 중이면 즉시 중단합니다.</summary>
|
||||
private void StopStreamingIfActive()
|
||||
{
|
||||
if (!_isStreaming) return;
|
||||
// 스트리밍 중단
|
||||
_streamCts?.Cancel();
|
||||
_cursorTimer.Stop();
|
||||
_elapsedTimer.Stop();
|
||||
_typingTimer.Stop();
|
||||
StopRainbowGlow();
|
||||
HideStickyProgress();
|
||||
_activeStreamText = null;
|
||||
_elapsedLabel = null;
|
||||
_cachedStreamContent = "";
|
||||
_isStreaming = false;
|
||||
BtnSend.IsEnabled = true;
|
||||
BtnStop.Visibility = Visibility.Collapsed;
|
||||
BtnPause.Visibility = Visibility.Collapsed;
|
||||
PauseIcon.Text = "\uE769"; // 리셋
|
||||
BtnSend.Visibility = Visibility.Visible;
|
||||
_streamCts?.Dispose();
|
||||
_streamCts = null;
|
||||
SetStatusIdle();
|
||||
}
|
||||
|
||||
private void TabChat_Checked(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (_activeTab == "Chat") return;
|
||||
StopStreamingIfActive();
|
||||
SaveCurrentTabConversationId();
|
||||
_activeTab = "Chat";
|
||||
_selectedCategory = ""; UpdateCategoryLabel();
|
||||
UpdateTabUI();
|
||||
UpdatePlanModeUI();
|
||||
}
|
||||
|
||||
private void TabCowork_Checked(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (_activeTab == "Cowork") return;
|
||||
StopStreamingIfActive();
|
||||
SaveCurrentTabConversationId();
|
||||
_activeTab = "Cowork";
|
||||
_selectedCategory = ""; UpdateCategoryLabel();
|
||||
UpdateTabUI();
|
||||
UpdatePlanModeUI();
|
||||
}
|
||||
|
||||
private void TabCode_Checked(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (_activeTab == "Code") return;
|
||||
StopStreamingIfActive();
|
||||
SaveCurrentTabConversationId();
|
||||
_activeTab = "Code";
|
||||
_selectedCategory = ""; UpdateCategoryLabel();
|
||||
UpdateTabUI();
|
||||
UpdatePlanModeUI();
|
||||
}
|
||||
|
||||
/// <summary>탭별로 마지막으로 활성화된 대화 ID를 기억.</summary>
|
||||
private readonly Dictionary<string, string?> _tabConversationId = new()
|
||||
{
|
||||
["Chat"] = null, ["Cowork"] = null, ["Code"] = null,
|
||||
};
|
||||
|
||||
private void UpdateTabUI()
|
||||
{
|
||||
// 폴더 바는 Cowork/Code 탭에서만 표시
|
||||
if (FolderBar != null)
|
||||
FolderBar.Visibility = _activeTab != "Chat" ? Visibility.Visible : Visibility.Collapsed;
|
||||
|
||||
// 탭별 입력 안내 문구
|
||||
if (InputWatermark != null)
|
||||
{
|
||||
InputWatermark.Text = _activeTab switch
|
||||
{
|
||||
"Cowork" => "에이전트에게 작업을 요청하세요 (파일 읽기/쓰기, 문서 생성...)",
|
||||
"Code" => "코드 관련 작업을 요청하세요...",
|
||||
_ => _promptCardPlaceholder,
|
||||
};
|
||||
}
|
||||
|
||||
// 권한 기본값 적용 (Cowork/Code 탭은 설정의 기본값 사용)
|
||||
ApplyTabDefaultPermission();
|
||||
|
||||
// 포맷/디자인 드롭다운은 Cowork 탭에서만 표시
|
||||
if (_activeTab == "Cowork")
|
||||
{
|
||||
BuildBottomBar();
|
||||
if (Llm.ShowFileBrowser && FileBrowserPanel != null)
|
||||
{
|
||||
FileBrowserPanel.Visibility = Visibility.Visible;
|
||||
BuildFileTree();
|
||||
}
|
||||
}
|
||||
else if (_activeTab == "Code")
|
||||
{
|
||||
// Code 탭: 언어 선택기 + 파일 탐색기
|
||||
BuildCodeBottomBar();
|
||||
if (Llm.ShowFileBrowser && FileBrowserPanel != null)
|
||||
{
|
||||
FileBrowserPanel.Visibility = Visibility.Visible;
|
||||
BuildFileTree();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
MoodIconPanel.Children.Clear();
|
||||
if (FormatMoodSeparator != null) FormatMoodSeparator.Visibility = Visibility.Collapsed;
|
||||
if (FileBrowserPanel != null) FileBrowserPanel.Visibility = Visibility.Collapsed;
|
||||
}
|
||||
|
||||
// 탭별 프리셋 버튼 재구성
|
||||
BuildTopicButtons();
|
||||
|
||||
// 현재 대화를 해당 탭 대화로 전환
|
||||
SwitchToTabConversation();
|
||||
|
||||
// Cowork/Code 탭 전환 시 팁 표시
|
||||
ShowRandomTip();
|
||||
}
|
||||
|
||||
private void BtnPlanMode_Click(object sender, System.Windows.Input.MouseButtonEventArgs e)
|
||||
{
|
||||
// 3단 순환: off → auto → always → off
|
||||
Llm.PlanMode = Llm.PlanMode switch
|
||||
{
|
||||
"auto" => "always",
|
||||
"always" => "off",
|
||||
_ => "auto"
|
||||
};
|
||||
_settings.Save();
|
||||
UpdatePlanModeUI();
|
||||
}
|
||||
|
||||
private void UpdatePlanModeUI()
|
||||
{
|
||||
var planMode = Llm.PlanMode ?? "off";
|
||||
if (PlanModeValue == null) return;
|
||||
|
||||
PlanModeValue.Text = planMode switch
|
||||
{
|
||||
"auto" => "Auto",
|
||||
"always" => "Always",
|
||||
_ => "Off"
|
||||
};
|
||||
var isActive = planMode != "off";
|
||||
var activeBrush = ThemeResourceHelper.Accent(this);
|
||||
var secondaryBrush = ThemeResourceHelper.Secondary(this);
|
||||
if (PlanModeIcon != null) PlanModeIcon.Foreground = isActive ? activeBrush : secondaryBrush;
|
||||
if (PlanModeLabel != null) PlanModeLabel.Foreground = isActive ? activeBrush : secondaryBrush;
|
||||
if (BtnPlanMode != null)
|
||||
BtnPlanMode.Background = isActive
|
||||
? new SolidColorBrush(Color.FromArgb(0x1A, 0x4B, 0x5E, 0xFC))
|
||||
: Brushes.Transparent;
|
||||
}
|
||||
|
||||
private void SwitchToTabConversation()
|
||||
{
|
||||
// 이전 탭의 대화 저장
|
||||
lock (_convLock)
|
||||
{
|
||||
if (_currentConversation != null && _currentConversation.Messages.Count > 0)
|
||||
{
|
||||
try { _storage.Save(_currentConversation); } catch (Exception) { /* 대화 저장 실패 — UI 차단 방지 */ }
|
||||
}
|
||||
}
|
||||
|
||||
// 현재 탭에 기억된 대화가 있으면 복원
|
||||
var savedId = _tabConversationId.GetValueOrDefault(_activeTab);
|
||||
if (!string.IsNullOrEmpty(savedId))
|
||||
{
|
||||
var conv = _storage.Load(savedId);
|
||||
if (conv != null)
|
||||
{
|
||||
if (string.IsNullOrEmpty(conv.Tab)) conv.Tab = _activeTab;
|
||||
lock (_convLock) _currentConversation = conv;
|
||||
MessagePanel.Children.Clear();
|
||||
foreach (var msg in conv.Messages)
|
||||
AddMessageBubble(msg.Role, msg.Content, animate: false, message: msg);
|
||||
EmptyState.Visibility = conv.Messages.Count > 0 ? Visibility.Collapsed : Visibility.Visible;
|
||||
UpdateChatTitle();
|
||||
RefreshConversationList();
|
||||
UpdateFolderBar();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// 기억된 대화가 없으면 새 대화
|
||||
lock (_convLock)
|
||||
{
|
||||
_currentConversation = new ChatConversation { Tab = _activeTab };
|
||||
var workFolder = Llm.WorkFolder;
|
||||
if (!string.IsNullOrEmpty(workFolder) && _activeTab != "Chat")
|
||||
_currentConversation.WorkFolder = workFolder;
|
||||
}
|
||||
MessagePanel.Children.Clear();
|
||||
EmptyState.Visibility = Visibility.Visible;
|
||||
_attachedFiles.Clear();
|
||||
RefreshAttachedFilesUI();
|
||||
UpdateChatTitle();
|
||||
RefreshConversationList();
|
||||
UpdateFolderBar();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user