AX Agent 진행 시간 표기와 글로우 설정 위치를 정리한다\n\n- Cowork/Code 진행 카드에서 스트리밍 시작 시각이 준비되기 전 계산되며 수천만 시간으로 튀는 문제를 수정한다\n- 진행 카드 라이브 대기 색상을 테마 AccentColor 기반으로 조정해 주황색 고정 느낌을 제거한다\n- 채팅 입력창 글로우를 런처와 같은 리듬의 무지개 글로우로 완화하고 외곽선 두께와 블러를 정리한다\n- 일반 설정의 런처/채팅 글로우 토글을 제거하고 AX Agent 내부 설정 공통 탭으로 이동한다\n- README와 DEVELOPMENT 문서에 변경 내용과 시각을 반영한다\n\n검증 결과\n- dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\\verify\\ -p:IntermediateOutputPath=obj\\verify\\\n- 경고 0 / 오류 0
This commit is contained in:
@@ -1448,3 +1448,7 @@ MIT License
|
|||||||
|
|
||||||
- 업데이트: 2026-04-07 02:11 (KST)
|
- 업데이트: 2026-04-07 02:11 (KST)
|
||||||
- AX Agent 내부 설정 공통 탭의 Gemini/Claude API 키 입력 필드를 PasswordBox에서 TextBox로 교체해, 오버레이 동기화 중에도 입력이 끊기거나 튕기지 않도록 수정했습니다.
|
- AX Agent 내부 설정 공통 탭의 Gemini/Claude API 키 입력 필드를 PasswordBox에서 TextBox로 교체해, 오버레이 동기화 중에도 입력이 끊기거나 튕기지 않도록 수정했습니다.
|
||||||
|
- 업데이트: 2026-04-07 02:45 (KST)
|
||||||
|
- Cowork/Code 진행 카드의 경과 시간 계산을 보정했습니다. 스트리밍 시작 시각이 준비되기 전에 진행 힌트가 먼저 그려질 때 `수천만 시간`처럼 비정상값이 표시되던 문제를 막고, 6시간을 넘는 비현실적인 경과 시간은 자동 무시하도록 정리했습니다.
|
||||||
|
- AX Agent 입력창 글로우를 런처와 같은 리듬의 무지개 글로우로 다시 맞췄습니다. 글로우 외곽선 두께와 블러를 부드럽게 조정하고, 라이브 진행 카드도 테마 AccentColor 기반의 은은한 톤을 써서 주황색 고정 느낌을 줄였습니다.
|
||||||
|
- 일반 설정에 있던 `런처 무지개 글로우`, `선택 아이템 글로우`, `채팅 입력창 무지개 글로우`를 AX Agent 내부 설정으로 이동해, 이제 내부 설정에서 바로 런처/입력창 글로우를 함께 조정할 수 있습니다.
|
||||||
|
|||||||
@@ -5287,3 +5287,18 @@ ow + toggle ?쒓컖 ?몄뼱濡??ㅼ떆 ?뺣젹?덈떎.
|
|||||||
- Document update: 2026-04-07 02:23 (KST) - Reconnected the AX Agent direct-chat execution path to the existing SSE/streaming transport in `LlmService`. Chat replies no longer wait for the final full string before rendering; when streaming is enabled they now advance through the existing streaming container and typing-timer path.
|
- Document update: 2026-04-07 02:23 (KST) - Reconnected the AX Agent direct-chat execution path to the existing SSE/streaming transport in `LlmService`. Chat replies no longer wait for the final full string before rendering; when streaming is enabled they now advance through the existing streaming container and typing-timer path.
|
||||||
- Document update: 2026-04-07 02:23 (KST) - Updated `AxAgentExecutionEngine.ResolveExecutionMode()` so non-agent chat can opt into streaming transport, and wired `ChatWindow.ExecutePreparedTurnAsync()` to consume `LlmService.StreamAsync(...)` for direct conversations while keeping Cowork/Code on the agent-loop progress-feed path.
|
- Document update: 2026-04-07 02:23 (KST) - Updated `AxAgentExecutionEngine.ResolveExecutionMode()` so non-agent chat can opt into streaming transport, and wired `ChatWindow.ExecutePreparedTurnAsync()` to consume `LlmService.StreamAsync(...)` for direct conversations while keeping Cowork/Code on the agent-loop progress-feed path.
|
||||||
- Document update: 2026-04-07 02:31 (KST) - Added a typed final-response preview for Cowork/Code agent-loop completions. Those tabs still use progress-feed execution during the loop, but once a final assistant answer is available it now passes through the same streaming container/typing presentation before the final transcript message is committed.
|
- Document update: 2026-04-07 02:31 (KST) - Added a typed final-response preview for Cowork/Code agent-loop completions. Those tabs still use progress-feed execution during the loop, but once a final assistant answer is available it now passes through the same streaming container/typing presentation before the final transcript message is committed.
|
||||||
|
|
||||||
|
## 2026-04-07 02:45 (KST)
|
||||||
|
|
||||||
|
- [ChatWindow.xaml.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Views/ChatWindow.xaml.cs)
|
||||||
|
- Cowork/Code 실행 시작 시 `_streamStartTime`을 라이브 진행 힌트보다 먼저 설정하도록 순서를 조정했다.
|
||||||
|
- 유효한 시작 시각이 없을 때는 진행 힌트 경과 시간을 계산하지 않도록 막아 `수천만 시간` 같은 비정상 표시를 방지했다.
|
||||||
|
- 내부 설정 저장 시 `EnableChatRainbowGlow`, `Launcher.EnableRainbowGlow`, `Launcher.EnableSelectionGlow`도 함께 반영되도록 연결했다.
|
||||||
|
- [ChatWindow.AgentEventRendering.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Views/ChatWindow.AgentEventRendering.cs)
|
||||||
|
- 진행 카드 메타에 쓰는 경과 시간을 6시간 상한으로 정규화해 비정상값을 자동 무시하도록 했다.
|
||||||
|
- 라이브 대기 카드와 진행 줄 배경을 고정 주황색 대신 테마 AccentColor 기반 반투명 톤으로 교체했다.
|
||||||
|
- [ChatWindow.xaml](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Views/ChatWindow.xaml)
|
||||||
|
- 입력창 글로우 외곽선의 두께와 블러를 완화해 런처 글로우와 더 비슷한 질감으로 조정했다.
|
||||||
|
- AX Agent 내부 설정 공통 탭에 `글로우 효과` 섹션을 추가해 런처 무지개 글로우, 런처 선택 글로우, 채팅 입력창 글로우를 내부 설정에서 바로 조정할 수 있게 했다.
|
||||||
|
- [SettingsWindow.xaml](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Views/SettingsWindow.xaml)
|
||||||
|
- 일반 설정 테마 섹션에 있던 런처/채팅 글로우 토글 3종을 제거해 AX Agent 내부 설정으로 UI를 일원화했다.
|
||||||
|
|||||||
@@ -10,6 +10,22 @@ namespace AxCopilot.Views;
|
|||||||
|
|
||||||
public partial class ChatWindow
|
public partial class ChatWindow
|
||||||
{
|
{
|
||||||
|
private static Color ResolveLiveProgressAccentColor(Brush accentBrush)
|
||||||
|
{
|
||||||
|
return accentBrush is SolidColorBrush solid
|
||||||
|
? solid.Color
|
||||||
|
: Color.FromRgb(0x59, 0xA5, 0xF5);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static long NormalizeProgressElapsedMs(long elapsedMs)
|
||||||
|
{
|
||||||
|
if (elapsedMs <= 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
var maxReasonableElapsed = (long)TimeSpan.FromHours(6).TotalMilliseconds;
|
||||||
|
return elapsedMs > maxReasonableElapsed ? 0 : elapsedMs;
|
||||||
|
}
|
||||||
|
|
||||||
private Border CreateCompactEventPill(
|
private Border CreateCompactEventPill(
|
||||||
string summary,
|
string summary,
|
||||||
Brush primaryText,
|
Brush primaryText,
|
||||||
@@ -20,13 +36,14 @@ public partial class ChatWindow
|
|||||||
string? metaText = null,
|
string? metaText = null,
|
||||||
bool liveWaitingStyle = false)
|
bool liveWaitingStyle = false)
|
||||||
{
|
{
|
||||||
|
var liveAccentColor = ResolveLiveProgressAccentColor(accentBrush);
|
||||||
return new Border
|
return new Border
|
||||||
{
|
{
|
||||||
Background = liveWaitingStyle
|
Background = liveWaitingStyle
|
||||||
? new SolidColorBrush(Color.FromArgb(0x20, 0xF5, 0x73, 0x16))
|
? new SolidColorBrush(Color.FromArgb(0x16, liveAccentColor.R, liveAccentColor.G, liveAccentColor.B))
|
||||||
: hintBg,
|
: hintBg,
|
||||||
BorderBrush = liveWaitingStyle
|
BorderBrush = liveWaitingStyle
|
||||||
? new SolidColorBrush(Color.FromArgb(0x4D, 0xF5, 0x73, 0x16))
|
? new SolidColorBrush(Color.FromArgb(0x46, liveAccentColor.R, liveAccentColor.G, liveAccentColor.B))
|
||||||
: borderBrush,
|
: borderBrush,
|
||||||
BorderThickness = new Thickness(1),
|
BorderThickness = new Thickness(1),
|
||||||
CornerRadius = new CornerRadius(10),
|
CornerRadius = new CornerRadius(10),
|
||||||
@@ -267,9 +284,10 @@ public partial class ChatWindow
|
|||||||
{
|
{
|
||||||
var parts = new List<string>();
|
var parts = new List<string>();
|
||||||
|
|
||||||
if (evt.ElapsedMs > 0)
|
var normalizedElapsedMs = NormalizeProgressElapsedMs(evt.ElapsedMs);
|
||||||
|
if (normalizedElapsedMs > 0)
|
||||||
{
|
{
|
||||||
var elapsed = TimeSpan.FromMilliseconds(evt.ElapsedMs);
|
var elapsed = TimeSpan.FromMilliseconds(normalizedElapsedMs);
|
||||||
if (elapsed.TotalHours >= 1)
|
if (elapsed.TotalHours >= 1)
|
||||||
parts.Add($"{(int)elapsed.TotalHours}h {elapsed.Minutes}m");
|
parts.Add($"{(int)elapsed.TotalHours}h {elapsed.Minutes}m");
|
||||||
else if (elapsed.TotalMinutes >= 1)
|
else if (elapsed.TotalMinutes >= 1)
|
||||||
@@ -324,11 +342,12 @@ public partial class ChatWindow
|
|||||||
bool liveWaitingStyle,
|
bool liveWaitingStyle,
|
||||||
out Border pulseMarker)
|
out Border pulseMarker)
|
||||||
{
|
{
|
||||||
|
var liveAccentColor = ResolveLiveProgressAccentColor(accentBrush);
|
||||||
var cardBackground = liveWaitingStyle
|
var cardBackground = liveWaitingStyle
|
||||||
? new SolidColorBrush(Color.FromArgb(0x20, 0xF5, 0x73, 0x16))
|
? new SolidColorBrush(Color.FromArgb(0x16, liveAccentColor.R, liveAccentColor.G, liveAccentColor.B))
|
||||||
: hintBg;
|
: hintBg;
|
||||||
var cardBorder = liveWaitingStyle
|
var cardBorder = liveWaitingStyle
|
||||||
? new SolidColorBrush(Color.FromArgb(0x4D, 0xF5, 0x73, 0x16))
|
? new SolidColorBrush(Color.FromArgb(0x46, liveAccentColor.R, liveAccentColor.G, liveAccentColor.B))
|
||||||
: borderBrush;
|
: borderBrush;
|
||||||
|
|
||||||
pulseMarker = new Border
|
pulseMarker = new Border
|
||||||
@@ -389,9 +408,10 @@ public partial class ChatWindow
|
|||||||
{
|
{
|
||||||
var parts = new List<string>();
|
var parts = new List<string>();
|
||||||
|
|
||||||
if (evt.ElapsedMs > 0)
|
var normalizedElapsedMs = NormalizeProgressElapsedMs(evt.ElapsedMs);
|
||||||
|
if (normalizedElapsedMs > 0)
|
||||||
{
|
{
|
||||||
var elapsed = TimeSpan.FromMilliseconds(evt.ElapsedMs);
|
var elapsed = TimeSpan.FromMilliseconds(normalizedElapsedMs);
|
||||||
if (elapsed.TotalHours >= 1)
|
if (elapsed.TotalHours >= 1)
|
||||||
parts.Add($"{(int)elapsed.TotalHours}h {elapsed.Minutes}m");
|
parts.Add($"{(int)elapsed.TotalHours}h {elapsed.Minutes}m");
|
||||||
else if (elapsed.TotalMinutes >= 1)
|
else if (elapsed.TotalMinutes >= 1)
|
||||||
@@ -418,11 +438,12 @@ public partial class ChatWindow
|
|||||||
bool liveWaitingStyle,
|
bool liveWaitingStyle,
|
||||||
out Border pulseMarker)
|
out Border pulseMarker)
|
||||||
{
|
{
|
||||||
|
var liveAccentColor = ResolveLiveProgressAccentColor(accentBrush);
|
||||||
var cardBackground = liveWaitingStyle
|
var cardBackground = liveWaitingStyle
|
||||||
? new SolidColorBrush(Color.FromArgb(0x20, 0xF5, 0x73, 0x16))
|
? new SolidColorBrush(Color.FromArgb(0x16, liveAccentColor.R, liveAccentColor.G, liveAccentColor.B))
|
||||||
: Brushes.Transparent;
|
: Brushes.Transparent;
|
||||||
var cardBorder = liveWaitingStyle
|
var cardBorder = liveWaitingStyle
|
||||||
? new SolidColorBrush(Color.FromArgb(0x4D, 0xF5, 0x73, 0x16))
|
? new SolidColorBrush(Color.FromArgb(0x46, liveAccentColor.R, liveAccentColor.G, liveAccentColor.B))
|
||||||
: Brushes.Transparent;
|
: Brushes.Transparent;
|
||||||
|
|
||||||
pulseMarker = new Border
|
pulseMarker = new Border
|
||||||
@@ -1003,11 +1024,12 @@ public partial class ChatWindow
|
|||||||
Grid.SetColumn(headerLeft, 0);
|
Grid.SetColumn(headerLeft, 0);
|
||||||
|
|
||||||
var headerRight = new StackPanel { Orientation = Orientation.Horizontal };
|
var headerRight = new StackPanel { Orientation = Orientation.Horizontal };
|
||||||
if (logLevel != "simple" && evt.ElapsedMs > 0)
|
var normalizedElapsedMs = NormalizeProgressElapsedMs(evt.ElapsedMs);
|
||||||
|
if (logLevel != "simple" && normalizedElapsedMs > 0)
|
||||||
{
|
{
|
||||||
headerRight.Children.Add(new TextBlock
|
headerRight.Children.Add(new TextBlock
|
||||||
{
|
{
|
||||||
Text = evt.ElapsedMs < 1000 ? $"{evt.ElapsedMs}ms" : $"{evt.ElapsedMs / 1000.0:F1}s",
|
Text = normalizedElapsedMs < 1000 ? $"{normalizedElapsedMs}ms" : $"{normalizedElapsedMs / 1000.0:F1}s",
|
||||||
FontSize = 8.5,
|
FontSize = 8.5,
|
||||||
Foreground = secondaryText,
|
Foreground = secondaryText,
|
||||||
VerticalAlignment = VerticalAlignment.Center,
|
VerticalAlignment = VerticalAlignment.Center,
|
||||||
|
|||||||
@@ -1917,7 +1917,7 @@
|
|||||||
Visibility="Collapsed"
|
Visibility="Collapsed"
|
||||||
Margin="0,0,0,6"/>
|
Margin="0,0,0,6"/>
|
||||||
<Border x:Name="InputGlowBorder" CornerRadius="18" Opacity="0"
|
<Border x:Name="InputGlowBorder" CornerRadius="18" Opacity="0"
|
||||||
Margin="-1" IsHitTestVisible="False">
|
Margin="-2" IsHitTestVisible="False">
|
||||||
<Border.BorderBrush>
|
<Border.BorderBrush>
|
||||||
<LinearGradientBrush x:Name="RainbowBrush" StartPoint="0,0" EndPoint="1,1">
|
<LinearGradientBrush x:Name="RainbowBrush" StartPoint="0,0" EndPoint="1,1">
|
||||||
<GradientStop Color="#FF6B6B" Offset="0.0"/>
|
<GradientStop Color="#FF6B6B" Offset="0.0"/>
|
||||||
@@ -1930,10 +1930,10 @@
|
|||||||
</LinearGradientBrush>
|
</LinearGradientBrush>
|
||||||
</Border.BorderBrush>
|
</Border.BorderBrush>
|
||||||
<Border.BorderThickness>
|
<Border.BorderThickness>
|
||||||
<Thickness>1.5</Thickness>
|
<Thickness>1.15</Thickness>
|
||||||
</Border.BorderThickness>
|
</Border.BorderThickness>
|
||||||
<Border.Effect>
|
<Border.Effect>
|
||||||
<BlurEffect Radius="2"/>
|
<BlurEffect Radius="6"/>
|
||||||
</Border.Effect>
|
</Border.Effect>
|
||||||
</Border>
|
</Border>
|
||||||
<!-- 실제 입력 영역 -->
|
<!-- 실제 입력 영역 -->
|
||||||
@@ -3688,6 +3688,99 @@
|
|||||||
</ComboBox>
|
</ComboBox>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Border>
|
</Border>
|
||||||
|
<Border x:Name="OverlaySectionGlowEffects"
|
||||||
|
Background="Transparent"
|
||||||
|
BorderBrush="{DynamicResource BorderColor}"
|
||||||
|
BorderThickness="0,1,0,0"
|
||||||
|
CornerRadius="0"
|
||||||
|
Padding="0,12,0,0"
|
||||||
|
Margin="0,0,0,12">
|
||||||
|
<StackPanel>
|
||||||
|
<TextBlock Text="글로우 효과"
|
||||||
|
FontSize="13"
|
||||||
|
FontWeight="SemiBold"
|
||||||
|
Foreground="{DynamicResource PrimaryText}"/>
|
||||||
|
<TextBlock Text="런처와 AX Agent의 글로우 연출을 여기서 조정합니다."
|
||||||
|
Margin="0,4,0,10"
|
||||||
|
FontSize="11"
|
||||||
|
Foreground="{DynamicResource SecondaryText}"/>
|
||||||
|
<Border Style="{StaticResource OverlayAdvancedToggleRowStyle}">
|
||||||
|
<Grid>
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="*"/>
|
||||||
|
<ColumnDefinition Width="Auto"/>
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<StackPanel Margin="0,0,16,0">
|
||||||
|
<TextBlock Text="런처 무지개 글로우"
|
||||||
|
FontSize="12.5"
|
||||||
|
FontWeight="SemiBold"
|
||||||
|
Foreground="{DynamicResource PrimaryText}"/>
|
||||||
|
<TextBlock Text="AX Commander 테두리에 무지개 글로우를 표시합니다."
|
||||||
|
Margin="0,4,0,0"
|
||||||
|
FontSize="11.5"
|
||||||
|
TextWrapping="Wrap"
|
||||||
|
Foreground="{DynamicResource SecondaryText}"/>
|
||||||
|
</StackPanel>
|
||||||
|
<CheckBox x:Name="ChkOverlayEnableLauncherRainbowGlow"
|
||||||
|
Grid.Column="1"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Style="{StaticResource ToggleSwitch}"
|
||||||
|
Checked="ChkOverlayFeatureToggle_Changed"
|
||||||
|
Unchecked="ChkOverlayFeatureToggle_Changed"/>
|
||||||
|
</Grid>
|
||||||
|
</Border>
|
||||||
|
<Border Style="{StaticResource OverlayAdvancedToggleRowStyle}" Margin="0,8,0,0">
|
||||||
|
<Grid>
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="*"/>
|
||||||
|
<ColumnDefinition Width="Auto"/>
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<StackPanel Margin="0,0,16,0">
|
||||||
|
<TextBlock Text="런처 선택 글로우"
|
||||||
|
FontSize="12.5"
|
||||||
|
FontWeight="SemiBold"
|
||||||
|
Foreground="{DynamicResource PrimaryText}"/>
|
||||||
|
<TextBlock Text="선택된 런처 항목에 은은한 글로우를 표시합니다."
|
||||||
|
Margin="0,4,0,0"
|
||||||
|
FontSize="11.5"
|
||||||
|
TextWrapping="Wrap"
|
||||||
|
Foreground="{DynamicResource SecondaryText}"/>
|
||||||
|
</StackPanel>
|
||||||
|
<CheckBox x:Name="ChkOverlayEnableSelectionGlow"
|
||||||
|
Grid.Column="1"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Style="{StaticResource ToggleSwitch}"
|
||||||
|
Checked="ChkOverlayFeatureToggle_Changed"
|
||||||
|
Unchecked="ChkOverlayFeatureToggle_Changed"/>
|
||||||
|
</Grid>
|
||||||
|
</Border>
|
||||||
|
<Border Style="{StaticResource OverlayAdvancedToggleRowStyle}" Margin="0,8,0,0">
|
||||||
|
<Grid>
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="*"/>
|
||||||
|
<ColumnDefinition Width="Auto"/>
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<StackPanel Margin="0,0,16,0">
|
||||||
|
<TextBlock Text="채팅 입력창 글로우"
|
||||||
|
FontSize="12.5"
|
||||||
|
FontWeight="SemiBold"
|
||||||
|
Foreground="{DynamicResource PrimaryText}"/>
|
||||||
|
<TextBlock Text="메시지 전송 중 입력창에 런처와 같은 무지개 글로우를 표시합니다."
|
||||||
|
Margin="0,4,0,0"
|
||||||
|
FontSize="11.5"
|
||||||
|
TextWrapping="Wrap"
|
||||||
|
Foreground="{DynamicResource SecondaryText}"/>
|
||||||
|
</StackPanel>
|
||||||
|
<CheckBox x:Name="ChkOverlayEnableChatRainbowGlow"
|
||||||
|
Grid.Column="1"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Style="{StaticResource ToggleSwitch}"
|
||||||
|
Checked="ChkOverlayFeatureToggle_Changed"
|
||||||
|
Unchecked="ChkOverlayFeatureToggle_Changed"/>
|
||||||
|
</Grid>
|
||||||
|
</Border>
|
||||||
|
</StackPanel>
|
||||||
|
</Border>
|
||||||
<Border x:Name="OverlayToggleImageInput" Style="{StaticResource OverlayAdvancedToggleRowStyle}">
|
<Border x:Name="OverlayToggleImageInput" Style="{StaticResource OverlayAdvancedToggleRowStyle}">
|
||||||
<Grid>
|
<Grid>
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
|
|||||||
@@ -5302,6 +5302,7 @@ public partial class ChatWindow : Window
|
|||||||
ForceScrollToEnd(); // 사용자 메시지 전송 시 강제 하단 이동
|
ForceScrollToEnd(); // 사용자 메시지 전송 시 강제 하단 이동
|
||||||
PlayRainbowGlow(); // 무지개 글로우 애니메이션
|
PlayRainbowGlow(); // 무지개 글로우 애니메이션
|
||||||
|
|
||||||
|
_streamStartTime = DateTime.UtcNow;
|
||||||
_isStreaming = true;
|
_isStreaming = true;
|
||||||
_streamRunTab = runTab;
|
_streamRunTab = runTab;
|
||||||
StartLiveAgentProgressHints();
|
StartLiveAgentProgressHints();
|
||||||
@@ -5318,7 +5319,6 @@ public partial class ChatWindow : Window
|
|||||||
_displayedLength = 0;
|
_displayedLength = 0;
|
||||||
_cursorVisible = true;
|
_cursorVisible = true;
|
||||||
_aiIconPulseStopped = false;
|
_aiIconPulseStopped = false;
|
||||||
_streamStartTime = DateTime.UtcNow;
|
|
||||||
_elapsedTimer.Start();
|
_elapsedTimer.Start();
|
||||||
SetStatus("응답 생성 중...", spinning: true);
|
SetStatus("응답 생성 중...", spinning: true);
|
||||||
|
|
||||||
@@ -6415,7 +6415,8 @@ public partial class ChatWindow : Window
|
|||||||
var normalizedSummary = string.IsNullOrWhiteSpace(summary) ? null : summary.Trim();
|
var normalizedSummary = string.IsNullOrWhiteSpace(summary) ? null : summary.Trim();
|
||||||
var currentSummary = _liveAgentProgressHint?.Summary;
|
var currentSummary = _liveAgentProgressHint?.Summary;
|
||||||
var currentToolName = _liveAgentProgressHint?.ToolName ?? "";
|
var currentToolName = _liveAgentProgressHint?.ToolName ?? "";
|
||||||
var elapsedMs = _isStreaming
|
var hasValidStreamStart = _streamStartTime.Year >= 2000 && _streamStartTime <= DateTime.UtcNow.AddSeconds(1);
|
||||||
|
var elapsedMs = _isStreaming && hasValidStreamStart
|
||||||
? Math.Max(0L, (long)(DateTime.UtcNow - _streamStartTime.ToUniversalTime()).TotalMilliseconds)
|
? Math.Max(0L, (long)(DateTime.UtcNow - _streamStartTime.ToUniversalTime()).TotalMilliseconds)
|
||||||
: 0L;
|
: 0L;
|
||||||
var inputTokens = Math.Max(0, _agentCumulativeInputTokens);
|
var inputTokens = Math.Max(0, _agentCumulativeInputTokens);
|
||||||
@@ -8769,22 +8770,18 @@ public partial class ChatWindow : Window
|
|||||||
_rainbowTimer?.Stop();
|
_rainbowTimer?.Stop();
|
||||||
_rainbowStartTime = DateTime.UtcNow;
|
_rainbowStartTime = DateTime.UtcNow;
|
||||||
|
|
||||||
// 페이드인 (빠르게)
|
InputGlowBorder.Effect = new System.Windows.Media.Effects.BlurEffect { Radius = 6 };
|
||||||
InputGlowBorder.BeginAnimation(UIElement.OpacityProperty,
|
InputGlowBorder.BeginAnimation(UIElement.OpacityProperty,
|
||||||
new System.Windows.Media.Animation.DoubleAnimation(0, 0.9, TimeSpan.FromMilliseconds(150)));
|
new System.Windows.Media.Animation.DoubleAnimation(0, 0.62, TimeSpan.FromMilliseconds(180)));
|
||||||
|
|
||||||
// 그라데이션 회전 타이머 (~60fps) — 스트리밍 종료까지 지속
|
_rainbowTimer = new DispatcherTimer { Interval = TimeSpan.FromMilliseconds(40) };
|
||||||
_rainbowTimer = new DispatcherTimer { Interval = TimeSpan.FromMilliseconds(16) };
|
|
||||||
_rainbowTimer.Tick += (_, _) =>
|
_rainbowTimer.Tick += (_, _) =>
|
||||||
{
|
{
|
||||||
var elapsed = (DateTime.UtcNow - _rainbowStartTime).TotalMilliseconds;
|
var elapsed = (DateTime.UtcNow - _rainbowStartTime).TotalMilliseconds;
|
||||||
|
var shift = (elapsed / 2000.0) % 1.0;
|
||||||
// 그라데이션 오프셋 회전
|
|
||||||
var shift = (elapsed / 1500.0) % 1.0; // 1.5초에 1바퀴 (느리게)
|
|
||||||
var brush = InputGlowBorder.BorderBrush as LinearGradientBrush;
|
var brush = InputGlowBorder.BorderBrush as LinearGradientBrush;
|
||||||
if (brush == null) return;
|
if (brush == null) return;
|
||||||
|
|
||||||
// 시작/끝점 회전 (원형 이동)
|
|
||||||
var angle = shift * Math.PI * 2;
|
var angle = shift * Math.PI * 2;
|
||||||
brush.StartPoint = new Point(0.5 + 0.5 * Math.Cos(angle), 0.5 + 0.5 * Math.Sin(angle));
|
brush.StartPoint = new Point(0.5 + 0.5 * Math.Cos(angle), 0.5 + 0.5 * Math.Sin(angle));
|
||||||
brush.EndPoint = new Point(0.5 - 0.5 * Math.Cos(angle), 0.5 - 0.5 * Math.Sin(angle));
|
brush.EndPoint = new Point(0.5 - 0.5 * Math.Cos(angle), 0.5 - 0.5 * Math.Sin(angle));
|
||||||
@@ -10278,6 +10275,9 @@ public partial class ChatWindow : Window
|
|||||||
llm.WorkflowVisualizer = ChkOverlayWorkflowVisualizer?.IsChecked == true;
|
llm.WorkflowVisualizer = ChkOverlayWorkflowVisualizer?.IsChecked == true;
|
||||||
llm.ShowTotalCallStats = ChkOverlayShowTotalCallStats?.IsChecked == true;
|
llm.ShowTotalCallStats = ChkOverlayShowTotalCallStats?.IsChecked == true;
|
||||||
llm.EnableAuditLog = ChkOverlayEnableAuditLog?.IsChecked == true;
|
llm.EnableAuditLog = ChkOverlayEnableAuditLog?.IsChecked == true;
|
||||||
|
llm.EnableChatRainbowGlow = ChkOverlayEnableChatRainbowGlow?.IsChecked == true;
|
||||||
|
_settings.Settings.Launcher.EnableRainbowGlow = ChkOverlayEnableLauncherRainbowGlow?.IsChecked == true;
|
||||||
|
_settings.Settings.Launcher.EnableSelectionGlow = ChkOverlayEnableSelectionGlow?.IsChecked == true;
|
||||||
|
|
||||||
CommitOverlayEndpointInput(normalizeOnInvalid: true);
|
CommitOverlayEndpointInput(normalizeOnInvalid: true);
|
||||||
CommitOverlayApiKeyInput();
|
CommitOverlayApiKeyInput();
|
||||||
@@ -10482,6 +10482,12 @@ public partial class ChatWindow : Window
|
|||||||
ChkOverlayShowTotalCallStats.IsChecked = llm.ShowTotalCallStats;
|
ChkOverlayShowTotalCallStats.IsChecked = llm.ShowTotalCallStats;
|
||||||
if (ChkOverlayEnableAuditLog != null)
|
if (ChkOverlayEnableAuditLog != null)
|
||||||
ChkOverlayEnableAuditLog.IsChecked = llm.EnableAuditLog;
|
ChkOverlayEnableAuditLog.IsChecked = llm.EnableAuditLog;
|
||||||
|
if (ChkOverlayEnableChatRainbowGlow != null)
|
||||||
|
ChkOverlayEnableChatRainbowGlow.IsChecked = llm.EnableChatRainbowGlow;
|
||||||
|
if (ChkOverlayEnableLauncherRainbowGlow != null)
|
||||||
|
ChkOverlayEnableLauncherRainbowGlow.IsChecked = _settings.Settings.Launcher.EnableRainbowGlow;
|
||||||
|
if (ChkOverlayEnableSelectionGlow != null)
|
||||||
|
ChkOverlayEnableSelectionGlow.IsChecked = _settings.Settings.Launcher.EnableSelectionGlow;
|
||||||
}
|
}
|
||||||
|
|
||||||
RefreshOverlayThemeCards();
|
RefreshOverlayThemeCards();
|
||||||
|
|||||||
@@ -1195,52 +1195,6 @@
|
|||||||
<!-- 테마 선택 패널 -->
|
<!-- 테마 선택 패널 -->
|
||||||
<ScrollViewer x:Name="ThemeSelectPanel" Grid.Row="2" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled">
|
<ScrollViewer x:Name="ThemeSelectPanel" Grid.Row="2" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled">
|
||||||
<StackPanel>
|
<StackPanel>
|
||||||
<!-- ── 시각 효과 ── -->
|
|
||||||
<TextBlock Text="시각 효과" Style="{StaticResource SectionHeader}"/>
|
|
||||||
<Border Style="{StaticResource SettingsRow}">
|
|
||||||
<Grid>
|
|
||||||
<StackPanel HorizontalAlignment="Left" Margin="0,0,60,0">
|
|
||||||
<StackPanel Orientation="Horizontal">
|
|
||||||
<TextBlock Style="{StaticResource RowLabel}" Text="런처 무지개 글로우"/>
|
|
||||||
<Border Width="16" Height="16" CornerRadius="8" Background="{DynamicResource ItemHoverBackground}" Margin="6,0,0,0" Cursor="Help" VerticalAlignment="Center">
|
|
||||||
<TextBlock Text="?" FontSize="10" FontWeight="Bold" Foreground="{DynamicResource AccentColor}" HorizontalAlignment="Center" VerticalAlignment="Center"/>
|
|
||||||
<Border.ToolTip>
|
|
||||||
<ToolTip Style="{StaticResource HelpTooltipStyle}">
|
|
||||||
<TextBlock TextWrapping="Wrap" Foreground="White" FontSize="12" LineHeight="18">
|
|
||||||
AX Commander 테두리에 무지개빛 회전 애니메이션을 표시합니다.
|
|
||||||
<LineBreak/>GPU 가속을 사용하므로 저사양 PC에서는 끄는 것을 권장합니다.
|
|
||||||
</TextBlock>
|
|
||||||
</ToolTip>
|
|
||||||
</Border.ToolTip>
|
|
||||||
</Border>
|
|
||||||
</StackPanel>
|
|
||||||
<TextBlock Style="{StaticResource RowHint}" Text="AX Commander 테두리에 무지개빛 글로우 효과를 표시합니다. 저사양 PC에서는 끄는 것을 권장합니다."/>
|
|
||||||
</StackPanel>
|
|
||||||
<CheckBox Style="{StaticResource ToggleSwitch}" HorizontalAlignment="Right" VerticalAlignment="Center"
|
|
||||||
IsChecked="{Binding EnableRainbowGlow, Mode=TwoWay}"/>
|
|
||||||
</Grid>
|
|
||||||
</Border>
|
|
||||||
<Border Style="{StaticResource SettingsRow}">
|
|
||||||
<Grid>
|
|
||||||
<StackPanel HorizontalAlignment="Left" Margin="0,0,60,0">
|
|
||||||
<TextBlock Style="{StaticResource RowLabel}" Text="선택 아이템 글로우"/>
|
|
||||||
<TextBlock Style="{StaticResource RowHint}" Text="선택된 항목에 은은한 글로우를 상시 표시합니다. 테마 AccentColor를 기반으로 색상이 적용됩니다."/>
|
|
||||||
</StackPanel>
|
|
||||||
<CheckBox Style="{StaticResource ToggleSwitch}" HorizontalAlignment="Right" VerticalAlignment="Center"
|
|
||||||
IsChecked="{Binding EnableSelectionGlow, Mode=TwoWay}"/>
|
|
||||||
</Grid>
|
|
||||||
</Border>
|
|
||||||
<Border Style="{StaticResource SettingsRow}">
|
|
||||||
<Grid>
|
|
||||||
<StackPanel HorizontalAlignment="Left" Margin="0,0,60,0">
|
|
||||||
<TextBlock Style="{StaticResource RowLabel}" Text="채팅 입력창 무지개 글로우"/>
|
|
||||||
<TextBlock Style="{StaticResource RowHint}" Text="메시지 전송 시 입력창 테두리에 무지개빛 글로우 효과를 표시합니다. 저사양 PC에서는 끄는 것을 권장합니다."/>
|
|
||||||
</StackPanel>
|
|
||||||
<CheckBox Style="{StaticResource ToggleSwitch}" HorizontalAlignment="Right" VerticalAlignment="Center"
|
|
||||||
IsChecked="{Binding EnableChatRainbowGlow, Mode=TwoWay}"/>
|
|
||||||
</Grid>
|
|
||||||
</Border>
|
|
||||||
|
|
||||||
<TextBlock Text="테마 선택" Style="{StaticResource SectionHeader}"/>
|
<TextBlock Text="테마 선택" Style="{StaticResource SectionHeader}"/>
|
||||||
<Border Background="White" CornerRadius="10" Padding="14,10" Margin="0,0,0,14">
|
<Border Background="White" CornerRadius="10" Padding="14,10" Margin="0,0,0,14">
|
||||||
<StackPanel Orientation="Horizontal">
|
<StackPanel Orientation="Horizontal">
|
||||||
|
|||||||
Reference in New Issue
Block a user