Refactor code to decouple view and viewmodel

pull/5550/head
2dust 2024-08-11 20:44:29 +08:00
parent 9e9808e489
commit 9aa5c0d135
16 changed files with 414 additions and 385 deletions

View File

@ -11,24 +11,24 @@ namespace v2rayN.Common
{
if (type == 1)
{
Utils.RegWriteValue(_regPath, "ProxyEnable", 0);
Utils.RegWriteValue(_regPath, "ProxyServer", string.Empty);
Utils.RegWriteValue(_regPath, "ProxyOverride", string.Empty);
Utils.RegWriteValue(_regPath, "AutoConfigURL", string.Empty);
WindowsUtils.RegWriteValue(_regPath, "ProxyEnable", 0);
WindowsUtils.RegWriteValue(_regPath, "ProxyServer", string.Empty);
WindowsUtils.RegWriteValue(_regPath, "ProxyOverride", string.Empty);
WindowsUtils.RegWriteValue(_regPath, "AutoConfigURL", string.Empty);
}
if (type == 2)
{
Utils.RegWriteValue(_regPath, "ProxyEnable", 1);
Utils.RegWriteValue(_regPath, "ProxyServer", strProxy ?? string.Empty);
Utils.RegWriteValue(_regPath, "ProxyOverride", exceptions ?? string.Empty);
Utils.RegWriteValue(_regPath, "AutoConfigURL", string.Empty);
WindowsUtils.RegWriteValue(_regPath, "ProxyEnable", 1);
WindowsUtils.RegWriteValue(_regPath, "ProxyServer", strProxy ?? string.Empty);
WindowsUtils.RegWriteValue(_regPath, "ProxyOverride", exceptions ?? string.Empty);
WindowsUtils.RegWriteValue(_regPath, "AutoConfigURL", string.Empty);
}
else if (type == 4)
{
Utils.RegWriteValue(_regPath, "ProxyEnable", 0);
Utils.RegWriteValue(_regPath, "ProxyServer", string.Empty);
Utils.RegWriteValue(_regPath, "ProxyOverride", string.Empty);
Utils.RegWriteValue(_regPath, "AutoConfigURL", strProxy ?? string.Empty);
WindowsUtils.RegWriteValue(_regPath, "ProxyEnable", 0);
WindowsUtils.RegWriteValue(_regPath, "ProxyServer", string.Empty);
WindowsUtils.RegWriteValue(_regPath, "ProxyOverride", string.Empty);
WindowsUtils.RegWriteValue(_regPath, "AutoConfigURL", strProxy ?? string.Empty);
}
return true;
}

View File

@ -1,23 +1,15 @@
using Microsoft.Win32;
using Microsoft.Win32.TaskScheduler;
using System.Collections.Specialized;
using System.Collections.Specialized;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.IO.Compression;
using System.Net;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Security.Cryptography;
using System.Security.Principal;
using System.Text;
using System.Text.RegularExpressions;
using System.Windows;
using System.Windows.Interop;
using System.Windows.Media;
using System.Windows.Media.Imaging;
namespace v2rayN
{
@ -345,14 +337,6 @@ namespace v2rayN
return sb.ToString();
}
public static ImageSource IconToImageSource(Icon icon)
{
return Imaging.CreateBitmapSourceFromHIcon(
icon.Handle,
new System.Windows.Int32Rect(0, 0, icon.Width, icon.Height),
BitmapSizeOptions.FromEmptyOptions());
}
/// <summary>
/// idn to idc
/// </summary>
@ -420,11 +404,7 @@ namespace v2rayN
}
}
/// <summary>
/// 文本
/// </summary>
/// <param name="text"></param>
/// <returns></returns>
public static bool IsNullOrEmpty(string? text)
{
if (string.IsNullOrWhiteSpace(text))
@ -631,43 +611,6 @@ namespace v2rayN
}
}
/// <summary>
/// 获取剪贴板数
/// </summary>
/// <returns></returns>
public static string? GetClipboardData()
{
string? strData = string.Empty;
try
{
IDataObject data = Clipboard.GetDataObject();
if (data.GetDataPresent(DataFormats.UnicodeText))
{
strData = data.GetData(DataFormats.UnicodeText)?.ToString();
}
return strData;
}
catch (Exception ex)
{
Logging.SaveLog(ex.Message, ex);
}
return strData;
}
/// <summary>
/// 拷贝至剪贴板
/// </summary>
/// <returns></returns>
public static void SetClipboardData(string strData)
{
try
{
Clipboard.SetText(strData);
}
catch
{
}
}
/// <summary>
/// 取得GUID
@ -752,23 +695,6 @@ namespace v2rayN
}
}
public static void SetDarkBorder(System.Windows.Window window, bool dark)
{
// Make sure the handle is created before the window is shown
IntPtr hWnd = new System.Windows.Interop.WindowInteropHelper(window).EnsureHandle();
int attribute = dark ? 1 : 0;
uint attributeSize = (uint)Marshal.SizeOf(attribute);
DwmSetWindowAttribute(hWnd, DWMWINDOWATTRIBUTE.DWMWA_USE_IMMERSIVE_DARK_MODE_BEFORE_20H1, ref attribute, attributeSize);
DwmSetWindowAttribute(hWnd, DWMWINDOWATTRIBUTE.DWMWA_USE_IMMERSIVE_DARK_MODE, ref attribute, attributeSize);
}
public static bool IsLightTheme()
{
using var key = Registry.CurrentUser.OpenSubKey(@"Software\Microsoft\Windows\CurrentVersion\Themes\Personalize");
var value = key?.GetValue("AppsUseLightTheme");
return value is int i && i > 0;
}
/// <summary>
/// 获取系统hosts
/// </summary>
@ -958,12 +884,13 @@ namespace v2rayN
try
{
var autoRunName = $"{AutoRunName}_{GetMD5(StartupPath())}";
WindowsUtils.
//delete first
RegWriteValue(AutoRunRegPath, autoRunName, "");
//delete first
RegWriteValue(AutoRunRegPath, autoRunName, "");
if (IsAdministrator())
{
AutoStart(autoRunName, "", "");
WindowsUtils.AutoStart(autoRunName, "", "");
}
if (run)
@ -971,11 +898,11 @@ namespace v2rayN
string exePath = GetExePath();
if (IsAdministrator())
{
AutoStart(autoRunName, exePath, "");
WindowsUtils.AutoStart(autoRunName, exePath, "");
}
else
{
RegWriteValue(AutoRunRegPath, autoRunName, exePath.AppendQuotes());
WindowsUtils.RegWriteValue(AutoRunRegPath, autoRunName, exePath.AppendQuotes());
}
}
}
@ -985,146 +912,8 @@ namespace v2rayN
}
}
public static string? RegReadValue(string path, string name, string def)
{
RegistryKey? regKey = null;
try
{
regKey = Registry.CurrentUser.OpenSubKey(path, false);
string? value = regKey?.GetValue(name) as string;
if (IsNullOrEmpty(value))
{
return def;
}
else
{
return value;
}
}
catch (Exception ex)
{
Logging.SaveLog(ex.Message, ex);
}
finally
{
regKey?.Close();
}
return def;
}
public static void RegWriteValue(string path, string name, object value)
{
RegistryKey? regKey = null;
try
{
regKey = Registry.CurrentUser.CreateSubKey(path);
if (IsNullOrEmpty(value.ToString()))
{
regKey?.DeleteValue(name, false);
}
else
{
regKey?.SetValue(name, value);
}
}
catch (Exception ex)
{
Logging.SaveLog(ex.Message, ex);
}
finally
{
regKey?.Close();
}
}
/// <summary>
/// Auto Start via TaskService
/// </summary>
/// <param name="taskName"></param>
/// <param name="fileName"></param>
/// <param name="description"></param>
/// <exception cref="ArgumentNullException"></exception>
public static void AutoStart(string taskName, string fileName, string description)
{
if (Utils.IsNullOrEmpty(taskName))
{
return;
}
string TaskName = taskName;
var logonUser = WindowsIdentity.GetCurrent().Name;
string taskDescription = description;
string deamonFileName = fileName;
using var taskService = new TaskService();
var tasks = taskService.RootFolder.GetTasks(new Regex(TaskName));
foreach (var t in tasks)
{
taskService.RootFolder.DeleteTask(t.Name);
}
if (Utils.IsNullOrEmpty(fileName))
{
return;
}
var task = taskService.NewTask();
task.RegistrationInfo.Description = taskDescription;
task.Settings.DisallowStartIfOnBatteries = false;
task.Settings.StopIfGoingOnBatteries = false;
task.Settings.RunOnlyIfIdle = false;
task.Settings.IdleSettings.StopOnIdleEnd = false;
task.Settings.ExecutionTimeLimit = TimeSpan.Zero;
task.Triggers.Add(new LogonTrigger { UserId = logonUser, Delay = TimeSpan.FromSeconds(10) });
task.Principal.RunLevel = TaskRunLevel.Highest;
task.Actions.Add(new ExecAction(deamonFileName.AppendQuotes(), null, Path.GetDirectoryName(deamonFileName)));
taskService.RootFolder.RegisterTaskDefinition(TaskName, task);
}
public static void RemoveTunDevice()
{
try
{
var sum = MD5.HashData(Encoding.UTF8.GetBytes("wintunsingbox_tun"));
var guid = new Guid(sum);
string pnputilPath = @"C:\Windows\System32\pnputil.exe";
string arg = $$""" /remove-device "SWD\Wintun\{{{guid}}}" """;
// Try to remove the device
Process proc = new()
{
StartInfo = new()
{
FileName = pnputilPath,
Arguments = arg,
RedirectStandardOutput = true,
UseShellExecute = false,
CreateNoWindow = true
}
};
proc.Start();
var output = proc.StandardOutput.ReadToEnd();
proc.WaitForExit();
}
catch
{
}
}
#endregion 开机自动启动等
#region Windows API
[Flags]
public enum DWMWINDOWATTRIBUTE : uint
{
DWMWA_USE_IMMERSIVE_DARK_MODE_BEFORE_20H1 = 19,
DWMWA_USE_IMMERSIVE_DARK_MODE = 20,
}
[DllImport("dwmapi.dll")]
public static extern int DwmSetWindowAttribute(IntPtr hwnd, DWMWINDOWATTRIBUTE attribute, ref int attributeValue, uint attributeSize);
#endregion Windows API
}
}

View File

@ -0,0 +1,223 @@
using Microsoft.Win32;
using Microsoft.Win32.TaskScheduler;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Runtime.InteropServices;
using System.Security.Cryptography;
using System.Security.Principal;
using System.Text;
using System.Text.RegularExpressions;
using System.Windows;
using System.Windows.Interop;
using System.Windows.Media;
using System.Windows.Media.Imaging;
namespace v2rayN
{
internal static class WindowsUtils
{
/// <summary>
/// 获取剪贴板数
/// </summary>
/// <returns></returns>
public static string? GetClipboardData()
{
string? strData = string.Empty;
try
{
IDataObject data = Clipboard.GetDataObject();
if (data.GetDataPresent(DataFormats.UnicodeText))
{
strData = data.GetData(DataFormats.UnicodeText)?.ToString();
}
return strData;
}
catch (Exception ex)
{
Logging.SaveLog(ex.Message, ex);
}
return strData;
}
/// <summary>
/// 拷贝至剪贴板
/// </summary>
/// <returns></returns>
public static void SetClipboardData(string strData)
{
try
{
Clipboard.SetText(strData);
}
catch
{
}
}
/// <summary>
/// Auto Start via TaskService
/// </summary>
/// <param name="taskName"></param>
/// <param name="fileName"></param>
/// <param name="description"></param>
/// <exception cref="ArgumentNullException"></exception>
public static void AutoStart(string taskName, string fileName, string description)
{
if (Utils.IsNullOrEmpty(taskName))
{
return;
}
string TaskName = taskName;
var logonUser = WindowsIdentity.GetCurrent().Name;
string taskDescription = description;
string deamonFileName = fileName;
using var taskService = new TaskService();
var tasks = taskService.RootFolder.GetTasks(new Regex(TaskName));
foreach (var t in tasks)
{
taskService.RootFolder.DeleteTask(t.Name);
}
if (Utils.IsNullOrEmpty(fileName))
{
return;
}
var task = taskService.NewTask();
task.RegistrationInfo.Description = taskDescription;
task.Settings.DisallowStartIfOnBatteries = false;
task.Settings.StopIfGoingOnBatteries = false;
task.Settings.RunOnlyIfIdle = false;
task.Settings.IdleSettings.StopOnIdleEnd = false;
task.Settings.ExecutionTimeLimit = TimeSpan.Zero;
task.Triggers.Add(new LogonTrigger { UserId = logonUser, Delay = TimeSpan.FromSeconds(10) });
task.Principal.RunLevel = TaskRunLevel.Highest;
task.Actions.Add(new ExecAction(deamonFileName.AppendQuotes(), null, Path.GetDirectoryName(deamonFileName)));
taskService.RootFolder.RegisterTaskDefinition(TaskName, task);
}
[DllImport("dwmapi.dll")]
public static extern int DwmSetWindowAttribute(IntPtr hwnd, DWMWINDOWATTRIBUTE attribute, ref int attributeValue, uint attributeSize);
public static ImageSource IconToImageSource(Icon icon)
{
return Imaging.CreateBitmapSourceFromHIcon(
icon.Handle,
new System.Windows.Int32Rect(0, 0, icon.Width, icon.Height),
BitmapSizeOptions.FromEmptyOptions());
}
public static bool IsLightTheme()
{
using var key = Registry.CurrentUser.OpenSubKey(@"Software\Microsoft\Windows\CurrentVersion\Themes\Personalize");
var value = key?.GetValue("AppsUseLightTheme");
return value is int i && i > 0;
}
public static string? RegReadValue(string path, string name, string def)
{
RegistryKey? regKey = null;
try
{
regKey = Registry.CurrentUser.OpenSubKey(path, false);
string? value = regKey?.GetValue(name) as string;
if (Utils.IsNullOrEmpty(value))
{
return def;
}
else
{
return value;
}
}
catch (Exception ex)
{
Logging.SaveLog(ex.Message, ex);
}
finally
{
regKey?.Close();
}
return def;
}
public static void RegWriteValue(string path, string name, object value)
{
RegistryKey? regKey = null;
try
{
regKey = Registry.CurrentUser.CreateSubKey(path);
if (Utils.IsNullOrEmpty(value.ToString()))
{
regKey?.DeleteValue(name, false);
}
else
{
regKey?.SetValue(name, value);
}
}
catch (Exception ex)
{
Logging.SaveLog(ex.Message, ex);
}
finally
{
regKey?.Close();
}
}
public static void RemoveTunDevice()
{
try
{
var sum = MD5.HashData(Encoding.UTF8.GetBytes("wintunsingbox_tun"));
var guid = new Guid(sum);
string pnputilPath = @"C:\Windows\System32\pnputil.exe";
string arg = $$""" /remove-device "SWD\Wintun\{{{guid}}}" """;
// Try to remove the device
Process proc = new()
{
StartInfo = new()
{
FileName = pnputilPath,
Arguments = arg,
RedirectStandardOutput = true,
UseShellExecute = false,
CreateNoWindow = true
}
};
proc.Start();
var output = proc.StandardOutput.ReadToEnd();
proc.WaitForExit();
}
catch
{
}
}
public static void SetDarkBorder(System.Windows.Window window, bool dark)
{
// Make sure the handle is created before the window is shown
IntPtr hWnd = new System.Windows.Interop.WindowInteropHelper(window).EnsureHandle();
int attribute = dark ? 1 : 0;
uint attributeSize = (uint)Marshal.SizeOf(attribute);
DwmSetWindowAttribute(hWnd, DWMWINDOWATTRIBUTE.DWMWA_USE_IMMERSIVE_DARK_MODE_BEFORE_20H1, ref attribute, attributeSize);
DwmSetWindowAttribute(hWnd, DWMWINDOWATTRIBUTE.DWMWA_USE_IMMERSIVE_DARK_MODE, ref attribute, attributeSize);
}
#region Windows API
[Flags]
public enum DWMWINDOWATTRIBUTE : uint
{
DWMWA_USE_IMMERSIVE_DARK_MODE_BEFORE_20H1 = 19,
DWMWA_USE_IMMERSIVE_DARK_MODE = 20,
}
#endregion Windows API
}
}

View File

@ -10,6 +10,8 @@
ShareSub,
ShareServer,
ShowHideWindow,
ScanScreenTask,
Shutdown,
SubEditWindow,
RoutingRuleSettingWindow,
RoutingRuleDetailsWindow,
@ -24,10 +26,10 @@
DispatcherRefreshConnections,
DispatcherRefreshProxyGroups,
DispatcherProxiesDelayTest,
DispatcherStatistics,
DispatcherServerAvailability,
DispatcherReload,
DispatcherRefreshServersBiz,
DispatcherRefreshIcon,
}
}

View File

@ -46,11 +46,11 @@ namespace v2rayN.Handler
ShowMsg(false, msg);
ShowMsg(true, $"{node.GetSummary()}");
CoreStop();
if (_config.tunModeItem.enableTun)
{
Thread.Sleep(1000);
Utils.RemoveTunDevice();
}
//if (_config.tunModeItem.enableTun)
//{
// Thread.Sleep(1000);
// WindowsUtils.RemoveTunDevice();
//}
CoreStart(node);

View File

@ -43,7 +43,7 @@ namespace v2rayN.Handler
if (_config.globalHotkeys == null) return;
foreach (var item in _config.globalHotkeys)
{
if (item.KeyCode != null && item.KeyCode != Key.None)
if (item.KeyCode != null && (Key)item.KeyCode != Key.None)
{
int key = KeyInterop.VirtualKeyFromKey((Key)item.KeyCode);
KeyModifiers modifiers = KeyModifiers.None;

View File

@ -156,71 +156,7 @@ namespace v2rayN.Handler
}
}
public void UpdateTask(Config config, Action<bool, string> update)
{
Task.Run(() => UpdateTaskRunSubscription(config, update));
Task.Run(() => UpdateTaskRunGeo(config, update));
}
private async Task UpdateTaskRunSubscription(Config config, Action<bool, string> update)
{
await Task.Delay(60000);
Logging.SaveLog("UpdateTaskRunSubscription");
var updateHandle = new UpdateHandle();
while (true)
{
var updateTime = ((DateTimeOffset)DateTime.Now).ToUnixTimeSeconds();
var lstSubs = LazyConfig.Instance.SubItems()
.Where(t => t.autoUpdateInterval > 0)
.Where(t => updateTime - t.updateTime >= t.autoUpdateInterval * 60)
.ToList();
foreach (var item in lstSubs)
{
updateHandle.UpdateSubscriptionProcess(config, item.id, true, (bool success, string msg) =>
{
update(success, msg);
if (success)
Logging.SaveLog("subscription" + msg);
});
item.updateTime = updateTime;
ConfigHandler.AddSubItem(config, item);
await Task.Delay(5000);
}
await Task.Delay(60000);
}
}
private async Task UpdateTaskRunGeo(Config config, Action<bool, string> update)
{
var autoUpdateGeoTime = DateTime.Now;
await Task.Delay(1000 * 120);
Logging.SaveLog("UpdateTaskRunGeo");
var updateHandle = new UpdateHandle();
while (true)
{
var dtNow = DateTime.Now;
if (config.guiItem.autoUpdateInterval > 0)
{
if ((dtNow - autoUpdateGeoTime).Hours % config.guiItem.autoUpdateInterval == 0)
{
updateHandle.UpdateGeoFileAll(config, (bool success, string msg) =>
{
update(false, msg);
});
autoUpdateGeoTime = dtNow;
}
}
await Task.Delay(1000 * 3600);
}
}
public void RegisterGlobalHotkey(Config config, Action<EGlobalHotkey> handler, Action<bool, string> update)
public void RegisterGlobalHotkey(Config config, Action<EGlobalHotkey> handler, Action<bool, string>? update)
{
HotkeyHandler.Instance.UpdateViewEvent += update;
HotkeyHandler.Instance.HotkeyTriggerEvent += handler;
@ -240,7 +176,7 @@ namespace v2rayN.Handler
{
if (wParam == IntPtr.Zero && Marshal.PtrToStringUni(lParam) == "ImmersiveColorSet")
{
update(!Utils.IsLightTheme());
update(!WindowsUtils.IsLightTheme());
}
}
}

View File

@ -1,5 +1,4 @@
using System.Windows.Input;
using v2rayN.Enums;
using v2rayN.Enums;
namespace v2rayN.Models
{
@ -152,7 +151,7 @@ namespace v2rayN.Models
public bool Shift { get; set; }
public Key? KeyCode { get; set; }
public int? KeyCode { get; set; }
}
[Serializable]

View File

@ -3,13 +3,10 @@ using ReactiveUI;
using ReactiveUI.Fody.Helpers;
using Splat;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Reactive;
using System.Reactive.Linq;
using System.Text;
using System.Windows;
using System.Windows.Media;
using v2rayN.Base;
using v2rayN.Enums;
using v2rayN.Handler;
@ -95,12 +92,6 @@ namespace v2rayN.ViewModels
public ReactiveCommand<Unit, Unit> NotifyLeftClickCmd { get; }
[Reactive]
public Icon NotifyIcon { get; set; }
[Reactive]
public ImageSource AppIcon { get; set; }
#endregion Menu
#region System Proxy
@ -259,9 +250,9 @@ namespace v2rayN.ViewModels
{
AddServerViaClipboard();
});
AddServerViaScanCmd = ReactiveCommand.CreateFromTask(() =>
AddServerViaScanCmd = ReactiveCommand.Create(() =>
{
return ScanScreenTaskAsync();
_updateView?.Invoke(EViewAction.ScanScreenTask, null);
});
//Subscription
@ -390,9 +381,7 @@ namespace v2rayN.ViewModels
StatisticsHandler.Instance.Init(_config, UpdateStatisticsHandler);
}
MainFormHandler.Instance.UpdateTask(_config, UpdateTaskHandler);
MainFormHandler.Instance.RegisterGlobalHotkey(_config, OnHotkeyHandler, UpdateTaskHandler);
RegUpdateTask(_config, UpdateTaskHandler);
RefreshRoutingsMenu();
//RefreshServers();
@ -463,32 +452,6 @@ namespace v2rayN.ViewModels
}
}
private void OnHotkeyHandler(EGlobalHotkey e)
{
switch (e)
{
case EGlobalHotkey.ShowForm:
_updateView?.Invoke(EViewAction.ShowHideWindow, null);
break;
case EGlobalHotkey.SystemProxyClear:
SetListenerType(ESysProxyType.ForcedClear);
break;
case EGlobalHotkey.SystemProxySet:
SetListenerType(ESysProxyType.ForcedChange);
break;
case EGlobalHotkey.SystemProxyUnchanged:
SetListenerType(ESysProxyType.Unchanged);
break;
case EGlobalHotkey.SystemProxyPac:
SetListenerType(ESysProxyType.Pac);
break;
}
}
public void MyAppExit(bool blWindowsShutDown)
{
try
@ -517,7 +480,7 @@ namespace v2rayN.ViewModels
catch { }
finally
{
Application.Current.Shutdown();
_updateView?.Invoke(EViewAction.Shutdown, null);
}
}
@ -613,7 +576,7 @@ namespace v2rayN.ViewModels
public void AddServerViaClipboard()
{
var clipboardData = Utils.GetClipboardData();
var clipboardData = WindowsUtils.GetClipboardData();
int ret = ConfigHandler.AddBatchServers(_config, clipboardData!, _config.subIndexId, false);
if (ret > 0)
{
@ -623,18 +586,8 @@ namespace v2rayN.ViewModels
}
}
public async Task ScanScreenTaskAsync()
public void ScanScreenTaskAsync(string result)
{
_updateView?.Invoke(EViewAction.ShowHideWindow, false);
var dpiXY = QRCodeHelper.GetDpiXY(Application.Current.MainWindow);
string result = await Task.Run(() =>
{
return QRCodeHelper.ScanScreen(dpiXY.Item1, dpiXY.Item2);
});
_updateView?.Invoke(EViewAction.ShowHideWindow, true);
if (Utils.IsNullOrEmpty(result))
{
_noticeHandler?.Enqueue(ResUI.NoValidQRcodeFound);
@ -869,6 +822,12 @@ namespace v2rayN.ViewModels
{
await Task.Run(() =>
{
if (_config.tunModeItem.enableTun)
{
Thread.Sleep(1000);
WindowsUtils.RemoveTunDevice();
}
var node = ConfigHandler.GetDefaultServer(_config);
_coreHandler.LoadCore(node);
});
@ -914,8 +873,7 @@ namespace v2rayN.ViewModels
if (blChange)
{
NotifyIcon = MainFormHandler.Instance.GetNotifyIcon(_config);
AppIcon = MainFormHandler.Instance.GetAppIcon(_config);
_updateView?.Invoke(EViewAction.DispatcherRefreshIcon, null);
}
}
@ -966,8 +924,7 @@ namespace v2rayN.ViewModels
{
_noticeHandler?.SendMessage(ResUI.TipChangeRouting, true);
Reload();
NotifyIcon = MainFormHandler.Instance.GetNotifyIcon(_config);
AppIcon = MainFormHandler.Instance.GetAppIcon(_config);
_updateView?.Invoke(EViewAction.DispatcherRefreshIcon, null);
}
}
@ -1054,5 +1011,73 @@ namespace v2rayN.ViewModels
}
#endregion UI
#region UpdateTask
private void RegUpdateTask(Config config, Action<bool, string> update)
{
Task.Run(() => UpdateTaskRunSubscription(config, update));
Task.Run(() => UpdateTaskRunGeo(config, update));
}
private async Task UpdateTaskRunSubscription(Config config, Action<bool, string> update)
{
await Task.Delay(60000);
Logging.SaveLog("UpdateTaskRunSubscription");
var updateHandle = new UpdateHandle();
while (true)
{
var updateTime = ((DateTimeOffset)DateTime.Now).ToUnixTimeSeconds();
var lstSubs = LazyConfig.Instance.SubItems()
.Where(t => t.autoUpdateInterval > 0)
.Where(t => updateTime - t.updateTime >= t.autoUpdateInterval * 60)
.ToList();
foreach (var item in lstSubs)
{
updateHandle.UpdateSubscriptionProcess(config, item.id, true, (bool success, string msg) =>
{
update(success, msg);
if (success)
Logging.SaveLog("subscription" + msg);
});
item.updateTime = updateTime;
ConfigHandler.AddSubItem(config, item);
await Task.Delay(5000);
}
await Task.Delay(60000);
}
}
private async Task UpdateTaskRunGeo(Config config, Action<bool, string> update)
{
var autoUpdateGeoTime = DateTime.Now;
await Task.Delay(1000 * 120);
Logging.SaveLog("UpdateTaskRunGeo");
var updateHandle = new UpdateHandle();
while (true)
{
var dtNow = DateTime.Now;
if (config.guiItem.autoUpdateInterval > 0)
{
if ((dtNow - autoUpdateGeoTime).Hours % config.guiItem.autoUpdateInterval == 0)
{
updateHandle.UpdateGeoFileAll(config, (bool success, string msg) =>
{
update(false, msg);
});
autoUpdateGeoTime = dtNow;
}
}
await Task.Delay(1000 * 3600);
}
}
#endregion UpdateTask
}
}

View File

@ -739,7 +739,7 @@ namespace v2rayN.ViewModels
}
if (sb.Length > 0)
{
Utils.SetClipboardData(sb.ToString());
WindowsUtils.SetClipboardData(sb.ToString());
_noticeHandler?.SendMessage(ResUI.BatchExportURLSuccessfully);
}
}

View File

@ -202,7 +202,7 @@ namespace v2rayN.ViewModels
}
if (lst.Count > 0)
{
Utils.SetClipboardData(JsonUtils.Serialize(lst));
WindowsUtils.SetClipboardData(JsonUtils.Serialize(lst));
//_noticeHandler?.Enqueue(ResUI.OperationSuccess"));
}
}
@ -283,7 +283,7 @@ namespace v2rayN.ViewModels
private void ImportRulesFromClipboard()
{
var clipboardData = Utils.GetClipboardData();
var clipboardData = WindowsUtils.GetClipboardData();
if (AddBatchRoutingRules(SelectedRouting, clipboardData) == 0)
{
RefreshRulesItems();

View File

@ -50,7 +50,7 @@ namespace v2rayN.ViewModels
{
if (FollowSystemTheme)
{
ModifyTheme(!Utils.IsLightTheme());
ModifyTheme(!WindowsUtils.IsLightTheme());
}
else
{
@ -104,7 +104,7 @@ namespace v2rayN.ViewModels
ConfigHandler.SaveConfig(_config);
if (FollowSystemTheme)
{
ModifyTheme(!Utils.IsLightTheme());
ModifyTheme(!WindowsUtils.IsLightTheme());
}
else
{
@ -173,8 +173,7 @@ namespace v2rayN.ViewModels
theme.SetBaseTheme(isDarkTheme ? BaseTheme.Dark : BaseTheme.Light);
_paletteHelper.SetTheme(theme);
Utils.SetDarkBorder(Application.Current.MainWindow, isDarkTheme);
WindowsUtils.SetDarkBorder(Application.Current.MainWindow, isDarkTheme);
}
public void ChangePrimaryColor(System.Windows.Media.Color color)

View File

@ -38,8 +38,7 @@ namespace v2rayN.Views
this.BindCommand(ViewModel, vm => vm.EditServerCmd, v => v.btnEdit).DisposeWith(disposables);
this.BindCommand(ViewModel, vm => vm.SaveServerCmd, v => v.btnSave).DisposeWith(disposables);
});
Utils.SetDarkBorder(this, LazyConfig.Instance.GetConfig().uiItem.followSystemTheme ? !Utils.IsLightTheme() : LazyConfig.Instance.GetConfig().uiItem.colorModeDark);
WindowsUtils.SetDarkBorder(this, LazyConfig.Instance.GetConfig().uiItem.followSystemTheme ? !WindowsUtils.IsLightTheme() : LazyConfig.Instance.GetConfig().uiItem.colorModeDark);
}
private bool UpdateViewHandler(EViewAction action, object? obj)

View File

@ -30,7 +30,7 @@ namespace v2rayN.Views
HotkeyHandler.Instance.IsPause = true;
this.Closing += (s, e) => HotkeyHandler.Instance.IsPause = false;
Utils.SetDarkBorder(this, _config.uiItem.followSystemTheme ? !Utils.IsLightTheme() : _config.uiItem.colorModeDark);
WindowsUtils.SetDarkBorder(this, _config.uiItem.followSystemTheme ? !WindowsUtils.IsLightTheme() : _config.uiItem.colorModeDark);
InitData();
}
@ -52,7 +52,7 @@ namespace v2rayN.Views
e.Handled = true;
var _ModifierKeys = new Key[] { Key.LeftCtrl, Key.RightCtrl, Key.LeftShift,
Key.RightShift, Key.LeftAlt, Key.RightAlt, Key.LWin, Key.RWin};
_TextBoxKeyEventItem[sender].KeyCode = e.Key == Key.System ? (_ModifierKeys.Contains(e.SystemKey) ? Key.None : e.SystemKey) : (_ModifierKeys.Contains(e.Key) ? Key.None : e.Key);
_TextBoxKeyEventItem[sender].KeyCode = (int)(e.Key == Key.System ? (_ModifierKeys.Contains(e.SystemKey) ? Key.None : e.SystemKey) : (_ModifierKeys.Contains(e.Key) ? Key.None : e.Key));
_TextBoxKeyEventItem[sender].Alt = (Keyboard.Modifiers & ModifierKeys.Alt) == ModifierKeys.Alt;
_TextBoxKeyEventItem[sender].Control = (Keyboard.Modifiers & ModifierKeys.Control) == ModifierKeys.Control;
_TextBoxKeyEventItem[sender].Shift = (Keyboard.Modifiers & ModifierKeys.Shift) == ModifierKeys.Shift;
@ -78,8 +78,8 @@ namespace v2rayN.Views
if (item.Control) res.Append($"{ModifierKeys.Control}+");
if (item.Shift) res.Append($"{ModifierKeys.Shift}+");
if (item.Alt) res.Append($"{ModifierKeys.Alt}+");
if (item.KeyCode != null && item.KeyCode != Key.None)
res.Append($"{item.KeyCode}");
if (item.KeyCode != null && (Key)item.KeyCode != Key.None)
res.Append($"{(Key)item.KeyCode}");
return res.ToString();
}
@ -88,7 +88,7 @@ namespace v2rayN.Views
{
foreach (var item in _TextBoxKeyEventItem)
{
if (item.Value.KeyCode != null && item.Value.KeyCode != Key.None)
if (item.Value.KeyCode != null && (Key)item.Value.KeyCode != Key.None)
{
(item.Key as TextBox)!.Text = KeyEventItemToString(item.Value);
}
@ -121,7 +121,7 @@ namespace v2rayN.Views
_TextBoxKeyEventItem[k].Alt = false;
_TextBoxKeyEventItem[k].Control = false;
_TextBoxKeyEventItem[k].Shift = false;
_TextBoxKeyEventItem[k].KeyCode = Key.None;
_TextBoxKeyEventItem[k].KeyCode = (int)Key.None;
}
BindingData();
}

View File

@ -37,6 +37,8 @@ namespace v2rayN.Views
ViewModel = new MainWindowViewModel(UpdateViewHandler);
Locator.CurrentMutable.RegisterLazySingleton(() => ViewModel, typeof(MainWindowViewModel));
MainFormHandler.Instance.RegisterGlobalHotkey(_config, OnHotkeyHandler, null);
this.WhenActivated(disposables =>
{
//servers
@ -106,10 +108,8 @@ namespace v2rayN.Views
this.BindCommand(ViewModel, vm => vm.SubUpdateCmd, v => v.menuSubUpdate2).DisposeWith(disposables);
this.BindCommand(ViewModel, vm => vm.SubUpdateViaProxyCmd, v => v.menuSubUpdateViaProxy2).DisposeWith(disposables);
this.OneWayBind(ViewModel, vm => vm.NotifyIcon, v => v.tbNotify.Icon).DisposeWith(disposables);
this.OneWayBind(ViewModel, vm => vm.RunningServerToolTipText, v => v.tbNotify.ToolTipText).DisposeWith(disposables);
this.OneWayBind(ViewModel, vm => vm.NotifyLeftClickCmd, v => v.tbNotify.LeftClickCommand).DisposeWith(disposables);
this.OneWayBind(ViewModel, vm => vm.AppIcon, v => v.Icon).DisposeWith(disposables);
//status bar
this.OneWayBind(ViewModel, vm => vm.InboundDisplay, v => v.txtInboundDisplay.Text).DisposeWith(disposables);
@ -183,6 +183,8 @@ namespace v2rayN.Views
AddHelpMenuItem();
}
#region Event
private bool UpdateViewHandler(EViewAction action, object? obj)
{
switch (action)
@ -246,12 +248,52 @@ namespace v2rayN.Views
ViewModel?.RefreshServersBiz();
}), DispatcherPriority.Normal);
break;
case EViewAction.DispatcherRefreshIcon:
Application.Current?.Dispatcher.Invoke((() =>
{
tbNotify.Icon = MainFormHandler.Instance.GetNotifyIcon(_config);
this.Icon = MainFormHandler.Instance.GetAppIcon(_config);
}), DispatcherPriority.Normal);
break;
case EViewAction.Shutdown:
Application.Current.Shutdown();
break;
case EViewAction ScanScreenTask:
ScanScreenTaskAsync().ContinueWith(_ => { });
break;
}
return true;
}
#region Event
private void OnHotkeyHandler(EGlobalHotkey e)
{
switch (e)
{
case EGlobalHotkey.ShowForm:
ShowHideWindow(null);
break;
case EGlobalHotkey.SystemProxyClear:
ViewModel?.SetListenerType(ESysProxyType.ForcedClear);
break;
case EGlobalHotkey.SystemProxySet:
ViewModel?.SetListenerType(ESysProxyType.ForcedChange);
break;
case EGlobalHotkey.SystemProxyUnchanged:
ViewModel?.SetListenerType(ESysProxyType.Unchanged);
break;
case EGlobalHotkey.SystemProxyPac:
ViewModel?.SetListenerType(ESysProxyType.Pac);
break;
}
}
private void MainWindow_Closing(object? sender, CancelEventArgs e)
{
@ -286,7 +328,7 @@ namespace v2rayN.Views
break;
case Key.S:
ViewModel?.ScanScreenTaskAsync().ContinueWith(_ => { });
ScanScreenTaskAsync().ContinueWith(_ => { });
break;
}
}
@ -320,6 +362,21 @@ namespace v2rayN.Views
Utils.ProcessStart(Utils.GetBinPath("EnableLoopback.exe"));
}
public async Task ScanScreenTaskAsync()
{
ShowHideWindow(false);
var dpiXY = QRCodeHelper.GetDpiXY(Application.Current.MainWindow);
string result = await Task.Run(() =>
{
return QRCodeHelper.ScanScreen(dpiXY.Item1, dpiXY.Item2);
});
ShowHideWindow(true);
ViewModel?.ScanScreenTaskAsync(result);
}
#endregion Event
#region UI

View File

@ -99,13 +99,13 @@ namespace v2rayN.Views
private void menuMsgViewCopy_Click(object sender, System.Windows.RoutedEventArgs e)
{
var data = txtMsg.SelectedText.TrimEx();
Utils.SetClipboardData(data);
WindowsUtils.SetClipboardData(data);
}
private void menuMsgViewCopyAll_Click(object sender, System.Windows.RoutedEventArgs e)
{
var data = txtMsg.Text;
Utils.SetClipboardData(data);
WindowsUtils.SetClipboardData(data);
}
private void menuMsgViewClear_Click(object sender, System.Windows.RoutedEventArgs e)