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) if (type == 1)
{ {
Utils.RegWriteValue(_regPath, "ProxyEnable", 0); WindowsUtils.RegWriteValue(_regPath, "ProxyEnable", 0);
Utils.RegWriteValue(_regPath, "ProxyServer", string.Empty); WindowsUtils.RegWriteValue(_regPath, "ProxyServer", string.Empty);
Utils.RegWriteValue(_regPath, "ProxyOverride", string.Empty); WindowsUtils.RegWriteValue(_regPath, "ProxyOverride", string.Empty);
Utils.RegWriteValue(_regPath, "AutoConfigURL", string.Empty); WindowsUtils.RegWriteValue(_regPath, "AutoConfigURL", string.Empty);
} }
if (type == 2) if (type == 2)
{ {
Utils.RegWriteValue(_regPath, "ProxyEnable", 1); WindowsUtils.RegWriteValue(_regPath, "ProxyEnable", 1);
Utils.RegWriteValue(_regPath, "ProxyServer", strProxy ?? string.Empty); WindowsUtils.RegWriteValue(_regPath, "ProxyServer", strProxy ?? string.Empty);
Utils.RegWriteValue(_regPath, "ProxyOverride", exceptions ?? string.Empty); WindowsUtils.RegWriteValue(_regPath, "ProxyOverride", exceptions ?? string.Empty);
Utils.RegWriteValue(_regPath, "AutoConfigURL", string.Empty); WindowsUtils.RegWriteValue(_regPath, "AutoConfigURL", string.Empty);
} }
else if (type == 4) else if (type == 4)
{ {
Utils.RegWriteValue(_regPath, "ProxyEnable", 0); WindowsUtils.RegWriteValue(_regPath, "ProxyEnable", 0);
Utils.RegWriteValue(_regPath, "ProxyServer", string.Empty); WindowsUtils.RegWriteValue(_regPath, "ProxyServer", string.Empty);
Utils.RegWriteValue(_regPath, "ProxyOverride", string.Empty); WindowsUtils.RegWriteValue(_regPath, "ProxyOverride", string.Empty);
Utils.RegWriteValue(_regPath, "AutoConfigURL", strProxy ?? string.Empty); WindowsUtils.RegWriteValue(_regPath, "AutoConfigURL", strProxy ?? string.Empty);
} }
return true; return true;
} }

View File

@ -1,23 +1,15 @@
using Microsoft.Win32; using System.Collections.Specialized;
using Microsoft.Win32.TaskScheduler;
using System.Collections.Specialized;
using System.Diagnostics; using System.Diagnostics;
using System.Drawing;
using System.IO; using System.IO;
using System.IO.Compression; using System.IO.Compression;
using System.Net; using System.Net;
using System.Net.NetworkInformation; using System.Net.NetworkInformation;
using System.Net.Sockets; using System.Net.Sockets;
using System.Reflection; using System.Reflection;
using System.Runtime.InteropServices;
using System.Security.Cryptography; using System.Security.Cryptography;
using System.Security.Principal; using System.Security.Principal;
using System.Text; using System.Text;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using System.Windows;
using System.Windows.Interop;
using System.Windows.Media;
using System.Windows.Media.Imaging;
namespace v2rayN namespace v2rayN
{ {
@ -345,14 +337,6 @@ namespace v2rayN
return sb.ToString(); 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> /// <summary>
/// idn to idc /// idn to idc
/// </summary> /// </summary>
@ -420,11 +404,7 @@ namespace v2rayN
} }
} }
/// <summary>
/// 文本
/// </summary>
/// <param name="text"></param>
/// <returns></returns>
public static bool IsNullOrEmpty(string? text) public static bool IsNullOrEmpty(string? text)
{ {
if (string.IsNullOrWhiteSpace(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> /// <summary>
/// 取得GUID /// 取得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> /// <summary>
/// 获取系统hosts /// 获取系统hosts
/// </summary> /// </summary>
@ -958,12 +884,13 @@ namespace v2rayN
try try
{ {
var autoRunName = $"{AutoRunName}_{GetMD5(StartupPath())}"; var autoRunName = $"{AutoRunName}_{GetMD5(StartupPath())}";
WindowsUtils.
//delete first //delete first
RegWriteValue(AutoRunRegPath, autoRunName, ""); RegWriteValue(AutoRunRegPath, autoRunName, "");
if (IsAdministrator()) if (IsAdministrator())
{ {
AutoStart(autoRunName, "", ""); WindowsUtils.AutoStart(autoRunName, "", "");
} }
if (run) if (run)
@ -971,11 +898,11 @@ namespace v2rayN
string exePath = GetExePath(); string exePath = GetExePath();
if (IsAdministrator()) if (IsAdministrator())
{ {
AutoStart(autoRunName, exePath, ""); WindowsUtils.AutoStart(autoRunName, exePath, "");
} }
else 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 开机自动启动等 #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, ShareSub,
ShareServer, ShareServer,
ShowHideWindow, ShowHideWindow,
ScanScreenTask,
Shutdown,
SubEditWindow, SubEditWindow,
RoutingRuleSettingWindow, RoutingRuleSettingWindow,
RoutingRuleDetailsWindow, RoutingRuleDetailsWindow,
@ -24,10 +26,10 @@
DispatcherRefreshConnections, DispatcherRefreshConnections,
DispatcherRefreshProxyGroups, DispatcherRefreshProxyGroups,
DispatcherProxiesDelayTest, DispatcherProxiesDelayTest,
DispatcherStatistics, DispatcherStatistics,
DispatcherServerAvailability, DispatcherServerAvailability,
DispatcherReload, DispatcherReload,
DispatcherRefreshServersBiz, DispatcherRefreshServersBiz,
DispatcherRefreshIcon,
} }
} }

View File

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

View File

@ -43,7 +43,7 @@ namespace v2rayN.Handler
if (_config.globalHotkeys == null) return; if (_config.globalHotkeys == null) return;
foreach (var item in _config.globalHotkeys) 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); int key = KeyInterop.VirtualKeyFromKey((Key)item.KeyCode);
KeyModifiers modifiers = KeyModifiers.None; KeyModifiers modifiers = KeyModifiers.None;

View File

@ -156,71 +156,7 @@ namespace v2rayN.Handler
} }
} }
public void UpdateTask(Config config, Action<bool, string> update) public void RegisterGlobalHotkey(Config config, Action<EGlobalHotkey> handler, 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)
{ {
HotkeyHandler.Instance.UpdateViewEvent += update; HotkeyHandler.Instance.UpdateViewEvent += update;
HotkeyHandler.Instance.HotkeyTriggerEvent += handler; HotkeyHandler.Instance.HotkeyTriggerEvent += handler;
@ -240,7 +176,7 @@ namespace v2rayN.Handler
{ {
if (wParam == IntPtr.Zero && Marshal.PtrToStringUni(lParam) == "ImmersiveColorSet") 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 namespace v2rayN.Models
{ {
@ -152,7 +151,7 @@ namespace v2rayN.Models
public bool Shift { get; set; } public bool Shift { get; set; }
public Key? KeyCode { get; set; } public int? KeyCode { get; set; }
} }
[Serializable] [Serializable]

View File

@ -3,13 +3,10 @@ using ReactiveUI;
using ReactiveUI.Fody.Helpers; using ReactiveUI.Fody.Helpers;
using Splat; using Splat;
using System.Diagnostics; using System.Diagnostics;
using System.Drawing;
using System.IO; using System.IO;
using System.Reactive; using System.Reactive;
using System.Reactive.Linq; using System.Reactive.Linq;
using System.Text; using System.Text;
using System.Windows;
using System.Windows.Media;
using v2rayN.Base; using v2rayN.Base;
using v2rayN.Enums; using v2rayN.Enums;
using v2rayN.Handler; using v2rayN.Handler;
@ -95,12 +92,6 @@ namespace v2rayN.ViewModels
public ReactiveCommand<Unit, Unit> NotifyLeftClickCmd { get; } public ReactiveCommand<Unit, Unit> NotifyLeftClickCmd { get; }
[Reactive]
public Icon NotifyIcon { get; set; }
[Reactive]
public ImageSource AppIcon { get; set; }
#endregion Menu #endregion Menu
#region System Proxy #region System Proxy
@ -259,9 +250,9 @@ namespace v2rayN.ViewModels
{ {
AddServerViaClipboard(); AddServerViaClipboard();
}); });
AddServerViaScanCmd = ReactiveCommand.CreateFromTask(() => AddServerViaScanCmd = ReactiveCommand.Create(() =>
{ {
return ScanScreenTaskAsync(); _updateView?.Invoke(EViewAction.ScanScreenTask, null);
}); });
//Subscription //Subscription
@ -390,9 +381,7 @@ namespace v2rayN.ViewModels
StatisticsHandler.Instance.Init(_config, UpdateStatisticsHandler); StatisticsHandler.Instance.Init(_config, UpdateStatisticsHandler);
} }
MainFormHandler.Instance.UpdateTask(_config, UpdateTaskHandler); RegUpdateTask(_config, UpdateTaskHandler);
MainFormHandler.Instance.RegisterGlobalHotkey(_config, OnHotkeyHandler, UpdateTaskHandler);
RefreshRoutingsMenu(); RefreshRoutingsMenu();
//RefreshServers(); //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) public void MyAppExit(bool blWindowsShutDown)
{ {
try try
@ -517,7 +480,7 @@ namespace v2rayN.ViewModels
catch { } catch { }
finally finally
{ {
Application.Current.Shutdown(); _updateView?.Invoke(EViewAction.Shutdown, null);
} }
} }
@ -613,7 +576,7 @@ namespace v2rayN.ViewModels
public void AddServerViaClipboard() public void AddServerViaClipboard()
{ {
var clipboardData = Utils.GetClipboardData(); var clipboardData = WindowsUtils.GetClipboardData();
int ret = ConfigHandler.AddBatchServers(_config, clipboardData!, _config.subIndexId, false); int ret = ConfigHandler.AddBatchServers(_config, clipboardData!, _config.subIndexId, false);
if (ret > 0) 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)) if (Utils.IsNullOrEmpty(result))
{ {
_noticeHandler?.Enqueue(ResUI.NoValidQRcodeFound); _noticeHandler?.Enqueue(ResUI.NoValidQRcodeFound);
@ -869,6 +822,12 @@ namespace v2rayN.ViewModels
{ {
await Task.Run(() => await Task.Run(() =>
{ {
if (_config.tunModeItem.enableTun)
{
Thread.Sleep(1000);
WindowsUtils.RemoveTunDevice();
}
var node = ConfigHandler.GetDefaultServer(_config); var node = ConfigHandler.GetDefaultServer(_config);
_coreHandler.LoadCore(node); _coreHandler.LoadCore(node);
}); });
@ -914,8 +873,7 @@ namespace v2rayN.ViewModels
if (blChange) if (blChange)
{ {
NotifyIcon = MainFormHandler.Instance.GetNotifyIcon(_config); _updateView?.Invoke(EViewAction.DispatcherRefreshIcon, null);
AppIcon = MainFormHandler.Instance.GetAppIcon(_config);
} }
} }
@ -966,8 +924,7 @@ namespace v2rayN.ViewModels
{ {
_noticeHandler?.SendMessage(ResUI.TipChangeRouting, true); _noticeHandler?.SendMessage(ResUI.TipChangeRouting, true);
Reload(); Reload();
NotifyIcon = MainFormHandler.Instance.GetNotifyIcon(_config); _updateView?.Invoke(EViewAction.DispatcherRefreshIcon, null);
AppIcon = MainFormHandler.Instance.GetAppIcon(_config);
} }
} }
@ -1054,5 +1011,73 @@ namespace v2rayN.ViewModels
} }
#endregion UI #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) if (sb.Length > 0)
{ {
Utils.SetClipboardData(sb.ToString()); WindowsUtils.SetClipboardData(sb.ToString());
_noticeHandler?.SendMessage(ResUI.BatchExportURLSuccessfully); _noticeHandler?.SendMessage(ResUI.BatchExportURLSuccessfully);
} }
} }

View File

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

View File

@ -50,7 +50,7 @@ namespace v2rayN.ViewModels
{ {
if (FollowSystemTheme) if (FollowSystemTheme)
{ {
ModifyTheme(!Utils.IsLightTheme()); ModifyTheme(!WindowsUtils.IsLightTheme());
} }
else else
{ {
@ -104,7 +104,7 @@ namespace v2rayN.ViewModels
ConfigHandler.SaveConfig(_config); ConfigHandler.SaveConfig(_config);
if (FollowSystemTheme) if (FollowSystemTheme)
{ {
ModifyTheme(!Utils.IsLightTheme()); ModifyTheme(!WindowsUtils.IsLightTheme());
} }
else else
{ {
@ -173,8 +173,7 @@ namespace v2rayN.ViewModels
theme.SetBaseTheme(isDarkTheme ? BaseTheme.Dark : BaseTheme.Light); theme.SetBaseTheme(isDarkTheme ? BaseTheme.Dark : BaseTheme.Light);
_paletteHelper.SetTheme(theme); _paletteHelper.SetTheme(theme);
WindowsUtils.SetDarkBorder(Application.Current.MainWindow, isDarkTheme);
Utils.SetDarkBorder(Application.Current.MainWindow, isDarkTheme);
} }
public void ChangePrimaryColor(System.Windows.Media.Color color) 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.EditServerCmd, v => v.btnEdit).DisposeWith(disposables);
this.BindCommand(ViewModel, vm => vm.SaveServerCmd, v => v.btnSave).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.SaveServerCmd, v => v.btnSave).DisposeWith(disposables);
}); });
WindowsUtils.SetDarkBorder(this, LazyConfig.Instance.GetConfig().uiItem.followSystemTheme ? !WindowsUtils.IsLightTheme() : LazyConfig.Instance.GetConfig().uiItem.colorModeDark);
Utils.SetDarkBorder(this, LazyConfig.Instance.GetConfig().uiItem.followSystemTheme ? !Utils.IsLightTheme() : LazyConfig.Instance.GetConfig().uiItem.colorModeDark);
} }
private bool UpdateViewHandler(EViewAction action, object? obj) private bool UpdateViewHandler(EViewAction action, object? obj)

View File

@ -30,7 +30,7 @@ namespace v2rayN.Views
HotkeyHandler.Instance.IsPause = true; HotkeyHandler.Instance.IsPause = true;
this.Closing += (s, e) => HotkeyHandler.Instance.IsPause = false; 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(); InitData();
} }
@ -52,7 +52,7 @@ namespace v2rayN.Views
e.Handled = true; e.Handled = true;
var _ModifierKeys = new Key[] { Key.LeftCtrl, Key.RightCtrl, Key.LeftShift, var _ModifierKeys = new Key[] { Key.LeftCtrl, Key.RightCtrl, Key.LeftShift,
Key.RightShift, Key.LeftAlt, Key.RightAlt, Key.LWin, Key.RWin}; 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].Alt = (Keyboard.Modifiers & ModifierKeys.Alt) == ModifierKeys.Alt;
_TextBoxKeyEventItem[sender].Control = (Keyboard.Modifiers & ModifierKeys.Control) == ModifierKeys.Control; _TextBoxKeyEventItem[sender].Control = (Keyboard.Modifiers & ModifierKeys.Control) == ModifierKeys.Control;
_TextBoxKeyEventItem[sender].Shift = (Keyboard.Modifiers & ModifierKeys.Shift) == ModifierKeys.Shift; _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.Control) res.Append($"{ModifierKeys.Control}+");
if (item.Shift) res.Append($"{ModifierKeys.Shift}+"); if (item.Shift) res.Append($"{ModifierKeys.Shift}+");
if (item.Alt) res.Append($"{ModifierKeys.Alt}+"); if (item.Alt) res.Append($"{ModifierKeys.Alt}+");
if (item.KeyCode != null && item.KeyCode != Key.None) if (item.KeyCode != null && (Key)item.KeyCode != Key.None)
res.Append($"{item.KeyCode}"); res.Append($"{(Key)item.KeyCode}");
return res.ToString(); return res.ToString();
} }
@ -88,7 +88,7 @@ namespace v2rayN.Views
{ {
foreach (var item in _TextBoxKeyEventItem) 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); (item.Key as TextBox)!.Text = KeyEventItemToString(item.Value);
} }
@ -121,7 +121,7 @@ namespace v2rayN.Views
_TextBoxKeyEventItem[k].Alt = false; _TextBoxKeyEventItem[k].Alt = false;
_TextBoxKeyEventItem[k].Control = false; _TextBoxKeyEventItem[k].Control = false;
_TextBoxKeyEventItem[k].Shift = false; _TextBoxKeyEventItem[k].Shift = false;
_TextBoxKeyEventItem[k].KeyCode = Key.None; _TextBoxKeyEventItem[k].KeyCode = (int)Key.None;
} }
BindingData(); BindingData();
} }

View File

@ -37,6 +37,8 @@ namespace v2rayN.Views
ViewModel = new MainWindowViewModel(UpdateViewHandler); ViewModel = new MainWindowViewModel(UpdateViewHandler);
Locator.CurrentMutable.RegisterLazySingleton(() => ViewModel, typeof(MainWindowViewModel)); Locator.CurrentMutable.RegisterLazySingleton(() => ViewModel, typeof(MainWindowViewModel));
MainFormHandler.Instance.RegisterGlobalHotkey(_config, OnHotkeyHandler, null);
this.WhenActivated(disposables => this.WhenActivated(disposables =>
{ {
//servers //servers
@ -106,10 +108,8 @@ namespace v2rayN.Views
this.BindCommand(ViewModel, vm => vm.SubUpdateCmd, v => v.menuSubUpdate2).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.SubUpdateCmd, v => v.menuSubUpdate2).DisposeWith(disposables);
this.BindCommand(ViewModel, vm => vm.SubUpdateViaProxyCmd, v => v.menuSubUpdateViaProxy2).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.RunningServerToolTipText, v => v.tbNotify.ToolTipText).DisposeWith(disposables);
this.OneWayBind(ViewModel, vm => vm.NotifyLeftClickCmd, v => v.tbNotify.LeftClickCommand).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 //status bar
this.OneWayBind(ViewModel, vm => vm.InboundDisplay, v => v.txtInboundDisplay.Text).DisposeWith(disposables); this.OneWayBind(ViewModel, vm => vm.InboundDisplay, v => v.txtInboundDisplay.Text).DisposeWith(disposables);
@ -183,6 +183,8 @@ namespace v2rayN.Views
AddHelpMenuItem(); AddHelpMenuItem();
} }
#region Event
private bool UpdateViewHandler(EViewAction action, object? obj) private bool UpdateViewHandler(EViewAction action, object? obj)
{ {
switch (action) switch (action)
@ -246,12 +248,52 @@ namespace v2rayN.Views
ViewModel?.RefreshServersBiz(); ViewModel?.RefreshServersBiz();
}), DispatcherPriority.Normal); }), DispatcherPriority.Normal);
break; 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; 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) private void MainWindow_Closing(object? sender, CancelEventArgs e)
{ {
@ -286,7 +328,7 @@ namespace v2rayN.Views
break; break;
case Key.S: case Key.S:
ViewModel?.ScanScreenTaskAsync().ContinueWith(_ => { }); ScanScreenTaskAsync().ContinueWith(_ => { });
break; break;
} }
} }
@ -320,6 +362,21 @@ namespace v2rayN.Views
Utils.ProcessStart(Utils.GetBinPath("EnableLoopback.exe")); 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 #endregion Event
#region UI #region UI

View File

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