Initial commit to new repository
This commit is contained in:
108
.decompiledproj/AxCopilot/ViewModels/AppShortcutModel.cs
Normal file
108
.decompiledproj/AxCopilot/ViewModels/AppShortcutModel.cs
Normal file
@@ -0,0 +1,108 @@
|
||||
using System.ComponentModel;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace AxCopilot.ViewModels;
|
||||
|
||||
public class AppShortcutModel : INotifyPropertyChanged
|
||||
{
|
||||
private string _key = "";
|
||||
|
||||
private string _description = "";
|
||||
|
||||
private string _target = "";
|
||||
|
||||
private string _type = "app";
|
||||
|
||||
public string Key
|
||||
{
|
||||
get
|
||||
{
|
||||
return _key;
|
||||
}
|
||||
set
|
||||
{
|
||||
_key = value;
|
||||
OnPropertyChanged("Key");
|
||||
}
|
||||
}
|
||||
|
||||
public string Description
|
||||
{
|
||||
get
|
||||
{
|
||||
return _description;
|
||||
}
|
||||
set
|
||||
{
|
||||
_description = value;
|
||||
OnPropertyChanged("Description");
|
||||
}
|
||||
}
|
||||
|
||||
public string Target
|
||||
{
|
||||
get
|
||||
{
|
||||
return _target;
|
||||
}
|
||||
set
|
||||
{
|
||||
_target = value;
|
||||
OnPropertyChanged("Target");
|
||||
}
|
||||
}
|
||||
|
||||
public string Type
|
||||
{
|
||||
get
|
||||
{
|
||||
return _type;
|
||||
}
|
||||
set
|
||||
{
|
||||
_type = value;
|
||||
OnPropertyChanged("Type");
|
||||
OnPropertyChanged("TypeSymbol");
|
||||
OnPropertyChanged("TypeLabel");
|
||||
}
|
||||
}
|
||||
|
||||
public string TypeSymbol
|
||||
{
|
||||
get
|
||||
{
|
||||
string type = Type;
|
||||
if (1 == 0)
|
||||
{
|
||||
}
|
||||
string result = ((type == "url") ? "\ue774" : ((!(type == "folder")) ? "\uecaa" : "\ue8b7"));
|
||||
if (1 == 0)
|
||||
{
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
public string TypeLabel
|
||||
{
|
||||
get
|
||||
{
|
||||
string type = Type;
|
||||
if (1 == 0)
|
||||
{
|
||||
}
|
||||
string result = ((type == "url") ? "URL" : ((!(type == "folder")) ? "앱" : "폴더"));
|
||||
if (1 == 0)
|
||||
{
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
public event PropertyChangedEventHandler? PropertyChanged;
|
||||
|
||||
protected void OnPropertyChanged([CallerMemberName] string? n = null)
|
||||
{
|
||||
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(n));
|
||||
}
|
||||
}
|
||||
59
.decompiledproj/AxCopilot/ViewModels/BatchCommandModel.cs
Normal file
59
.decompiledproj/AxCopilot/ViewModels/BatchCommandModel.cs
Normal file
@@ -0,0 +1,59 @@
|
||||
using System.ComponentModel;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace AxCopilot.ViewModels;
|
||||
|
||||
public class BatchCommandModel : INotifyPropertyChanged
|
||||
{
|
||||
private string _key = "";
|
||||
|
||||
private string _command = "";
|
||||
|
||||
private bool _showWindow;
|
||||
|
||||
public string Key
|
||||
{
|
||||
get
|
||||
{
|
||||
return _key;
|
||||
}
|
||||
set
|
||||
{
|
||||
_key = value;
|
||||
OnPropertyChanged("Key");
|
||||
}
|
||||
}
|
||||
|
||||
public string Command
|
||||
{
|
||||
get
|
||||
{
|
||||
return _command;
|
||||
}
|
||||
set
|
||||
{
|
||||
_command = value;
|
||||
OnPropertyChanged("Command");
|
||||
}
|
||||
}
|
||||
|
||||
public bool ShowWindow
|
||||
{
|
||||
get
|
||||
{
|
||||
return _showWindow;
|
||||
}
|
||||
set
|
||||
{
|
||||
_showWindow = value;
|
||||
OnPropertyChanged("ShowWindow");
|
||||
}
|
||||
}
|
||||
|
||||
public event PropertyChangedEventHandler? PropertyChanged;
|
||||
|
||||
protected void OnPropertyChanged([CallerMemberName] string? n = null)
|
||||
{
|
||||
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(n));
|
||||
}
|
||||
}
|
||||
57
.decompiledproj/AxCopilot/ViewModels/ColorRowModel.cs
Normal file
57
.decompiledproj/AxCopilot/ViewModels/ColorRowModel.cs
Normal file
@@ -0,0 +1,57 @@
|
||||
using System.ComponentModel;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace AxCopilot.ViewModels;
|
||||
|
||||
public class ColorRowModel : INotifyPropertyChanged
|
||||
{
|
||||
private string _hex;
|
||||
|
||||
public string Label { get; init; } = "";
|
||||
|
||||
public string Property { get; init; } = "";
|
||||
|
||||
public string Hex
|
||||
{
|
||||
get
|
||||
{
|
||||
return _hex;
|
||||
}
|
||||
set
|
||||
{
|
||||
_hex = value;
|
||||
OnPropertyChanged("Hex");
|
||||
OnPropertyChanged("Preview");
|
||||
}
|
||||
}
|
||||
|
||||
public SolidColorBrush Preview
|
||||
{
|
||||
get
|
||||
{
|
||||
try
|
||||
{
|
||||
return new SolidColorBrush((Color)ColorConverter.ConvertFromString(Hex));
|
||||
}
|
||||
catch
|
||||
{
|
||||
return new SolidColorBrush(Colors.Transparent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public event PropertyChangedEventHandler? PropertyChanged;
|
||||
|
||||
public ColorRowModel(string label, string property, string hex)
|
||||
{
|
||||
Label = label;
|
||||
Property = property;
|
||||
_hex = hex;
|
||||
}
|
||||
|
||||
protected void OnPropertyChanged([CallerMemberName] string? n = null)
|
||||
{
|
||||
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(n));
|
||||
}
|
||||
}
|
||||
12
.decompiledproj/AxCopilot/ViewModels/CommandStatItem.cs
Normal file
12
.decompiledproj/AxCopilot/ViewModels/CommandStatItem.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
namespace AxCopilot.ViewModels;
|
||||
|
||||
public class CommandStatItem
|
||||
{
|
||||
public int Rank { get; init; }
|
||||
|
||||
public string Command { get; init; } = "";
|
||||
|
||||
public int Count { get; init; }
|
||||
|
||||
public double BarWidth { get; init; }
|
||||
}
|
||||
20
.decompiledproj/AxCopilot/ViewModels/DayBarItem.cs
Normal file
20
.decompiledproj/AxCopilot/ViewModels/DayBarItem.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
namespace AxCopilot.ViewModels;
|
||||
|
||||
public class DayBarItem
|
||||
{
|
||||
public string DateLabel { get; init; } = "";
|
||||
|
||||
public string DayLabel { get; init; } = "";
|
||||
|
||||
public int Value { get; init; }
|
||||
|
||||
public double BarHeight { get; init; }
|
||||
|
||||
public string ValueLabel { get; init; } = "";
|
||||
|
||||
public string ToolTipText { get; init; } = "";
|
||||
|
||||
public bool IsToday { get; init; }
|
||||
|
||||
public bool HasData => Value > 0;
|
||||
}
|
||||
14
.decompiledproj/AxCopilot/ViewModels/FavoriteStatItem.cs
Normal file
14
.decompiledproj/AxCopilot/ViewModels/FavoriteStatItem.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
namespace AxCopilot.ViewModels;
|
||||
|
||||
public class FavoriteStatItem
|
||||
{
|
||||
public int Rank { get; init; }
|
||||
|
||||
public string Name { get; init; } = "";
|
||||
|
||||
public string Path { get; init; } = "";
|
||||
|
||||
public string Icon { get; init; } = "\ue8b7";
|
||||
|
||||
public bool Exists { get; init; }
|
||||
}
|
||||
13
.decompiledproj/AxCopilot/ViewModels/FileAction.cs
Normal file
13
.decompiledproj/AxCopilot/ViewModels/FileAction.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
namespace AxCopilot.ViewModels;
|
||||
|
||||
public enum FileAction
|
||||
{
|
||||
CopyPath,
|
||||
CopyFullPath,
|
||||
OpenExplorer,
|
||||
RunAsAdmin,
|
||||
OpenTerminal,
|
||||
ShowProperties,
|
||||
Rename,
|
||||
DeleteToRecycleBin
|
||||
}
|
||||
3
.decompiledproj/AxCopilot/ViewModels/FileActionData.cs
Normal file
3
.decompiledproj/AxCopilot/ViewModels/FileActionData.cs
Normal file
@@ -0,0 +1,3 @@
|
||||
namespace AxCopilot.ViewModels;
|
||||
|
||||
public record FileActionData(string Path, FileAction Action);
|
||||
971
.decompiledproj/AxCopilot/ViewModels/LauncherViewModel.cs
Normal file
971
.decompiledproj/AxCopilot/ViewModels/LauncherViewModel.cs
Normal file
@@ -0,0 +1,971 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Threading;
|
||||
using AxCopilot.Core;
|
||||
using AxCopilot.Handlers;
|
||||
using AxCopilot.Models;
|
||||
using AxCopilot.SDK;
|
||||
using AxCopilot.Services;
|
||||
|
||||
namespace AxCopilot.ViewModels;
|
||||
|
||||
public class LauncherViewModel : INotifyPropertyChanged
|
||||
{
|
||||
private sealed class FavJson
|
||||
{
|
||||
[JsonPropertyName("name")]
|
||||
public string Name { get; set; } = "";
|
||||
|
||||
[JsonPropertyName("path")]
|
||||
public string Path { get; set; } = "";
|
||||
}
|
||||
|
||||
private readonly CommandResolver _resolver;
|
||||
|
||||
private readonly SettingsService _settings;
|
||||
|
||||
private string _inputText = "";
|
||||
|
||||
private LauncherItem? _selectedItem;
|
||||
|
||||
private bool _isLoading;
|
||||
|
||||
private CancellationTokenSource? _searchCts;
|
||||
|
||||
private Timer? _debounceTimer;
|
||||
|
||||
private const int DebounceMs = 30;
|
||||
|
||||
private string _lastSearchQuery = "";
|
||||
|
||||
private bool _isActionMode;
|
||||
|
||||
private LauncherItem? _actionSourceItem;
|
||||
|
||||
private string _savedQuery = "";
|
||||
|
||||
private readonly HashSet<ClipboardEntry> _mergeQueue = new HashSet<ClipboardEntry>();
|
||||
|
||||
private string _placeholderText = L10n.Get("placeholder");
|
||||
|
||||
private static readonly Dictionary<string, (string Label, string Symbol, string ColorHex)> PrefixMap = new Dictionary<string, (string, string, string)>
|
||||
{
|
||||
{
|
||||
"@",
|
||||
("URL", "\ue774", "#0078D4")
|
||||
},
|
||||
{
|
||||
"~",
|
||||
("워크", "\ue8a1", "#C50F1F")
|
||||
},
|
||||
{
|
||||
">",
|
||||
("명령", "\ue756", "#323130")
|
||||
},
|
||||
{
|
||||
"$",
|
||||
("클립", "\ue77f", "#8764B8")
|
||||
},
|
||||
{
|
||||
"cd",
|
||||
("폴더", "\ue8b7", "#107C10")
|
||||
},
|
||||
{
|
||||
"#",
|
||||
("히스", "\ue81c", "#B7791F")
|
||||
},
|
||||
{
|
||||
";",
|
||||
("스닛", "\ue70b", "#0F6CBD")
|
||||
},
|
||||
{
|
||||
"=",
|
||||
("계산", "\ue8ef", "#4B5EFC")
|
||||
},
|
||||
{
|
||||
"!",
|
||||
("AI", "\ue8bd", "#8B2FC9")
|
||||
},
|
||||
{
|
||||
"?",
|
||||
("검색", "\ue774", "#006EAF")
|
||||
},
|
||||
{
|
||||
"/",
|
||||
("시스템", "\ue7e8", "#4A4A4A")
|
||||
},
|
||||
{
|
||||
"kill ",
|
||||
("킬", "\uea39", "#CC2222")
|
||||
},
|
||||
{
|
||||
"media ",
|
||||
("미디어", "\ue768", "#1A6B3C")
|
||||
},
|
||||
{
|
||||
"info ",
|
||||
("시스템", "\ue7f4", "#5B4E7E")
|
||||
},
|
||||
{
|
||||
"port",
|
||||
("포트", "\ue968", "#006699")
|
||||
},
|
||||
{
|
||||
"emoji",
|
||||
("이모지", "\ue76e", "#F59E0B")
|
||||
},
|
||||
{
|
||||
"color",
|
||||
("색상", "\ue771", "#EC4899")
|
||||
},
|
||||
{
|
||||
"recent",
|
||||
("최근", "\ue81c", "#059669")
|
||||
},
|
||||
{
|
||||
"note",
|
||||
("메모", "\ue70b", "#7C3AED")
|
||||
},
|
||||
{
|
||||
"uninstall",
|
||||
("제거", "\ue74d", "#DC2626")
|
||||
},
|
||||
{
|
||||
"env",
|
||||
("환경변수", "\ue8d7", "#0D9488")
|
||||
},
|
||||
{
|
||||
"json",
|
||||
("JSON", "\ue930", "#D97706")
|
||||
},
|
||||
{
|
||||
"encode ",
|
||||
("인코딩", "\ue8cb", "#6366F1")
|
||||
},
|
||||
{
|
||||
"snap",
|
||||
("스냅", "\ue8a0", "#B45309")
|
||||
},
|
||||
{
|
||||
"cap",
|
||||
("캡처", "\ue722", "#BE185D")
|
||||
},
|
||||
{
|
||||
"help",
|
||||
("도움말", "\ue946", "#6B7280")
|
||||
}
|
||||
};
|
||||
|
||||
public BulkObservableCollection<LauncherItem> Results { get; } = new BulkObservableCollection<LauncherItem>();
|
||||
|
||||
public string InputText
|
||||
{
|
||||
get
|
||||
{
|
||||
return _inputText;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (_inputText == value)
|
||||
{
|
||||
return;
|
||||
}
|
||||
_inputText = value;
|
||||
OnPropertyChanged("InputText");
|
||||
OnPropertyChanged("HasActivePrefix");
|
||||
OnPropertyChanged("ActivePrefixLabel");
|
||||
OnPropertyChanged("ActivePrefixSymbol");
|
||||
OnPropertyChanged("ActivePrefixBrush");
|
||||
OnPropertyChanged("IsClipboardMode");
|
||||
OnPropertyChanged("ShowMergeHint");
|
||||
OnPropertyChanged("MergeHintText");
|
||||
_searchCts?.Cancel();
|
||||
_debounceTimer?.Dispose();
|
||||
if (string.IsNullOrWhiteSpace(value))
|
||||
{
|
||||
Results.Clear();
|
||||
return;
|
||||
}
|
||||
string captured = value;
|
||||
_debounceTimer = new Timer(delegate(object? _)
|
||||
{
|
||||
Application current = Application.Current;
|
||||
if (current != null)
|
||||
{
|
||||
((DispatcherObject)current).Dispatcher.InvokeAsync<object>((Func<object>)(() => _ = SearchAsync(captured)));
|
||||
}
|
||||
}, null, 30, -1);
|
||||
}
|
||||
}
|
||||
|
||||
public LauncherItem? SelectedItem
|
||||
{
|
||||
get
|
||||
{
|
||||
return _selectedItem;
|
||||
}
|
||||
set
|
||||
{
|
||||
_selectedItem = value;
|
||||
OnPropertyChanged("SelectedItem");
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsLoading
|
||||
{
|
||||
get
|
||||
{
|
||||
return _isLoading;
|
||||
}
|
||||
set
|
||||
{
|
||||
_isLoading = value;
|
||||
OnPropertyChanged("IsLoading");
|
||||
}
|
||||
}
|
||||
|
||||
public string PlaceholderText
|
||||
{
|
||||
get
|
||||
{
|
||||
return _placeholderText;
|
||||
}
|
||||
private set
|
||||
{
|
||||
_placeholderText = value;
|
||||
OnPropertyChanged("PlaceholderText");
|
||||
}
|
||||
}
|
||||
|
||||
public bool EnableIconAnimation => _settings.Settings.Launcher.EnableIconAnimation;
|
||||
|
||||
public bool EnableRainbowGlow => _settings.Settings.Launcher.EnableRainbowGlow;
|
||||
|
||||
public bool EnableSelectionGlow => _settings.Settings.Launcher.EnableSelectionGlow;
|
||||
|
||||
public bool ShowLauncherBorder => _settings.Settings.Launcher.ShowLauncherBorder;
|
||||
|
||||
public string ThemeSetting => _settings.Settings.Launcher.Theme;
|
||||
|
||||
public CustomThemeColors? CustomThemeColors => _settings.Settings.Launcher.CustomTheme;
|
||||
|
||||
public string WindowPosition => _settings.Settings.Launcher.Position;
|
||||
|
||||
public bool ShowNumberBadges => _settings.Settings.Launcher.ShowNumberBadges;
|
||||
|
||||
public bool CloseOnFocusLost => _settings.Settings.Launcher.CloseOnFocusLost;
|
||||
|
||||
public bool EnableActionMode => _settings.Settings.Launcher.EnableActionMode;
|
||||
|
||||
public bool HasActivePrefix => _settings.Settings.Launcher.ShowPrefixBadge && _inputText.Length > 0 && PrefixMap.Keys.Any((string k) => (k != "!" || IsAiEnabled()) && _inputText.StartsWith(k, StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
public string? ActivePrefix => PrefixMap.Keys.FirstOrDefault((string k) => (k != "!" || IsAiEnabled()) && _inputText.StartsWith(k, StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
public string ActivePrefixLabel
|
||||
{
|
||||
get
|
||||
{
|
||||
object result;
|
||||
if (ActivePrefix != null && PrefixMap.TryGetValue(ActivePrefix, out (string, string, string) value))
|
||||
{
|
||||
(result, _, _) = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = "";
|
||||
}
|
||||
return (string)result;
|
||||
}
|
||||
}
|
||||
|
||||
public string ActivePrefixSymbol
|
||||
{
|
||||
get
|
||||
{
|
||||
(string, string, string) value;
|
||||
return (ActivePrefix != null && PrefixMap.TryGetValue(ActivePrefix, out value)) ? value.Item2 : "\ue721";
|
||||
}
|
||||
}
|
||||
|
||||
public SolidColorBrush ActivePrefixBrush
|
||||
{
|
||||
get
|
||||
{
|
||||
if (ActivePrefix != null && PrefixMap.TryGetValue(ActivePrefix, out (string, string, string) value))
|
||||
{
|
||||
Color color = (Color)ColorConverter.ConvertFromString(value.Item3);
|
||||
return new SolidColorBrush(color);
|
||||
}
|
||||
return new SolidColorBrush(Color.FromRgb(75, 94, 252));
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsActionMode
|
||||
{
|
||||
get
|
||||
{
|
||||
return _isActionMode;
|
||||
}
|
||||
private set
|
||||
{
|
||||
_isActionMode = value;
|
||||
OnPropertyChanged("IsActionMode");
|
||||
OnPropertyChanged("ShowActionModeBar");
|
||||
OnPropertyChanged("ActionModeBreadcrumb");
|
||||
}
|
||||
}
|
||||
|
||||
public bool ShowActionModeBar => IsActionMode;
|
||||
|
||||
public string ActionModeBreadcrumb => _actionSourceItem?.Title ?? "";
|
||||
|
||||
public bool IsClipboardMode => _inputText.StartsWith("#", StringComparison.Ordinal);
|
||||
|
||||
public int MergeCount => _mergeQueue.Count;
|
||||
|
||||
public bool ShowMergeHint => _mergeQueue.Count > 0 && IsClipboardMode;
|
||||
|
||||
public string MergeHintText => (_mergeQueue.Count > 0) ? $"{_mergeQueue.Count}개 선택됨 · Shift+Enter로 합치기 · Esc로 취소" : "";
|
||||
|
||||
public event EventHandler? CloseRequested;
|
||||
|
||||
public event EventHandler<string>? NotificationRequested;
|
||||
|
||||
public event PropertyChangedEventHandler? PropertyChanged;
|
||||
|
||||
public void RefreshPlaceholder()
|
||||
{
|
||||
PlaceholderText = (_settings.Settings.Launcher.EnableRandomPlaceholder ? L10n.GetRandomPlaceholder() : L10n.Get("placeholder"));
|
||||
}
|
||||
|
||||
private static bool IsAiEnabled()
|
||||
{
|
||||
return (Application.Current as App)?.SettingsService?.Settings.AiEnabled ?? true;
|
||||
}
|
||||
|
||||
public bool CanEnterActionMode()
|
||||
{
|
||||
return !IsActionMode && SelectedItem?.Data is IndexEntry;
|
||||
}
|
||||
|
||||
public bool IsItemMarkedForMerge(LauncherItem item)
|
||||
{
|
||||
return item.Data is ClipboardEntry item2 && _mergeQueue.Contains(item2);
|
||||
}
|
||||
|
||||
public LauncherViewModel(CommandResolver resolver, SettingsService settings)
|
||||
{
|
||||
_resolver = resolver;
|
||||
_settings = settings;
|
||||
}
|
||||
|
||||
public void OnShown()
|
||||
{
|
||||
if (IsActionMode)
|
||||
{
|
||||
IsActionMode = false;
|
||||
_actionSourceItem = null;
|
||||
}
|
||||
Results.Clear();
|
||||
_lastSearchQuery = "";
|
||||
ClearMerge();
|
||||
}
|
||||
|
||||
internal Task TriggerImeSearchAsync(string text)
|
||||
{
|
||||
string text2 = text.Trim().ToLowerInvariant();
|
||||
if (text2 == _lastSearchQuery && Results.Count > 0)
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
return SearchAsync(text);
|
||||
}
|
||||
|
||||
private async Task SearchAsync(string query)
|
||||
{
|
||||
_searchCts = new CancellationTokenSource();
|
||||
CancellationToken ct = _searchCts.Token;
|
||||
string queryKey = query.Trim().ToLowerInvariant();
|
||||
bool isSameQuery = queryKey == _lastSearchQuery && Results.Count > 0;
|
||||
if (!isSameQuery)
|
||||
{
|
||||
Results.Clear();
|
||||
}
|
||||
if (string.IsNullOrWhiteSpace(query))
|
||||
{
|
||||
_lastSearchQuery = "";
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((!_settings.Settings.Launcher.EnableFavorites && query.StartsWith("fav", StringComparison.OrdinalIgnoreCase)) || (!_settings.Settings.Launcher.EnableRecent && query.StartsWith("recent", StringComparison.OrdinalIgnoreCase)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
LauncherItem prevSelected = (isSameQuery ? SelectedItem : null);
|
||||
IsLoading = true;
|
||||
try
|
||||
{
|
||||
IEnumerable<LauncherItem> items = await _resolver.ResolveAsync(query, ct);
|
||||
if (ct.IsCancellationRequested)
|
||||
{
|
||||
return;
|
||||
}
|
||||
Results.ReplaceAll(items);
|
||||
_lastSearchQuery = queryKey;
|
||||
if (isSameQuery && prevSelected != null)
|
||||
{
|
||||
LauncherItem restored = Results.FirstOrDefault((LauncherItem r) => r.Data == prevSelected.Data || r.Title == prevSelected.Title);
|
||||
SelectedItem = restored ?? Results.FirstOrDefault();
|
||||
}
|
||||
else
|
||||
{
|
||||
SelectedItem = Results.FirstOrDefault();
|
||||
}
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
}
|
||||
catch (Exception ex2)
|
||||
{
|
||||
Exception ex3 = ex2;
|
||||
LogService.Error("검색 오류: " + ex3.Message);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (!ct.IsCancellationRequested)
|
||||
{
|
||||
IsLoading = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public async Task ExecuteSelectedAsync()
|
||||
{
|
||||
FileActionData fileAction = default(FileActionData);
|
||||
int num;
|
||||
if (IsActionMode)
|
||||
{
|
||||
object obj = SelectedItem?.Data;
|
||||
fileAction = obj as FileActionData;
|
||||
num = (((object)fileAction != null) ? 1 : 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
num = 0;
|
||||
}
|
||||
if (num != 0)
|
||||
{
|
||||
ExecuteFileAction(fileAction);
|
||||
ExitActionMode();
|
||||
this.CloseRequested?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
else if (!(SelectedItem == null))
|
||||
{
|
||||
this.CloseRequested?.Invoke(this, EventArgs.Empty);
|
||||
try
|
||||
{
|
||||
await _resolver.ExecuteAsync(SelectedItem, InputText, CancellationToken.None);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
this.NotificationRequested?.Invoke(this, "실행 실패: " + ex.Message);
|
||||
LogService.Error("Execute 오류: " + ex.Message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool ShowDelayTimerItems()
|
||||
{
|
||||
if (!(SelectedItem?.Data is string text))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (text.StartsWith("delay:"))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (!_resolver.RegisteredHandlers.TryGetValue(ActivePrefix ?? "", out IActionHandler value) || !(value is ScreenCaptureHandler screenCaptureHandler))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
List<LauncherItem> list = screenCaptureHandler.GetDelayItems(text).ToList();
|
||||
Results.Clear();
|
||||
foreach (LauncherItem item in list)
|
||||
{
|
||||
Results.Add(item);
|
||||
}
|
||||
SelectedItem = Results.FirstOrDefault();
|
||||
return true;
|
||||
}
|
||||
|
||||
public void SelectNext()
|
||||
{
|
||||
if (Results.Count != 0)
|
||||
{
|
||||
int num = ((SelectedItem != null) ? Results.IndexOf(SelectedItem) : (-1));
|
||||
SelectedItem = Results[(num + 1) % Results.Count];
|
||||
}
|
||||
}
|
||||
|
||||
public void SelectPrev()
|
||||
{
|
||||
if (Results.Count != 0)
|
||||
{
|
||||
int num = ((SelectedItem != null) ? Results.IndexOf(SelectedItem) : 0);
|
||||
SelectedItem = Results[(num - 1 + Results.Count) % Results.Count];
|
||||
}
|
||||
}
|
||||
|
||||
public string GetLargeTypeText()
|
||||
{
|
||||
if (SelectedItem == null)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
if (SelectedItem.Data is string text && !string.IsNullOrWhiteSpace(text))
|
||||
{
|
||||
return text;
|
||||
}
|
||||
if (SelectedItem.Data is ClipboardEntry { IsText: not false } clipboardEntry)
|
||||
{
|
||||
return clipboardEntry.Text;
|
||||
}
|
||||
return SelectedItem.Title;
|
||||
}
|
||||
|
||||
public void EnterActionMode(LauncherItem item)
|
||||
{
|
||||
if (_settings.Settings.Launcher.EnableActionMode && item.Data is IndexEntry indexEntry)
|
||||
{
|
||||
_actionSourceItem = item;
|
||||
_savedQuery = _inputText;
|
||||
IsActionMode = true;
|
||||
string text = Environment.ExpandEnvironmentVariables(indexEntry.Path);
|
||||
bool flag = Directory.Exists(text);
|
||||
string fileName = Path.GetFileName(text);
|
||||
Results.Clear();
|
||||
Results.Add(MakeAction("경로 복사", text, FileAction.CopyPath, "\ue77f", "#8764B8"));
|
||||
Results.Add(MakeAction("전체 경로 복사", text, FileAction.CopyFullPath, "\ue77f", "#C55A11"));
|
||||
Results.Add(MakeAction("파일 탐색기에서 열기", "Explorer에서 위치 선택됨으로 표시", FileAction.OpenExplorer, "\ue8b7", "#107C10"));
|
||||
if (!flag)
|
||||
{
|
||||
Results.Add(MakeAction("관리자 권한으로 실행", "UAC 권한 상승 후 실행", FileAction.RunAsAdmin, "\ue72e", "#C50F1F"));
|
||||
}
|
||||
Results.Add(MakeAction("터미널에서 열기", flag ? text : (Path.GetDirectoryName(text) ?? text), FileAction.OpenTerminal, "\ue756", "#323130"));
|
||||
if (!flag)
|
||||
{
|
||||
Results.Add(MakeAction("파일 속성 보기", "Windows 속성 대화 상자 열기", FileAction.ShowProperties, "\ue946", "#6B2C91"));
|
||||
}
|
||||
Results.Add(MakeAction("이름 바꾸기", fileName, FileAction.Rename, "\ue8ac", "#D97706"));
|
||||
Results.Add(MakeAction("휴지통으로 삭제", "복구 가능한 삭제 · 확인 후 실행", FileAction.DeleteToRecycleBin, "\ue74d", "#C50F1F"));
|
||||
SelectedItem = Results.FirstOrDefault();
|
||||
}
|
||||
static LauncherItem MakeAction(string title, string subtitle, FileAction action, string symbol, string colorHex)
|
||||
{
|
||||
FileActionData data = new FileActionData(subtitle, action);
|
||||
return new LauncherItem(title, subtitle, null, data, null, symbol);
|
||||
}
|
||||
}
|
||||
|
||||
public void ExitActionMode()
|
||||
{
|
||||
IsActionMode = false;
|
||||
_actionSourceItem = null;
|
||||
string savedQuery = _savedQuery;
|
||||
_savedQuery = "";
|
||||
SearchAsync(savedQuery);
|
||||
}
|
||||
|
||||
private static void ExecuteFileAction(FileActionData data)
|
||||
{
|
||||
string path = data.Path;
|
||||
switch (data.Action)
|
||||
{
|
||||
case FileAction.CopyPath:
|
||||
((DispatcherObject)Application.Current).Dispatcher.Invoke((Action)delegate
|
||||
{
|
||||
Clipboard.SetText(path);
|
||||
});
|
||||
break;
|
||||
case FileAction.OpenExplorer:
|
||||
if (File.Exists(path))
|
||||
{
|
||||
Process.Start("explorer.exe", "/select,\"" + path + "\"");
|
||||
}
|
||||
else
|
||||
{
|
||||
Process.Start("explorer.exe", "\"" + path + "\"");
|
||||
}
|
||||
break;
|
||||
case FileAction.RunAsAdmin:
|
||||
try
|
||||
{
|
||||
Process.Start(new ProcessStartInfo(path)
|
||||
{
|
||||
UseShellExecute = true,
|
||||
Verb = "runas"
|
||||
});
|
||||
break;
|
||||
}
|
||||
catch (Exception ex2)
|
||||
{
|
||||
LogService.Warn("관리자 실행 취소: " + ex2.Message);
|
||||
break;
|
||||
}
|
||||
case FileAction.CopyFullPath:
|
||||
((DispatcherObject)Application.Current).Dispatcher.Invoke((Action)delegate
|
||||
{
|
||||
Clipboard.SetText(path);
|
||||
});
|
||||
break;
|
||||
case FileAction.ShowProperties:
|
||||
try
|
||||
{
|
||||
ProcessStartInfo startInfo = new ProcessStartInfo("explorer.exe")
|
||||
{
|
||||
Arguments = "/select,\"" + path + "\"",
|
||||
UseShellExecute = true
|
||||
};
|
||||
Process.Start(startInfo);
|
||||
ProcessStartInfo processStartInfo = new ProcessStartInfo
|
||||
{
|
||||
FileName = "rundll32.exe",
|
||||
Arguments = "shell32.dll,ShellExec_RunDLL \"properties\" \"" + path + "\"",
|
||||
UseShellExecute = false
|
||||
};
|
||||
try
|
||||
{
|
||||
Process.Start(new ProcessStartInfo(path)
|
||||
{
|
||||
UseShellExecute = true,
|
||||
Verb = "properties"
|
||||
});
|
||||
break;
|
||||
}
|
||||
catch
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (Exception ex3)
|
||||
{
|
||||
LogService.Warn("속성 열기 실패: " + ex3.Message);
|
||||
break;
|
||||
}
|
||||
case FileAction.Rename:
|
||||
break;
|
||||
case FileAction.DeleteToRecycleBin:
|
||||
break;
|
||||
case FileAction.OpenTerminal:
|
||||
{
|
||||
string text = (File.Exists(path) ? (Path.GetDirectoryName(path) ?? path) : path);
|
||||
try
|
||||
{
|
||||
Process.Start("wt.exe", "-d \"" + text + "\"");
|
||||
break;
|
||||
}
|
||||
catch
|
||||
{
|
||||
try
|
||||
{
|
||||
Process.Start("cmd.exe", "/k cd /d \"" + text + "\"");
|
||||
break;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogService.Warn("터미널 열기 실패: " + ex.Message);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool CopySelectedPath()
|
||||
{
|
||||
if (SelectedItem?.Data is IndexEntry indexEntry)
|
||||
{
|
||||
string path = Path.GetFileName(Environment.ExpandEnvironmentVariables(indexEntry.Path));
|
||||
((DispatcherObject)Application.Current).Dispatcher.Invoke((Action)delegate
|
||||
{
|
||||
Clipboard.SetText(path);
|
||||
});
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool CopySelectedFullPath()
|
||||
{
|
||||
if (SelectedItem?.Data is IndexEntry indexEntry)
|
||||
{
|
||||
string path = Environment.ExpandEnvironmentVariables(indexEntry.Path);
|
||||
((DispatcherObject)Application.Current).Dispatcher.Invoke((Action)delegate
|
||||
{
|
||||
Clipboard.SetText(path);
|
||||
});
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool OpenSelectedInExplorer()
|
||||
{
|
||||
if (SelectedItem?.Data is IndexEntry indexEntry)
|
||||
{
|
||||
string text = Environment.ExpandEnvironmentVariables(indexEntry.Path);
|
||||
if (File.Exists(text))
|
||||
{
|
||||
Process.Start("explorer.exe", "/select,\"" + text + "\"");
|
||||
}
|
||||
else if (Directory.Exists(text))
|
||||
{
|
||||
Process.Start("explorer.exe", "\"" + text + "\"");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool RunSelectedAsAdmin()
|
||||
{
|
||||
if (SelectedItem?.Data is IndexEntry indexEntry)
|
||||
{
|
||||
string fileName = Environment.ExpandEnvironmentVariables(indexEntry.Path);
|
||||
try
|
||||
{
|
||||
Process.Start(new ProcessStartInfo(fileName)
|
||||
{
|
||||
UseShellExecute = true,
|
||||
Verb = "runas"
|
||||
});
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogService.Warn("관리자 실행 취소: " + ex.Message);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool ShowSelectedProperties()
|
||||
{
|
||||
if (SelectedItem?.Data is IndexEntry indexEntry)
|
||||
{
|
||||
string text = Environment.ExpandEnvironmentVariables(indexEntry.Path);
|
||||
try
|
||||
{
|
||||
Process.Start(new ProcessStartInfo(text)
|
||||
{
|
||||
UseShellExecute = true,
|
||||
Verb = "properties"
|
||||
});
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
Process.Start("explorer.exe", "/select,\"" + text + "\"");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool RemoveSelectedFromRecent()
|
||||
{
|
||||
if (SelectedItem == null || Results.Count == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
int val = Results.IndexOf(SelectedItem);
|
||||
Results.Remove(SelectedItem);
|
||||
if (Results.Count > 0)
|
||||
{
|
||||
SelectedItem = Results[Math.Min(val, Results.Count - 1)];
|
||||
}
|
||||
else
|
||||
{
|
||||
SelectedItem = null;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public void ClearInput()
|
||||
{
|
||||
InputText = "";
|
||||
}
|
||||
|
||||
public void SelectFirst()
|
||||
{
|
||||
if (Results.Count > 0)
|
||||
{
|
||||
SelectedItem = Results[0];
|
||||
}
|
||||
}
|
||||
|
||||
public void SelectLast()
|
||||
{
|
||||
if (Results.Count > 0)
|
||||
{
|
||||
BulkObservableCollection<LauncherItem> results = Results;
|
||||
SelectedItem = results[results.Count - 1];
|
||||
}
|
||||
}
|
||||
|
||||
public bool? ToggleFavorite()
|
||||
{
|
||||
if (!(SelectedItem?.Data is IndexEntry indexEntry))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
string path = Environment.ExpandEnvironmentVariables(indexEntry.Path);
|
||||
string text = Path.GetFileNameWithoutExtension(path);
|
||||
if (string.IsNullOrWhiteSpace(text))
|
||||
{
|
||||
text = Path.GetFileName(path);
|
||||
}
|
||||
string path2 = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "AxCopilot", "favorites.json");
|
||||
try
|
||||
{
|
||||
JsonSerializerOptions options = new JsonSerializerOptions
|
||||
{
|
||||
WriteIndented = true,
|
||||
PropertyNameCaseInsensitive = true
|
||||
};
|
||||
List<FavJson> list = new List<FavJson>();
|
||||
if (File.Exists(path2))
|
||||
{
|
||||
list = JsonSerializer.Deserialize<List<FavJson>>(File.ReadAllText(path2), options) ?? new List<FavJson>();
|
||||
}
|
||||
FavJson favJson = list.FirstOrDefault((FavJson f) => f.Path.Equals(path, StringComparison.OrdinalIgnoreCase));
|
||||
if (favJson != null)
|
||||
{
|
||||
list.Remove(favJson);
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(path2));
|
||||
File.WriteAllText(path2, JsonSerializer.Serialize(list, options));
|
||||
return false;
|
||||
}
|
||||
list.Insert(0, new FavJson
|
||||
{
|
||||
Name = text,
|
||||
Path = path
|
||||
});
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(path2));
|
||||
File.WriteAllText(path2, JsonSerializer.Serialize(list, options));
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogService.Warn("즐겨찾기 토글 실패: " + ex.Message);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public bool OpenSelectedInTerminal()
|
||||
{
|
||||
string text2;
|
||||
if (SelectedItem?.Data is IndexEntry indexEntry)
|
||||
{
|
||||
string text = Environment.ExpandEnvironmentVariables(indexEntry.Path);
|
||||
text2 = (Directory.Exists(text) ? text : (Path.GetDirectoryName(text) ?? text));
|
||||
}
|
||||
else
|
||||
{
|
||||
text2 = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
|
||||
}
|
||||
try
|
||||
{
|
||||
Process.Start("wt.exe", "-d \"" + text2 + "\"");
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
try
|
||||
{
|
||||
Process.Start("cmd.exe", "/k cd /d \"" + text2 + "\"");
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogService.Warn("터미널 열기 실패: " + ex.Message);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void NavigateToDownloads()
|
||||
{
|
||||
string text = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), "Downloads");
|
||||
InputText = "cd " + text;
|
||||
}
|
||||
|
||||
public void ToggleMergeItem(LauncherItem? item)
|
||||
{
|
||||
if (item?.Data is ClipboardEntry { IsText: not false } clipboardEntry)
|
||||
{
|
||||
if (!_mergeQueue.Remove(clipboardEntry))
|
||||
{
|
||||
_mergeQueue.Add(clipboardEntry);
|
||||
}
|
||||
OnPropertyChanged("MergeCount");
|
||||
OnPropertyChanged("ShowMergeHint");
|
||||
OnPropertyChanged("MergeHintText");
|
||||
}
|
||||
}
|
||||
|
||||
public void ExecuteMerge()
|
||||
{
|
||||
if (_mergeQueue.Count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
List<string> list = (from r in Results
|
||||
where r.Data is ClipboardEntry item && _mergeQueue.Contains(item)
|
||||
select ((ClipboardEntry)r.Data).Text).ToList();
|
||||
if (list.Count == 0)
|
||||
{
|
||||
list = _mergeQueue.Select((ClipboardEntry e) => e.Text).ToList();
|
||||
}
|
||||
string merged = string.Join("\n", list);
|
||||
try
|
||||
{
|
||||
((DispatcherObject)Application.Current).Dispatcher.Invoke((Action)delegate
|
||||
{
|
||||
Clipboard.SetText(merged);
|
||||
});
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogService.Warn("병합 클립보드 실패: " + ex.Message);
|
||||
}
|
||||
ClearMerge();
|
||||
this.CloseRequested?.Invoke(this, EventArgs.Empty);
|
||||
LogService.Info($"클립보드 병합: {list.Count}개 항목");
|
||||
}
|
||||
|
||||
public void ClearMerge()
|
||||
{
|
||||
_mergeQueue.Clear();
|
||||
OnPropertyChanged("MergeCount");
|
||||
OnPropertyChanged("ShowMergeHint");
|
||||
OnPropertyChanged("MergeHintText");
|
||||
}
|
||||
|
||||
protected void OnPropertyChanged([CallerMemberName] string? name = null)
|
||||
{
|
||||
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
|
||||
}
|
||||
}
|
||||
62
.decompiledproj/AxCopilot/ViewModels/PromptTemplateRow.cs
Normal file
62
.decompiledproj/AxCopilot/ViewModels/PromptTemplateRow.cs
Normal file
@@ -0,0 +1,62 @@
|
||||
using System.ComponentModel;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace AxCopilot.ViewModels;
|
||||
|
||||
public class PromptTemplateRow : INotifyPropertyChanged
|
||||
{
|
||||
private string _name = "";
|
||||
|
||||
private string _content = "";
|
||||
|
||||
private string _icon = "\ue8bd";
|
||||
|
||||
public string Name
|
||||
{
|
||||
get
|
||||
{
|
||||
return _name;
|
||||
}
|
||||
set
|
||||
{
|
||||
_name = value;
|
||||
OnPropertyChanged("Name");
|
||||
}
|
||||
}
|
||||
|
||||
public string Content
|
||||
{
|
||||
get
|
||||
{
|
||||
return _content;
|
||||
}
|
||||
set
|
||||
{
|
||||
_content = value;
|
||||
OnPropertyChanged("Content");
|
||||
OnPropertyChanged("Preview");
|
||||
}
|
||||
}
|
||||
|
||||
public string Icon
|
||||
{
|
||||
get
|
||||
{
|
||||
return _icon;
|
||||
}
|
||||
set
|
||||
{
|
||||
_icon = value;
|
||||
OnPropertyChanged("Icon");
|
||||
}
|
||||
}
|
||||
|
||||
public string Preview => (Content.Length > 60) ? (Content.Substring(0, 57).Replace("\n", " ") + "…") : Content.Replace("\n", " ");
|
||||
|
||||
public event PropertyChangedEventHandler? PropertyChanged;
|
||||
|
||||
protected void OnPropertyChanged([CallerMemberName] string? n = null)
|
||||
{
|
||||
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(n));
|
||||
}
|
||||
}
|
||||
161
.decompiledproj/AxCopilot/ViewModels/RegisteredModelRow.cs
Normal file
161
.decompiledproj/AxCopilot/ViewModels/RegisteredModelRow.cs
Normal file
@@ -0,0 +1,161 @@
|
||||
using System.ComponentModel;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace AxCopilot.ViewModels;
|
||||
|
||||
public class RegisteredModelRow : INotifyPropertyChanged
|
||||
{
|
||||
private string _alias = "";
|
||||
|
||||
private string _encryptedModelName = "";
|
||||
|
||||
private string _service = "ollama";
|
||||
|
||||
private string _endpoint = "";
|
||||
|
||||
private string _apiKey = "";
|
||||
|
||||
private string _authType = "bearer";
|
||||
|
||||
private string _cp4dUrl = "";
|
||||
|
||||
private string _cp4dUsername = "";
|
||||
|
||||
private string _cp4dPassword = "";
|
||||
|
||||
public string Alias
|
||||
{
|
||||
get
|
||||
{
|
||||
return _alias;
|
||||
}
|
||||
set
|
||||
{
|
||||
_alias = value;
|
||||
OnPropertyChanged("Alias");
|
||||
}
|
||||
}
|
||||
|
||||
public string EncryptedModelName
|
||||
{
|
||||
get
|
||||
{
|
||||
return _encryptedModelName;
|
||||
}
|
||||
set
|
||||
{
|
||||
_encryptedModelName = value;
|
||||
OnPropertyChanged("EncryptedModelName");
|
||||
OnPropertyChanged("MaskedModelName");
|
||||
}
|
||||
}
|
||||
|
||||
public string Service
|
||||
{
|
||||
get
|
||||
{
|
||||
return _service;
|
||||
}
|
||||
set
|
||||
{
|
||||
_service = value;
|
||||
OnPropertyChanged("Service");
|
||||
OnPropertyChanged("ServiceLabel");
|
||||
}
|
||||
}
|
||||
|
||||
public string Endpoint
|
||||
{
|
||||
get
|
||||
{
|
||||
return _endpoint;
|
||||
}
|
||||
set
|
||||
{
|
||||
_endpoint = value;
|
||||
OnPropertyChanged("Endpoint");
|
||||
OnPropertyChanged("EndpointDisplay");
|
||||
}
|
||||
}
|
||||
|
||||
public string ApiKey
|
||||
{
|
||||
get
|
||||
{
|
||||
return _apiKey;
|
||||
}
|
||||
set
|
||||
{
|
||||
_apiKey = value;
|
||||
OnPropertyChanged("ApiKey");
|
||||
}
|
||||
}
|
||||
|
||||
public string AuthType
|
||||
{
|
||||
get
|
||||
{
|
||||
return _authType;
|
||||
}
|
||||
set
|
||||
{
|
||||
_authType = value;
|
||||
OnPropertyChanged("AuthType");
|
||||
OnPropertyChanged("AuthLabel");
|
||||
}
|
||||
}
|
||||
|
||||
public string Cp4dUrl
|
||||
{
|
||||
get
|
||||
{
|
||||
return _cp4dUrl;
|
||||
}
|
||||
set
|
||||
{
|
||||
_cp4dUrl = value;
|
||||
OnPropertyChanged("Cp4dUrl");
|
||||
}
|
||||
}
|
||||
|
||||
public string Cp4dUsername
|
||||
{
|
||||
get
|
||||
{
|
||||
return _cp4dUsername;
|
||||
}
|
||||
set
|
||||
{
|
||||
_cp4dUsername = value;
|
||||
OnPropertyChanged("Cp4dUsername");
|
||||
}
|
||||
}
|
||||
|
||||
public string Cp4dPassword
|
||||
{
|
||||
get
|
||||
{
|
||||
return _cp4dPassword;
|
||||
}
|
||||
set
|
||||
{
|
||||
_cp4dPassword = value;
|
||||
OnPropertyChanged("Cp4dPassword");
|
||||
}
|
||||
}
|
||||
|
||||
public string AuthLabel => (_authType == "cp4d") ? "CP4D" : "Bearer";
|
||||
|
||||
public string EndpointDisplay => string.IsNullOrEmpty(_endpoint) ? "(기본 서버)" : _endpoint;
|
||||
|
||||
public string MaskedModelName => string.IsNullOrEmpty(_encryptedModelName) ? "(미등록)" : "••••••••";
|
||||
|
||||
public string ServiceLabel => (_service == "vllm") ? "vLLM" : "Ollama";
|
||||
|
||||
public event PropertyChangedEventHandler? PropertyChanged;
|
||||
|
||||
protected void OnPropertyChanged([CallerMemberName] string? n = null)
|
||||
{
|
||||
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(n));
|
||||
}
|
||||
}
|
||||
2813
.decompiledproj/AxCopilot/ViewModels/SettingsViewModel.cs
Normal file
2813
.decompiledproj/AxCopilot/ViewModels/SettingsViewModel.cs
Normal file
File diff suppressed because it is too large
Load Diff
61
.decompiledproj/AxCopilot/ViewModels/SnippetRowModel.cs
Normal file
61
.decompiledproj/AxCopilot/ViewModels/SnippetRowModel.cs
Normal file
@@ -0,0 +1,61 @@
|
||||
using System.ComponentModel;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace AxCopilot.ViewModels;
|
||||
|
||||
public class SnippetRowModel : INotifyPropertyChanged
|
||||
{
|
||||
private string _key = "";
|
||||
|
||||
private string _name = "";
|
||||
|
||||
private string _content = "";
|
||||
|
||||
public string Key
|
||||
{
|
||||
get
|
||||
{
|
||||
return _key;
|
||||
}
|
||||
set
|
||||
{
|
||||
_key = value;
|
||||
OnPropertyChanged("Key");
|
||||
}
|
||||
}
|
||||
|
||||
public string Name
|
||||
{
|
||||
get
|
||||
{
|
||||
return _name;
|
||||
}
|
||||
set
|
||||
{
|
||||
_name = value;
|
||||
OnPropertyChanged("Name");
|
||||
}
|
||||
}
|
||||
|
||||
public string Content
|
||||
{
|
||||
get
|
||||
{
|
||||
return _content;
|
||||
}
|
||||
set
|
||||
{
|
||||
_content = value;
|
||||
OnPropertyChanged("Content");
|
||||
}
|
||||
}
|
||||
|
||||
public string Preview => (Content.Length > 50) ? (Content.Substring(0, 47).Replace("\n", " ") + "…") : Content.Replace("\n", " ");
|
||||
|
||||
public event PropertyChangedEventHandler? PropertyChanged;
|
||||
|
||||
protected void OnPropertyChanged([CallerMemberName] string? n = null)
|
||||
{
|
||||
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(n));
|
||||
}
|
||||
}
|
||||
655
.decompiledproj/AxCopilot/ViewModels/StatisticsViewModel.cs
Normal file
655
.decompiledproj/AxCopilot/ViewModels/StatisticsViewModel.cs
Normal file
@@ -0,0 +1,655 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.ComponentModel;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Windows.Media;
|
||||
using AxCopilot.Models;
|
||||
using AxCopilot.Services;
|
||||
|
||||
namespace AxCopilot.ViewModels;
|
||||
|
||||
public class StatisticsViewModel : INotifyPropertyChanged
|
||||
{
|
||||
private class FavFileEntry
|
||||
{
|
||||
[JsonPropertyName("name")]
|
||||
public string Name { get; set; } = "";
|
||||
|
||||
[JsonPropertyName("path")]
|
||||
public string Path { get; set; } = "";
|
||||
}
|
||||
|
||||
private const double MaxBarHeight = 66.0;
|
||||
|
||||
private const double MaxBarWidth = 200.0;
|
||||
|
||||
private bool _hasFavorites;
|
||||
|
||||
private string _todayDate = "";
|
||||
|
||||
private string _todaySummary = "";
|
||||
|
||||
private string _peakDate = "";
|
||||
|
||||
private string _peakDaySummary = "";
|
||||
|
||||
private string _weekSummary = "";
|
||||
|
||||
private string _totalOpensSummary = "";
|
||||
|
||||
private string _agentSummary = "";
|
||||
|
||||
private double _promptBarWidth;
|
||||
|
||||
private double _completionBarWidth;
|
||||
|
||||
private string _promptTokenLabel = "";
|
||||
|
||||
private string _completionTokenLabel = "";
|
||||
|
||||
private string _tokenRatioSummary = "";
|
||||
|
||||
public ObservableCollection<DayBarItem> LauncherOpenBars { get; } = new ObservableCollection<DayBarItem>();
|
||||
|
||||
public ObservableCollection<DayBarItem> ActiveTimeBars { get; } = new ObservableCollection<DayBarItem>();
|
||||
|
||||
public ObservableCollection<CommandStatItem> TopCommands { get; } = new ObservableCollection<CommandStatItem>();
|
||||
|
||||
public ObservableCollection<FavoriteStatItem> TopFavorites { get; } = new ObservableCollection<FavoriteStatItem>();
|
||||
|
||||
public ObservableCollection<DayBarItem> ChatCountBars { get; } = new ObservableCollection<DayBarItem>();
|
||||
|
||||
public ObservableCollection<DayBarItem> TokenUsageBars { get; } = new ObservableCollection<DayBarItem>();
|
||||
|
||||
public ObservableCollection<DayBarItem> WeekdayAvgBars { get; } = new ObservableCollection<DayBarItem>();
|
||||
|
||||
public ObservableCollection<TabRatioItem> TabChatRatios { get; } = new ObservableCollection<TabRatioItem>();
|
||||
|
||||
public bool HasFavorites
|
||||
{
|
||||
get
|
||||
{
|
||||
return _hasFavorites;
|
||||
}
|
||||
private set
|
||||
{
|
||||
_hasFavorites = value;
|
||||
OnPropertyChanged("HasFavorites");
|
||||
}
|
||||
}
|
||||
|
||||
public string TodayDate
|
||||
{
|
||||
get
|
||||
{
|
||||
return _todayDate;
|
||||
}
|
||||
set
|
||||
{
|
||||
_todayDate = value;
|
||||
OnPropertyChanged("TodayDate");
|
||||
}
|
||||
}
|
||||
|
||||
public string TodaySummary
|
||||
{
|
||||
get
|
||||
{
|
||||
return _todaySummary;
|
||||
}
|
||||
set
|
||||
{
|
||||
_todaySummary = value;
|
||||
OnPropertyChanged("TodaySummary");
|
||||
}
|
||||
}
|
||||
|
||||
public string PeakDate
|
||||
{
|
||||
get
|
||||
{
|
||||
return _peakDate;
|
||||
}
|
||||
set
|
||||
{
|
||||
_peakDate = value;
|
||||
OnPropertyChanged("PeakDate");
|
||||
}
|
||||
}
|
||||
|
||||
public string PeakDaySummary
|
||||
{
|
||||
get
|
||||
{
|
||||
return _peakDaySummary;
|
||||
}
|
||||
set
|
||||
{
|
||||
_peakDaySummary = value;
|
||||
OnPropertyChanged("PeakDaySummary");
|
||||
}
|
||||
}
|
||||
|
||||
public string WeekSummary
|
||||
{
|
||||
get
|
||||
{
|
||||
return _weekSummary;
|
||||
}
|
||||
set
|
||||
{
|
||||
_weekSummary = value;
|
||||
OnPropertyChanged("WeekSummary");
|
||||
}
|
||||
}
|
||||
|
||||
public string TotalOpensSummary
|
||||
{
|
||||
get
|
||||
{
|
||||
return _totalOpensSummary;
|
||||
}
|
||||
set
|
||||
{
|
||||
_totalOpensSummary = value;
|
||||
OnPropertyChanged("TotalOpensSummary");
|
||||
}
|
||||
}
|
||||
|
||||
public string AgentSummary
|
||||
{
|
||||
get
|
||||
{
|
||||
return _agentSummary;
|
||||
}
|
||||
set
|
||||
{
|
||||
_agentSummary = value;
|
||||
OnPropertyChanged("AgentSummary");
|
||||
}
|
||||
}
|
||||
|
||||
public double PromptBarWidth
|
||||
{
|
||||
get
|
||||
{
|
||||
return _promptBarWidth;
|
||||
}
|
||||
set
|
||||
{
|
||||
_promptBarWidth = value;
|
||||
OnPropertyChanged("PromptBarWidth");
|
||||
}
|
||||
}
|
||||
|
||||
public double CompletionBarWidth
|
||||
{
|
||||
get
|
||||
{
|
||||
return _completionBarWidth;
|
||||
}
|
||||
set
|
||||
{
|
||||
_completionBarWidth = value;
|
||||
OnPropertyChanged("CompletionBarWidth");
|
||||
}
|
||||
}
|
||||
|
||||
public string PromptTokenLabel
|
||||
{
|
||||
get
|
||||
{
|
||||
return _promptTokenLabel;
|
||||
}
|
||||
set
|
||||
{
|
||||
_promptTokenLabel = value;
|
||||
OnPropertyChanged("PromptTokenLabel");
|
||||
}
|
||||
}
|
||||
|
||||
public string CompletionTokenLabel
|
||||
{
|
||||
get
|
||||
{
|
||||
return _completionTokenLabel;
|
||||
}
|
||||
set
|
||||
{
|
||||
_completionTokenLabel = value;
|
||||
OnPropertyChanged("CompletionTokenLabel");
|
||||
}
|
||||
}
|
||||
|
||||
public string TokenRatioSummary
|
||||
{
|
||||
get
|
||||
{
|
||||
return _tokenRatioSummary;
|
||||
}
|
||||
set
|
||||
{
|
||||
_tokenRatioSummary = value;
|
||||
OnPropertyChanged("TokenRatioSummary");
|
||||
}
|
||||
}
|
||||
|
||||
public event PropertyChangedEventHandler? PropertyChanged;
|
||||
|
||||
public StatisticsViewModel()
|
||||
{
|
||||
Refresh();
|
||||
}
|
||||
|
||||
public void Refresh()
|
||||
{
|
||||
List<DailyUsageStats> stats = UsageStatisticsService.GetStats();
|
||||
string today = DateTime.Today.ToString("yyyy-MM-dd");
|
||||
BuildLauncherOpenChart(stats, today);
|
||||
BuildActiveTimeChart(stats, today);
|
||||
BuildChatCountChart(stats, today);
|
||||
BuildTokenUsageChart(stats, today);
|
||||
BuildTopCommands(stats);
|
||||
BuildWeekdayAvgChart(stats);
|
||||
BuildTabChatRatios(stats);
|
||||
BuildTokenRatio(stats);
|
||||
BuildSummaryCards(stats, today);
|
||||
BuildTopFavorites();
|
||||
}
|
||||
|
||||
private void BuildLauncherOpenChart(List<DailyUsageStats> stats, string today)
|
||||
{
|
||||
List<DailyUsageStats> list = stats.TakeLast(14).ToList();
|
||||
int num = list.Max((DailyUsageStats s) => s.LauncherOpens);
|
||||
if (num == 0)
|
||||
{
|
||||
num = 1;
|
||||
}
|
||||
LauncherOpenBars.Clear();
|
||||
foreach (DailyUsageStats item in list)
|
||||
{
|
||||
DateTime result;
|
||||
DateTime dateTime = (DateTime.TryParse(item.Date, out result) ? result : DateTime.MinValue);
|
||||
LauncherOpenBars.Add(new DayBarItem
|
||||
{
|
||||
DateLabel = ((dateTime != DateTime.MinValue) ? $"{dateTime.Month}/{dateTime.Day}" : ""),
|
||||
DayLabel = ((dateTime != DateTime.MinValue) ? GetKoreanDayOfWeek(dateTime.DayOfWeek) : ""),
|
||||
Value = item.LauncherOpens,
|
||||
BarHeight = 66.0 * (double)item.LauncherOpens / (double)num,
|
||||
ValueLabel = ((item.LauncherOpens > 0) ? item.LauncherOpens.ToString() : ""),
|
||||
ToolTipText = ((dateTime != DateTime.MinValue) ? $"{dateTime:yyyy-MM-dd} ({GetKoreanDayOfWeek(dateTime.DayOfWeek)})\n호출 {item.LauncherOpens}회" : ""),
|
||||
IsToday = (item.Date == today)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void BuildActiveTimeChart(List<DailyUsageStats> stats, string today)
|
||||
{
|
||||
List<DailyUsageStats> list = stats.TakeLast(14).ToList();
|
||||
int num = list.Max((DailyUsageStats s) => s.ActiveSeconds);
|
||||
if (num == 0)
|
||||
{
|
||||
num = 1;
|
||||
}
|
||||
ActiveTimeBars.Clear();
|
||||
foreach (DailyUsageStats item in list)
|
||||
{
|
||||
DateTime result;
|
||||
DateTime dateTime = (DateTime.TryParse(item.Date, out result) ? result : DateTime.MinValue);
|
||||
ActiveTimeBars.Add(new DayBarItem
|
||||
{
|
||||
DateLabel = ((dateTime != DateTime.MinValue) ? $"{dateTime.Month}/{dateTime.Day}" : ""),
|
||||
DayLabel = ((dateTime != DateTime.MinValue) ? GetKoreanDayOfWeek(dateTime.DayOfWeek) : ""),
|
||||
Value = item.ActiveSeconds,
|
||||
BarHeight = 66.0 * (double)item.ActiveSeconds / (double)num,
|
||||
ValueLabel = FormatActiveTime(item.ActiveSeconds),
|
||||
ToolTipText = ((dateTime != DateTime.MinValue) ? $"{dateTime:yyyy-MM-dd} ({GetKoreanDayOfWeek(dateTime.DayOfWeek)})\n활성 {FormatActiveTime(item.ActiveSeconds)}" : ""),
|
||||
IsToday = (item.Date == today)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void BuildChatCountChart(List<DailyUsageStats> stats, string today)
|
||||
{
|
||||
List<DailyUsageStats> list = stats.TakeLast(14).ToList();
|
||||
int num = list.Max(delegate(DailyUsageStats s)
|
||||
{
|
||||
int num3 = 0;
|
||||
foreach (KeyValuePair<string, int> chatCount in s.ChatCounts)
|
||||
{
|
||||
num3 += chatCount.Value;
|
||||
}
|
||||
return num3;
|
||||
});
|
||||
if (num == 0)
|
||||
{
|
||||
num = 1;
|
||||
}
|
||||
ChatCountBars.Clear();
|
||||
foreach (DailyUsageStats item in list)
|
||||
{
|
||||
DateTime result;
|
||||
DateTime value = (DateTime.TryParse(item.Date, out result) ? result : DateTime.MinValue);
|
||||
int valueOrDefault = item.ChatCounts.GetValueOrDefault("Chat");
|
||||
int valueOrDefault2 = item.ChatCounts.GetValueOrDefault("Cowork");
|
||||
int valueOrDefault3 = item.ChatCounts.GetValueOrDefault("Code");
|
||||
int num2 = valueOrDefault + valueOrDefault2 + valueOrDefault3;
|
||||
bool isToday = item.Date == today;
|
||||
ChatCountBars.Add(new DayBarItem
|
||||
{
|
||||
DateLabel = value.ToString("M/d"),
|
||||
DayLabel = value.ToString("ddd").Substring(0, 1),
|
||||
Value = num2,
|
||||
BarHeight = ((num2 > 0) ? ((double)num2 * 66.0 / (double)num) : 2.0),
|
||||
ValueLabel = ((num2 > 0) ? num2.ToString() : ""),
|
||||
ToolTipText = $"{item.Date} ({value:ddd})\nChat: {valueOrDefault}회 · Cowork: {valueOrDefault2}회 · Code: {valueOrDefault3}회",
|
||||
IsToday = isToday
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void BuildTokenUsageChart(List<DailyUsageStats> stats, string today)
|
||||
{
|
||||
List<DailyUsageStats> list = stats.TakeLast(14).ToList();
|
||||
long num = list.Max((DailyUsageStats s) => s.TotalTokens);
|
||||
if (num == 0)
|
||||
{
|
||||
num = 1L;
|
||||
}
|
||||
TokenUsageBars.Clear();
|
||||
foreach (DailyUsageStats item in list)
|
||||
{
|
||||
DateTime result;
|
||||
DateTime value = (DateTime.TryParse(item.Date, out result) ? result : DateTime.MinValue);
|
||||
bool isToday = item.Date == today;
|
||||
long totalTokens = item.TotalTokens;
|
||||
TokenUsageBars.Add(new DayBarItem
|
||||
{
|
||||
DateLabel = value.ToString("M/d"),
|
||||
DayLabel = value.ToString("ddd").Substring(0, 1),
|
||||
Value = (int)Math.Min(totalTokens, 2147483647L),
|
||||
BarHeight = ((totalTokens > 0) ? ((double)totalTokens * 66.0 / (double)num) : 2.0),
|
||||
ValueLabel = ((totalTokens > 0) ? FormatTokens(totalTokens) : ""),
|
||||
ToolTipText = $"{item.Date} ({value:ddd})\n프롬프트: {item.PromptTokens:N0} · 완료: {item.CompletionTokens:N0} · 합계: {item.TotalTokens:N0}",
|
||||
IsToday = isToday
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private static string FormatTokens(long tokens)
|
||||
{
|
||||
if (1 == 0)
|
||||
{
|
||||
}
|
||||
string result = ((tokens >= 1000000) ? $"{(double)tokens / 1000000.0:F1}M" : ((tokens < 1000) ? tokens.ToString() : $"{(double)tokens / 1000.0:F1}K"));
|
||||
if (1 == 0)
|
||||
{
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private void BuildWeekdayAvgChart(List<DailyUsageStats> stats)
|
||||
{
|
||||
Dictionary<DayOfWeek, List<int>> groups = new Dictionary<DayOfWeek, List<int>>();
|
||||
DayOfWeek[] values = Enum.GetValues<DayOfWeek>();
|
||||
foreach (DayOfWeek key in values)
|
||||
{
|
||||
groups[key] = new List<int>();
|
||||
}
|
||||
foreach (DailyUsageStats stat in stats)
|
||||
{
|
||||
if (DateTime.TryParse(stat.Date, out var result))
|
||||
{
|
||||
groups[result.DayOfWeek].Add(stat.LauncherOpens);
|
||||
}
|
||||
}
|
||||
DayOfWeek[] array = new DayOfWeek[7]
|
||||
{
|
||||
DayOfWeek.Monday,
|
||||
DayOfWeek.Tuesday,
|
||||
DayOfWeek.Wednesday,
|
||||
DayOfWeek.Thursday,
|
||||
DayOfWeek.Friday,
|
||||
DayOfWeek.Saturday,
|
||||
DayOfWeek.Sunday
|
||||
};
|
||||
double num = array.Max((DayOfWeek dow) => (groups[dow].Count > 0) ? groups[dow].Average() : 0.0);
|
||||
if (num < 1.0)
|
||||
{
|
||||
num = 1.0;
|
||||
}
|
||||
WeekdayAvgBars.Clear();
|
||||
DayOfWeek[] array2 = array;
|
||||
foreach (DayOfWeek dayOfWeek in array2)
|
||||
{
|
||||
List<int> list = groups[dayOfWeek];
|
||||
double num3 = ((list.Count > 0) ? list.Average() : 0.0);
|
||||
WeekdayAvgBars.Add(new DayBarItem
|
||||
{
|
||||
DateLabel = "",
|
||||
DayLabel = GetKoreanDayOfWeek(dayOfWeek),
|
||||
Value = (int)Math.Round(num3),
|
||||
BarHeight = ((num3 > 0.0) ? (num3 * 66.0 / num) : 2.0),
|
||||
ValueLabel = ((num3 > 0.0) ? num3.ToString("F1") : ""),
|
||||
ToolTipText = $"{GetKoreanDayOfWeek(dayOfWeek)}요일 평균 {num3:F1}회 ({list.Count}일 데이터)",
|
||||
IsToday = (DateTime.Today.DayOfWeek == dayOfWeek)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void BuildTabChatRatios(List<DailyUsageStats> stats)
|
||||
{
|
||||
int num = 0;
|
||||
int num2 = 0;
|
||||
int num3 = 0;
|
||||
foreach (DailyUsageStats stat in stats)
|
||||
{
|
||||
num += stat.ChatCounts.GetValueOrDefault("Chat");
|
||||
num2 += stat.ChatCounts.GetValueOrDefault("Cowork");
|
||||
num3 += stat.ChatCounts.GetValueOrDefault("Code");
|
||||
}
|
||||
int num4 = num + num2 + num3;
|
||||
if (num4 == 0)
|
||||
{
|
||||
num4 = 1;
|
||||
}
|
||||
TabChatRatios.Clear();
|
||||
TabChatRatios.Add(new TabRatioItem
|
||||
{
|
||||
TabName = "Chat",
|
||||
Count = num,
|
||||
Percentage = 100.0 * (double)num / (double)num4,
|
||||
BarWidth = 300.0 * (double)num / (double)num4,
|
||||
PercentLabel = $"{100.0 * (double)num / (double)num4:F0}% ({num}회)",
|
||||
Color = new SolidColorBrush((Color)ColorConverter.ConvertFromString("#818CF8"))
|
||||
});
|
||||
TabChatRatios.Add(new TabRatioItem
|
||||
{
|
||||
TabName = "Cowork",
|
||||
Count = num2,
|
||||
Percentage = 100.0 * (double)num2 / (double)num4,
|
||||
BarWidth = 300.0 * (double)num2 / (double)num4,
|
||||
PercentLabel = $"{100.0 * (double)num2 / (double)num4:F0}% ({num2}회)",
|
||||
Color = new SolidColorBrush((Color)ColorConverter.ConvertFromString("#10B981"))
|
||||
});
|
||||
TabChatRatios.Add(new TabRatioItem
|
||||
{
|
||||
TabName = "Code",
|
||||
Count = num3,
|
||||
Percentage = 100.0 * (double)num3 / (double)num4,
|
||||
BarWidth = 300.0 * (double)num3 / (double)num4,
|
||||
PercentLabel = $"{100.0 * (double)num3 / (double)num4:F0}% ({num3}회)",
|
||||
Color = new SolidColorBrush((Color)ColorConverter.ConvertFromString("#F59E0B"))
|
||||
});
|
||||
}
|
||||
|
||||
private void BuildTokenRatio(List<DailyUsageStats> stats)
|
||||
{
|
||||
long num = stats.Sum((DailyUsageStats s) => s.PromptTokens);
|
||||
long num2 = stats.Sum((DailyUsageStats s) => s.CompletionTokens);
|
||||
long num3 = num + num2;
|
||||
if (num3 == 0)
|
||||
{
|
||||
num3 = 1L;
|
||||
}
|
||||
PromptBarWidth = 400.0 * (double)num / (double)num3;
|
||||
CompletionBarWidth = 400.0 * (double)num2 / (double)num3;
|
||||
PromptTokenLabel = $"입력 {FormatTokens(num)} ({100.0 * (double)num / (double)num3:F0}%)";
|
||||
CompletionTokenLabel = $"출력 {FormatTokens(num2)} ({100.0 * (double)num2 / (double)num3:F0}%)";
|
||||
TokenRatioSummary = $"30일 합계 입력 {FormatTokens(num)} + 출력 {FormatTokens(num2)} = {FormatTokens(num + num2)}";
|
||||
}
|
||||
|
||||
private void BuildTopCommands(List<DailyUsageStats> stats)
|
||||
{
|
||||
Dictionary<string, int> dictionary = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase);
|
||||
foreach (DailyUsageStats stat in stats)
|
||||
{
|
||||
foreach (var (key, num2) in stat.CommandUsage)
|
||||
{
|
||||
dictionary.TryGetValue(key, out var value);
|
||||
dictionary[key] = value + num2;
|
||||
}
|
||||
}
|
||||
List<KeyValuePair<string, int>> list = dictionary.OrderByDescending((KeyValuePair<string, int> kv) => kv.Value).Take(10).ToList();
|
||||
int num3 = ((list.Count <= 0) ? 1 : list[0].Value);
|
||||
TopCommands.Clear();
|
||||
for (int num4 = 0; num4 < list.Count; num4++)
|
||||
{
|
||||
TopCommands.Add(new CommandStatItem
|
||||
{
|
||||
Rank = num4 + 1,
|
||||
Command = list[num4].Key,
|
||||
Count = list[num4].Value,
|
||||
BarWidth = 200.0 * (double)list[num4].Value / (double)num3
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void BuildSummaryCards(List<DailyUsageStats> stats, string today)
|
||||
{
|
||||
TodayDate = DateTime.Today.ToString("yyyy년 M월 d일");
|
||||
DailyUsageStats dailyUsageStats = stats.FirstOrDefault((DailyUsageStats s) => s.Date == today);
|
||||
TodaySummary = ((dailyUsageStats != null) ? $"{dailyUsageStats.LauncherOpens}회 호출 · {FormatActiveTime(dailyUsageStats.ActiveSeconds)}" : "데이터 없음");
|
||||
DailyUsageStats dailyUsageStats2 = stats.OrderByDescending((DailyUsageStats s) => s.LauncherOpens).FirstOrDefault();
|
||||
if (dailyUsageStats2 != null && dailyUsageStats2.LauncherOpens > 0)
|
||||
{
|
||||
PeakDate = (DateTime.TryParse(dailyUsageStats2.Date, out var result) ? result.ToString("yyyy년 M월 d일") : dailyUsageStats2.Date);
|
||||
PeakDaySummary = $"{dailyUsageStats2.LauncherOpens}회 호출";
|
||||
}
|
||||
else
|
||||
{
|
||||
PeakDate = "";
|
||||
PeakDaySummary = "기록 없음";
|
||||
}
|
||||
DateTime weekStart = DateTime.Today.AddDays(0 - DateTime.Today.DayOfWeek);
|
||||
DateTime result2;
|
||||
int value = stats.Where((DailyUsageStats s) => DateTime.TryParse(s.Date, out result2) && result2 >= weekStart).Sum((DailyUsageStats s) => s.LauncherOpens);
|
||||
WeekSummary = $"이번 주 {value}회";
|
||||
int value2 = stats.Sum((DailyUsageStats s) => s.LauncherOpens);
|
||||
TotalOpensSummary = $"30일 합계 {value2}회";
|
||||
int value3 = stats.Sum((DailyUsageStats s) => s.ChatCounts.Values.Sum());
|
||||
long tokens = stats.Sum((DailyUsageStats s) => s.TotalTokens);
|
||||
int value4 = dailyUsageStats?.ChatCounts.Values.Sum() ?? 0;
|
||||
long tokens2 = dailyUsageStats?.TotalTokens ?? 0;
|
||||
AgentSummary = $"오늘 {value4}회 대화 · {FormatTokens(tokens2)} 토큰 | 30일 합계 {value3}회 · {FormatTokens(tokens)} 토큰";
|
||||
}
|
||||
|
||||
private void BuildTopFavorites()
|
||||
{
|
||||
TopFavorites.Clear();
|
||||
string path = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "AxCopilot", "favorites.json");
|
||||
if (!File.Exists(path))
|
||||
{
|
||||
HasFavorites = false;
|
||||
return;
|
||||
}
|
||||
try
|
||||
{
|
||||
JsonSerializerOptions options = new JsonSerializerOptions
|
||||
{
|
||||
PropertyNameCaseInsensitive = true
|
||||
};
|
||||
List<FavFileEntry> source = JsonSerializer.Deserialize<List<FavFileEntry>>(File.ReadAllText(path), options) ?? new List<FavFileEntry>();
|
||||
List<FavFileEntry> list = source.Take(6).ToList();
|
||||
if (list.Count == 0)
|
||||
{
|
||||
HasFavorites = false;
|
||||
return;
|
||||
}
|
||||
for (int i = 0; i < list.Count; i++)
|
||||
{
|
||||
FavFileEntry favFileEntry = list[i];
|
||||
string path2 = Environment.ExpandEnvironmentVariables(favFileEntry.Path);
|
||||
bool flag = Directory.Exists(path2);
|
||||
bool exists = flag || File.Exists(path2);
|
||||
TopFavorites.Add(new FavoriteStatItem
|
||||
{
|
||||
Rank = i + 1,
|
||||
Name = favFileEntry.Name,
|
||||
Path = favFileEntry.Path,
|
||||
Icon = (flag ? "\ue8b7" : "\ue8a5"),
|
||||
Exists = exists
|
||||
});
|
||||
}
|
||||
HasFavorites = TopFavorites.Count > 0;
|
||||
}
|
||||
catch
|
||||
{
|
||||
HasFavorites = false;
|
||||
}
|
||||
}
|
||||
|
||||
private static string GetKoreanDayOfWeek(DayOfWeek dow)
|
||||
{
|
||||
if (1 == 0)
|
||||
{
|
||||
}
|
||||
string result = dow switch
|
||||
{
|
||||
DayOfWeek.Monday => "월",
|
||||
DayOfWeek.Tuesday => "화",
|
||||
DayOfWeek.Wednesday => "수",
|
||||
DayOfWeek.Thursday => "목",
|
||||
DayOfWeek.Friday => "금",
|
||||
DayOfWeek.Saturday => "토",
|
||||
_ => "일",
|
||||
};
|
||||
if (1 == 0)
|
||||
{
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static string FormatActiveTime(int totalSeconds)
|
||||
{
|
||||
if (totalSeconds <= 0)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
int num = totalSeconds / 3600;
|
||||
int num2 = totalSeconds % 3600 / 60;
|
||||
if (num > 0 && num2 > 0)
|
||||
{
|
||||
return $"{num}시간 {num2}분";
|
||||
}
|
||||
if (num <= 0)
|
||||
{
|
||||
if (num2 <= 0)
|
||||
{
|
||||
return $"{totalSeconds}초";
|
||||
}
|
||||
return $"{num2}분";
|
||||
}
|
||||
return $"{num}시간";
|
||||
}
|
||||
|
||||
protected void OnPropertyChanged([CallerMemberName] string? n = null)
|
||||
{
|
||||
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(n));
|
||||
}
|
||||
}
|
||||
18
.decompiledproj/AxCopilot/ViewModels/TabRatioItem.cs
Normal file
18
.decompiledproj/AxCopilot/ViewModels/TabRatioItem.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace AxCopilot.ViewModels;
|
||||
|
||||
public class TabRatioItem
|
||||
{
|
||||
public string TabName { get; init; } = "";
|
||||
|
||||
public int Count { get; init; }
|
||||
|
||||
public double Percentage { get; init; }
|
||||
|
||||
public double BarWidth { get; init; }
|
||||
|
||||
public string PercentLabel { get; init; } = "";
|
||||
|
||||
public Brush Color { get; init; } = Brushes.MediumSlateBlue;
|
||||
}
|
||||
45
.decompiledproj/AxCopilot/ViewModels/ThemeCardModel.cs
Normal file
45
.decompiledproj/AxCopilot/ViewModels/ThemeCardModel.cs
Normal file
@@ -0,0 +1,45 @@
|
||||
using System.ComponentModel;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace AxCopilot.ViewModels;
|
||||
|
||||
public class ThemeCardModel : INotifyPropertyChanged
|
||||
{
|
||||
private bool _isSelected;
|
||||
|
||||
public string Key { get; init; } = "";
|
||||
|
||||
public string Name { get; init; } = "";
|
||||
|
||||
public string PreviewBackground { get; init; } = "#1A1B2E";
|
||||
|
||||
public string PreviewText { get; init; } = "#F0F0FF";
|
||||
|
||||
public string PreviewSubText { get; init; } = "#7A7D9C";
|
||||
|
||||
public string PreviewAccent { get; init; } = "#4B5EFC";
|
||||
|
||||
public string PreviewItem { get; init; } = "#252637";
|
||||
|
||||
public string PreviewBorder { get; init; } = "#2E2F4A";
|
||||
|
||||
public bool IsSelected
|
||||
{
|
||||
get
|
||||
{
|
||||
return _isSelected;
|
||||
}
|
||||
set
|
||||
{
|
||||
_isSelected = value;
|
||||
OnPropertyChanged("IsSelected");
|
||||
}
|
||||
}
|
||||
|
||||
public event PropertyChangedEventHandler? PropertyChanged;
|
||||
|
||||
protected void OnPropertyChanged([CallerMemberName] string? n = null)
|
||||
{
|
||||
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(n));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user