- 등록 모델 실행 프로파일을 검증 게이트, 문서 fallback, post-tool verification까지 확장 적용 - Cowork/Code 진행 카드에 계획/도구/검증/압축/폴백/재시도 단계 메타를 추가해 대기 상태 가시성 강화 - OpenAI/vLLM tool 요청에 병렬 도구 호출 힌트를 추가하고 회귀 프롬프트 문서를 프로파일 기준으로 전면 정리 - 검증: dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\\verify\\ -p:IntermediateOutputPath=obj\\verify\\ (경고 0 / 오류 0)
287 lines
9.3 KiB
C#
287 lines
9.3 KiB
C#
using System.Windows;
|
|
using System.Windows.Media;
|
|
using System.Windows.Threading;
|
|
using AxCopilot.Services;
|
|
|
|
namespace AxCopilot.Views;
|
|
|
|
public partial class LauncherWindow
|
|
{
|
|
private DispatcherTimer? _widgetTimer;
|
|
private int _widgetBatteryTick;
|
|
private int _widgetWeatherTick;
|
|
|
|
internal void StartWidgetUpdates()
|
|
{
|
|
SyncWidgetPollingState();
|
|
PomodoroService.Instance.StateChanged -= OnPomoStateChanged;
|
|
PomodoroService.Instance.StateChanged += OnPomoStateChanged;
|
|
|
|
UpdateWidgetVisibility();
|
|
RefreshVisibleWidgets(forceWeatherRefresh: true);
|
|
|
|
if (!ShouldRunWidgetTimer())
|
|
{
|
|
_widgetTimer?.Stop();
|
|
return;
|
|
}
|
|
|
|
if (_widgetTimer == null)
|
|
{
|
|
_widgetTimer = new DispatcherTimer(DispatcherPriority.Background)
|
|
{
|
|
Interval = TimeSpan.FromSeconds(1)
|
|
};
|
|
_widgetTimer.Tick += (_, _) =>
|
|
{
|
|
if (!ShouldRunWidgetTimer())
|
|
{
|
|
_widgetTimer?.Stop();
|
|
SyncWidgetPollingState();
|
|
UpdateWidgetVisibility();
|
|
return;
|
|
}
|
|
|
|
SyncWidgetPollingState();
|
|
RefreshVisibleWidgets(forceWeatherRefresh: false);
|
|
if (ShouldShowBatteryWidget() && _widgetBatteryTick++ % 30 == 0)
|
|
UpdateBatteryWidget();
|
|
if (ShouldShowWeatherWidget() && _widgetWeatherTick++ % 120 == 0)
|
|
_ = RefreshWeatherAsync();
|
|
};
|
|
}
|
|
|
|
_widgetTimer.Start();
|
|
UpdatePomoWidgetStyle();
|
|
}
|
|
|
|
internal void StopWidgetUpdates()
|
|
{
|
|
_widgetTimer?.Stop();
|
|
PerformanceMonitorService.Instance.StopPolling();
|
|
PomodoroService.Instance.StateChanged -= OnPomoStateChanged;
|
|
}
|
|
|
|
private void OnPomoStateChanged(object? sender, EventArgs e)
|
|
{
|
|
Dispatcher.InvokeAsync(() =>
|
|
{
|
|
RefreshVisibleWidgets(forceWeatherRefresh: false);
|
|
UpdatePomoWidgetStyle();
|
|
UpdateWidgetVisibility();
|
|
});
|
|
}
|
|
|
|
private void RefreshVisibleWidgets(bool forceWeatherRefresh)
|
|
{
|
|
var launcher = CurrentApp?.SettingsService?.Settings?.Launcher;
|
|
if (launcher == null)
|
|
return;
|
|
|
|
_vm.UpdateWidgets(
|
|
includePerf: launcher.ShowWidgetPerf,
|
|
includePomo: launcher.ShowWidgetPomo,
|
|
includeNote: launcher.ShowWidgetNote,
|
|
includeCalendar: launcher.ShowWidgetCalendar,
|
|
includeServerStatus: false);
|
|
|
|
UpdateWidgetVisibility();
|
|
|
|
if (ShouldShowBatteryWidget())
|
|
UpdateBatteryWidget();
|
|
if (forceWeatherRefresh && ShouldShowWeatherWidget())
|
|
_ = RefreshWeatherAsync();
|
|
}
|
|
|
|
private void SyncWidgetPollingState()
|
|
{
|
|
if (ShouldShowPerfWidget())
|
|
PerformanceMonitorService.Instance.StartPolling();
|
|
else
|
|
PerformanceMonitorService.Instance.StopPolling();
|
|
}
|
|
|
|
private bool ShouldRunWidgetTimer()
|
|
{
|
|
var launcher = CurrentApp?.SettingsService?.Settings?.Launcher;
|
|
if (launcher == null)
|
|
return false;
|
|
|
|
return launcher.ShowWidgetPerf
|
|
|| launcher.ShowWidgetPomo
|
|
|| launcher.ShowWidgetNote
|
|
|| launcher.ShowWidgetWeather
|
|
|| launcher.ShowWidgetCalendar
|
|
|| launcher.ShowWidgetBattery;
|
|
}
|
|
|
|
private bool ShouldShowPerfWidget()
|
|
=> CurrentApp?.SettingsService?.Settings?.Launcher?.ShowWidgetPerf ?? false;
|
|
|
|
private bool ShouldShowWeatherWidget()
|
|
=> CurrentApp?.SettingsService?.Settings?.Launcher?.ShowWidgetWeather ?? false;
|
|
|
|
private bool ShouldShowBatteryWidget()
|
|
=> (CurrentApp?.SettingsService?.Settings?.Launcher?.ShowWidgetBattery ?? false) && _vm.Widget_BatteryVisible;
|
|
|
|
private void UpdatePomoWidgetStyle()
|
|
{
|
|
if (WgtPomo == null)
|
|
return;
|
|
|
|
var running = PomodoroService.Instance.IsRunning;
|
|
WgtPomo.Background = running
|
|
? new SolidColorBrush(Color.FromArgb(0x1E, 0xF5, 0x9E, 0x0B))
|
|
: new SolidColorBrush(Color.FromArgb(0x0D, 0xF5, 0x9E, 0x0B));
|
|
}
|
|
|
|
private void UpdateWidgetVisibility()
|
|
{
|
|
var launcher = CurrentApp?.SettingsService?.Settings?.Launcher;
|
|
if (launcher == null)
|
|
return;
|
|
|
|
if (WgtPerf != null)
|
|
WgtPerf.Visibility = launcher.ShowWidgetPerf ? Visibility.Visible : Visibility.Collapsed;
|
|
if (WgtPomo != null)
|
|
WgtPomo.Visibility = launcher.ShowWidgetPomo ? Visibility.Visible : Visibility.Collapsed;
|
|
if (WgtNote != null)
|
|
WgtNote.Visibility = launcher.ShowWidgetNote ? Visibility.Visible : Visibility.Collapsed;
|
|
if (WgtWeather != null)
|
|
WgtWeather.Visibility = launcher.ShowWidgetWeather ? Visibility.Visible : Visibility.Collapsed;
|
|
if (WgtCal != null)
|
|
WgtCal.Visibility = launcher.ShowWidgetCalendar ? Visibility.Visible : Visibility.Collapsed;
|
|
if (WgtBattery != null)
|
|
WgtBattery.Visibility = launcher.ShowWidgetBattery && _vm.Widget_BatteryVisible ? Visibility.Visible : Visibility.Collapsed;
|
|
|
|
var hasAny =
|
|
launcher.ShowWidgetPerf ||
|
|
launcher.ShowWidgetPomo ||
|
|
launcher.ShowWidgetNote ||
|
|
launcher.ShowWidgetWeather ||
|
|
launcher.ShowWidgetCalendar ||
|
|
(launcher.ShowWidgetBattery && _vm.Widget_BatteryVisible);
|
|
|
|
if (WidgetBar != null)
|
|
WidgetBar.Visibility = hasAny ? Visibility.Visible : Visibility.Collapsed;
|
|
|
|
SyncWidgetPollingState();
|
|
if (!hasAny)
|
|
_widgetTimer?.Stop();
|
|
}
|
|
|
|
private void WgtPerf_Click(object sender, System.Windows.Input.MouseButtonEventArgs e)
|
|
{
|
|
_vm.InputText = "info ";
|
|
InputBox?.Focus();
|
|
}
|
|
|
|
private void WgtPomo_Click(object sender, System.Windows.Input.MouseButtonEventArgs e)
|
|
{
|
|
_vm.InputText = "pomo ";
|
|
InputBox?.Focus();
|
|
}
|
|
|
|
private void WgtNote_Click(object sender, System.Windows.Input.MouseButtonEventArgs e)
|
|
{
|
|
_vm.InputText = "note ";
|
|
InputBox?.Focus();
|
|
}
|
|
|
|
private void WgtWeather_Click(object sender, System.Windows.Input.MouseButtonEventArgs e)
|
|
{
|
|
var internalMode = CurrentApp?.SettingsService?.Settings.InternalModeEnabled ?? true;
|
|
if (!internalMode)
|
|
{
|
|
try
|
|
{
|
|
System.Diagnostics.Process.Start(new System.Diagnostics.ProcessStartInfo("https://wttr.in") { UseShellExecute = true });
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
LogService.Warn($"날씨 페이지 열기 실패: {ex.Message}");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WeatherWidgetService.Invalidate();
|
|
_ = RefreshWeatherAsync();
|
|
}
|
|
}
|
|
|
|
private void WgtCal_Click(object sender, System.Windows.Input.MouseButtonEventArgs e)
|
|
{
|
|
try
|
|
{
|
|
System.Diagnostics.Process.Start(new System.Diagnostics.ProcessStartInfo("ms-clock:") { UseShellExecute = true });
|
|
}
|
|
catch
|
|
{
|
|
try
|
|
{
|
|
System.Diagnostics.Process.Start(new System.Diagnostics.ProcessStartInfo("outlookcal:") { UseShellExecute = true });
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
LogService.Warn($"일정 열기 실패: {ex.Message}");
|
|
}
|
|
}
|
|
}
|
|
|
|
private void WgtBattery_Click(object sender, System.Windows.Input.MouseButtonEventArgs e)
|
|
{
|
|
try
|
|
{
|
|
System.Diagnostics.Process.Start(new System.Diagnostics.ProcessStartInfo("ms-settings:powersleep") { UseShellExecute = true });
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
LogService.Warn($"전원 설정 열기 실패: {ex.Message}");
|
|
}
|
|
}
|
|
|
|
private void UpdateBatteryWidget()
|
|
{
|
|
try
|
|
{
|
|
var power = System.Windows.Forms.SystemInformation.PowerStatus;
|
|
var pct = power.BatteryLifePercent;
|
|
if (pct > 1.0f || pct < 0f)
|
|
{
|
|
_vm.Widget_BatteryVisible = false;
|
|
UpdateWidgetVisibility();
|
|
return;
|
|
}
|
|
|
|
_vm.Widget_BatteryVisible = true;
|
|
var pctInt = (int)(pct * 100);
|
|
var charging = power.PowerLineStatus == System.Windows.Forms.PowerLineStatus.Online;
|
|
_vm.Widget_BatteryText = charging ? $"{pctInt}% 충전" : $"{pctInt}%";
|
|
_vm.Widget_BatteryIcon = charging ? "\uE83E"
|
|
: pctInt >= 85 ? "\uEBA7"
|
|
: pctInt >= 70 ? "\uEBA5"
|
|
: pctInt >= 50 ? "\uEBA3"
|
|
: pctInt >= 25 ? "\uEBA1"
|
|
: "\uEBA0";
|
|
UpdateWidgetVisibility();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
LogService.Warn($"배터리 상태 갱신 실패: {ex.Message}");
|
|
_vm.Widget_BatteryVisible = false;
|
|
UpdateWidgetVisibility();
|
|
}
|
|
}
|
|
|
|
private async Task RefreshWeatherAsync()
|
|
{
|
|
var internalMode = CurrentApp?.SettingsService?.Settings.InternalModeEnabled ?? true;
|
|
await WeatherWidgetService.RefreshAsync(internalMode);
|
|
await Dispatcher.InvokeAsync(() =>
|
|
{
|
|
_vm.Widget_WeatherText = WeatherWidgetService.CachedText;
|
|
UpdateWidgetVisibility();
|
|
});
|
|
}
|
|
}
|