Refactor code to decouple view and viewmodel

pull/5550/head
2dust 2024-08-17 10:53:02 +08:00
parent a9860418ba
commit 7faabdc375
14 changed files with 304 additions and 299 deletions

View File

@ -4,6 +4,7 @@
{
CloseWindow,
ShowYesNo,
SaveFileDialog,
AddBatchRoutingRulesYesNo,
AdjustMainLvColWidth,
ProfilesFocus,

View File

@ -355,13 +355,64 @@ namespace v2rayN.Handler
#region Server
public static int AddServer(Config config, ProfileItem profileItem)
{
var item = LazyConfig.Instance.GetProfileItem(profileItem.indexId);
if (item is null)
{
item = profileItem;
}
else
{
item.coreType = profileItem.coreType;
item.remarks = profileItem.remarks;
item.address = profileItem.address;
item.port = profileItem.port;
item.id = profileItem.id;
item.alterId = profileItem.alterId;
item.security = profileItem.security;
item.flow = profileItem.flow;
item.network = profileItem.network;
item.headerType = profileItem.headerType;
item.requestHost = profileItem.requestHost;
item.path = profileItem.path;
item.streamSecurity = profileItem.streamSecurity;
item.sni = profileItem.sni;
item.allowInsecure = profileItem.allowInsecure;
item.fingerprint = profileItem.fingerprint;
item.alpn = profileItem.alpn;
item.publicKey = profileItem.publicKey;
item.shortId = profileItem.shortId;
item.spiderX = profileItem.spiderX;
}
var ret = item.configType switch
{
EConfigType.VMess => AddVMessServer(config, item),
EConfigType.Shadowsocks => AddShadowsocksServer(config, item),
EConfigType.Socks => AddSocksServer(config, item),
EConfigType.Http => AddHttpServer(config, item),
EConfigType.Trojan => AddTrojanServer(config, item),
EConfigType.VLESS => AddVlessServer(config, item),
EConfigType.Hysteria2 => AddHysteria2Server(config, item),
EConfigType.Tuic => AddTuicServer(config, item),
EConfigType.Wireguard => AddWireguardServer(config, item),
_ => -1,
};
return ret;
}
/// <summary>
/// Add or edit server
/// </summary>
/// <param name="config"></param>
/// <param name="profileItem"></param>
/// <returns></returns>
public static int AddServer(Config config, ProfileItem profileItem, bool toFile = true)
public static int AddVMessServer(Config config, ProfileItem profileItem, bool toFile = true)
{
profileItem.configType = EConfigType.VMess;
@ -619,7 +670,21 @@ namespace v2rayN.Handler
/// <returns></returns>
public static int EditCustomServer(Config config, ProfileItem profileItem)
{
if (SQLiteHelper.Instance.Update(profileItem) > 0)
var item = LazyConfig.Instance.GetProfileItem(profileItem.indexId);
if (item is null)
{
item = profileItem;
}
else
{
item.remarks = profileItem.remarks;
item.address = profileItem.address;
item.coreType = profileItem.coreType;
item.displayLog = profileItem.displayLog;
item.preSocksPort = profileItem.preSocksPort;
}
if (SQLiteHelper.Instance.Update(item) > 0)
{
return 0;
}
@ -1189,7 +1254,7 @@ namespace v2rayN.Handler
var addStatus = profileItem.configType switch
{
EConfigType.VMess => AddServer(config, profileItem, false),
EConfigType.VMess => AddVMessServer(config, profileItem, false),
EConfigType.Shadowsocks => AddShadowsocksServer(config, profileItem, false),
EConfigType.Socks => AddSocksServer(config, profileItem, false),
EConfigType.Trojan => AddTrojanServer(config, profileItem, false),
@ -1419,21 +1484,41 @@ namespace v2rayN.Handler
public static int AddSubItem(Config config, SubItem subItem)
{
if (Utils.IsNullOrEmpty(subItem.id))
var item = LazyConfig.Instance.GetSubItem(subItem.id);
if (item is null)
{
subItem.id = Utils.GetGUID(false);
item = subItem;
}
else
{
item.remarks = subItem.remarks;
item.url = subItem.url;
item.moreUrl = subItem.moreUrl;
item.enabled = subItem.enabled;
item.autoUpdateInterval = subItem.autoUpdateInterval;
item.userAgent = subItem.userAgent;
item.sort = subItem.sort;
item.filter = subItem.filter;
item.convertTarget = subItem.convertTarget;
item.prevProfile = subItem.prevProfile;
item.nextProfile = subItem.nextProfile;
}
if (subItem.sort <= 0)
if (Utils.IsNullOrEmpty(item.id))
{
item.id = Utils.GetGUID(false);
if (item.sort <= 0)
{
var maxSort = 0;
if (SQLiteHelper.Instance.Table<SubItem>().Count() > 0)
{
maxSort = SQLiteHelper.Instance.Table<SubItem>().Max(t => t == null ? 0 : t.sort);
}
subItem.sort = maxSort + 1;
item.sort = maxSort + 1;
}
}
if (SQLiteHelper.Instance.Replace(subItem) > 0)
if (SQLiteHelper.Instance.Replace(item) > 0)
{
return 0;
}

View File

@ -1,4 +1,5 @@
using v2rayN.Enums;
using v2rayN.Handler.Statistics;
using v2rayN.Models;
namespace v2rayN.Handler
@ -119,6 +120,45 @@ namespace v2rayN.Handler
return SQLiteHelper.Instance.Query<ProfileItemModel>(sql).ToList();
}
public List<ProfileItemModel> ProfileItemsEx(string subid, string filter)
{
var lstModel = ProfileItems(_config.subIndexId, filter);
ConfigHandler.SetDefaultServer(_config, lstModel);
var lstServerStat = (_config.guiItem.enableStatistics ? StatisticsHandler.Instance.ServerStat : null) ?? [];
var lstProfileExs = ProfileExHandler.Instance.ProfileExs;
lstModel = (from t in lstModel
join t2 in lstServerStat on t.indexId equals t2.indexId into t2b
from t22 in t2b.DefaultIfEmpty()
join t3 in lstProfileExs on t.indexId equals t3.indexId into t3b
from t33 in t3b.DefaultIfEmpty()
select new ProfileItemModel
{
indexId = t.indexId,
configType = t.configType,
remarks = t.remarks,
address = t.address,
port = t.port,
security = t.security,
network = t.network,
streamSecurity = t.streamSecurity,
subid = t.subid,
subRemarks = t.subRemarks,
isActive = t.indexId == _config.indexId,
sort = t33 == null ? 0 : t33.sort,
delay = t33 == null ? 0 : t33.delay,
delayVal = t33?.delay != 0 ? $"{t33?.delay} {Global.DelayUnit}" : string.Empty,
speedVal = t33?.speed != 0 ? $"{t33?.speed} {Global.SpeedUnit}" : string.Empty,
todayDown = t22 == null ? "" : Utils.HumanFy(t22.todayDown),
todayUp = t22 == null ? "" : Utils.HumanFy(t22.todayUp),
totalDown = t22 == null ? "" : Utils.HumanFy(t22.totalDown),
totalUp = t22 == null ? "" : Utils.HumanFy(t22.totalUp)
}).OrderBy(t => t.sort).ToList();
return lstModel;
}
public ProfileItem? GetProfileItem(string indexId)
{
if (Utils.IsNullOrEmpty(indexId))

View File

@ -0,0 +1,78 @@
using v2rayN.Models;
namespace v2rayN.Handler
{
internal class TaskHandler
{
private static readonly Lazy<TaskHandler> _instance = new(() => new());
public static TaskHandler Instance => _instance.Value;
public TaskHandler()
{
}
public 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 UpdateHandler();
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 UpdateHandler();
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);
}
}
}
}

View File

@ -1,22 +1,15 @@
using Microsoft.Win32;
using Splat;
using System.Drawing;
using System.Drawing;
using System.IO;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Interop;
using System.Windows.Media.Imaging;
using v2rayN.Enums;
using v2rayN.Handler.CoreConfig;
using v2rayN.Models;
using v2rayN.Resx;
namespace v2rayN.Handler
{
public sealed class MainFormHandler
public sealed class WindowsHandler
{
private static readonly Lazy<MainFormHandler> instance = new(() => new());
public static MainFormHandler Instance => instance.Value;
private static readonly Lazy<WindowsHandler> instance = new(() => new());
public static WindowsHandler Instance => instance.Value;
public Icon GetNotifyIcon(Config config)
{
@ -123,66 +116,11 @@ namespace v2rayN.Handler
}
}
public void Export2ClientConfig(ProfileItem item, Config config)
{
if (item == null)
{
return;
}
SaveFileDialog fileDialog = new()
{
Filter = "Config|*.json",
FilterIndex = 2,
RestoreDirectory = true
};
if (fileDialog.ShowDialog() != true)
{
return;
}
string fileName = fileDialog.FileName;
if (Utils.IsNullOrEmpty(fileName))
{
return;
}
if (CoreConfigHandler.GenerateClientConfig(item, fileName, out string msg, out string content) != 0)
{
Locator.Current.GetService<NoticeHandler>()?.Enqueue(msg);
}
else
{
msg = string.Format(ResUI.SaveClientConfigurationIn, fileName);
Locator.Current.GetService<NoticeHandler>()?.SendMessageAndEnqueue(msg);
}
}
public void RegisterGlobalHotkey(Config config, Action<EGlobalHotkey> handler, Action<bool, string>? update)
{
HotkeyHandler.Instance.UpdateViewEvent += update;
HotkeyHandler.Instance.HotkeyTriggerEvent += handler;
HotkeyHandler.Instance.Load();
}
public void RegisterSystemColorSet(Config config, Window window, Action<bool> update)
{
var helper = new WindowInteropHelper(window);
var hwndSource = HwndSource.FromHwnd(helper.EnsureHandle());
hwndSource.AddHook((IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) =>
{
if (config.uiItem.followSystemTheme)
{
const int WM_SETTINGCHANGE = 0x001A;
if (msg == WM_SETTINGCHANGE)
{
if (wParam == IntPtr.Zero && Marshal.PtrToStringUni(lParam) == "ImmersiveColorSet")
{
update(!WindowsUtils.IsLightTheme());
}
}
}
return IntPtr.Zero;
});
}
}
}

View File

@ -67,21 +67,7 @@ namespace v2rayN.ViewModels
return;
}
var item = LazyConfig.Instance.GetProfileItem(SelectedSource.indexId);
if (item is null)
{
item = SelectedSource;
}
else
{
item.remarks = SelectedSource.remarks;
item.address = SelectedSource.address;
item.coreType = SelectedSource.coreType;
item.displayLog = SelectedSource.displayLog;
item.preSocksPort = SelectedSource.preSocksPort;
}
if (ConfigHandler.EditCustomServer(_config, item) == 0)
if (ConfigHandler.EditCustomServer(_config, SelectedSource) == 0)
{
_noticeHandler?.Enqueue(ResUI.OperationSuccess);
_updateView?.Invoke(EViewAction.CloseWindow, null);

View File

@ -85,54 +85,7 @@ namespace v2rayN.ViewModels
}
}
var item = LazyConfig.Instance.GetProfileItem(SelectedSource.indexId);
if (item is null)
{
item = SelectedSource;
}
else
{
item.coreType = SelectedSource.coreType;
item.remarks = SelectedSource.remarks;
item.address = SelectedSource.address;
item.port = SelectedSource.port;
item.id = SelectedSource.id;
item.alterId = SelectedSource.alterId;
item.security = SelectedSource.security;
item.flow = SelectedSource.flow;
item.network = SelectedSource.network;
item.headerType = SelectedSource.headerType;
item.requestHost = SelectedSource.requestHost;
item.path = SelectedSource.path;
item.streamSecurity = SelectedSource.streamSecurity;
item.sni = SelectedSource.sni;
item.allowInsecure = SelectedSource.allowInsecure;
item.fingerprint = SelectedSource.fingerprint;
item.alpn = SelectedSource.alpn;
item.publicKey = SelectedSource.publicKey;
item.shortId = SelectedSource.shortId;
item.spiderX = SelectedSource.spiderX;
}
var ret = item.configType switch
{
EConfigType.VMess => ConfigHandler.AddServer(_config, item),
EConfigType.Shadowsocks => ConfigHandler.AddShadowsocksServer(_config, item),
EConfigType.Socks => ConfigHandler.AddSocksServer(_config, item),
EConfigType.Http => ConfigHandler.AddHttpServer(_config, item),
EConfigType.Trojan => ConfigHandler.AddTrojanServer(_config, item),
EConfigType.VLESS => ConfigHandler.AddVlessServer(_config, item),
EConfigType.Hysteria2 => ConfigHandler.AddHysteria2Server(_config, item),
EConfigType.Tuic => ConfigHandler.AddTuicServer(_config, item),
EConfigType.Wireguard => ConfigHandler.AddWireguardServer(_config, item),
_ => -1,
};
if (ret == 0)
if (ConfigHandler.AddServer(_config, SelectedSource) == 0)
{
_noticeHandler?.Enqueue(ResUI.OperationSuccess);
_updateView?.Invoke(EViewAction.CloseWindow, null);

View File

@ -162,8 +162,10 @@ namespace v2rayN.ViewModels
if (mode != ERuleMode.Unchanged)
{
Dictionary<string, string> headers = new Dictionary<string, string>();
headers.Add("mode", mode.ToString().ToLower());
Dictionary<string, string> headers = new()
{
{ "mode", mode.ToString().ToLower() }
};
ClashApiHandler.Instance.ClashConfigUpdate(headers);
}
}
@ -382,15 +384,10 @@ namespace v2rayN.ViewModels
_proxyGroups.Replace(group, group2);
SelectedGroup = group2;
//var index = _proxyGroups.IndexOf(group);
//_proxyGroups.Remove(group);
//_proxyGroups.Insert(index, group);
}
_noticeHandler?.Enqueue(ResUI.OperationSuccess);
//RefreshProxyDetails(true);
//GetClashProxies(true);
}
private void ProxiesDelayTest(bool blAll)

View File

@ -381,7 +381,7 @@ namespace v2rayN.ViewModels
StatisticsHandler.Instance.Init(_config, UpdateStatisticsHandler);
}
RegUpdateTask(_config, UpdateTaskHandler);
TaskHandler.Instance.RegUpdateTask(_config, UpdateTaskHandler);
RefreshRoutingsMenu();
//RefreshServers();
@ -1015,73 +1015,5 @@ 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 UpdateHandler();
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 UpdateHandler();
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

@ -9,8 +9,8 @@ using System.Text;
using v2rayN.Base;
using v2rayN.Enums;
using v2rayN.Handler;
using v2rayN.Handler.CoreConfig;
using v2rayN.Handler.Fmt;
using v2rayN.Handler.Statistics;
using v2rayN.Models;
using v2rayN.Resx;
@ -143,7 +143,7 @@ namespace v2rayN.ViewModels
//servers delete
EditServerCmd = ReactiveCommand.Create(() =>
{
EditServer(false, EConfigType.Custom);
EditServer(EConfigType.Custom);
}, canEditRemove);
RemoveServerCmd = ReactiveCommand.Create(() =>
{
@ -346,39 +346,7 @@ namespace v2rayN.ViewModels
public void RefreshServersBiz()
{
var lstModel = LazyConfig.Instance.ProfileItems(_config.subIndexId, _serverFilter);
ConfigHandler.SetDefaultServer(_config, lstModel);
var lstServerStat = (_config.guiItem.enableStatistics ? StatisticsHandler.Instance.ServerStat : null) ?? [];
var lstProfileExs = ProfileExHandler.Instance.ProfileExs;
lstModel = (from t in lstModel
join t2 in lstServerStat on t.indexId equals t2.indexId into t2b
from t22 in t2b.DefaultIfEmpty()
join t3 in lstProfileExs on t.indexId equals t3.indexId into t3b
from t33 in t3b.DefaultIfEmpty()
select new ProfileItemModel
{
indexId = t.indexId,
configType = t.configType,
remarks = t.remarks,
address = t.address,
port = t.port,
security = t.security,
network = t.network,
streamSecurity = t.streamSecurity,
subid = t.subid,
subRemarks = t.subRemarks,
isActive = t.indexId == _config.indexId,
sort = t33 == null ? 0 : t33.sort,
delay = t33 == null ? 0 : t33.delay,
delayVal = t33?.delay != 0 ? $"{t33?.delay} {Global.DelayUnit}" : string.Empty,
speedVal = t33?.speed != 0 ? $"{t33?.speed} {Global.SpeedUnit}" : string.Empty,
todayDown = t22 == null ? "" : Utils.HumanFy(t22.todayDown),
todayUp = t22 == null ? "" : Utils.HumanFy(t22.todayUp),
totalDown = t22 == null ? "" : Utils.HumanFy(t22.totalDown),
totalUp = t22 == null ? "" : Utils.HumanFy(t22.totalUp)
}).OrderBy(t => t.sort).ToList();
var lstModel = LazyConfig.Instance.ProfileItemsEx(_config.subIndexId, _serverFilter);
_lstProfile = JsonUtils.Deserialize<List<ProfileItem>>(JsonUtils.Serialize(lstModel)) ?? [];
_profileItems.Clear();
@ -448,32 +416,20 @@ namespace v2rayN.ViewModels
return 0;
}
public void EditServer(bool blNew, EConfigType eConfigType)
public void EditServer(EConfigType eConfigType)
{
ProfileItem item;
if (blNew)
if (Utils.IsNullOrEmpty(SelectedProfile?.indexId))
{
item = new()
{
subid = _config.subIndexId,
configType = eConfigType,
isSub = false,
};
return;
}
else
var item = LazyConfig.Instance.GetProfileItem(SelectedProfile.indexId);
if (item is null)
{
if (Utils.IsNullOrEmpty(SelectedProfile?.indexId))
{
return;
}
item = LazyConfig.Instance.GetProfileItem(SelectedProfile.indexId);
if (item is null)
{
_noticeHandler?.Enqueue(ResUI.PleaseSelectServer);
return;
}
eConfigType = item.configType;
_noticeHandler?.Enqueue(ResUI.PleaseSelectServer);
return;
}
eConfigType = item.configType;
bool? ret = false;
if (eConfigType == EConfigType.Custom)
{
@ -722,7 +678,25 @@ namespace v2rayN.ViewModels
_noticeHandler?.Enqueue(ResUI.PleaseSelectServer);
return;
}
MainFormHandler.Instance.Export2ClientConfig(item, _config);
_updateView?.Invoke(EViewAction.SaveFileDialog, item);
}
public void Export2ClientConfigResult(string fileName, ProfileItem item)
{
if (Utils.IsNullOrEmpty(fileName))
{
return;
}
if (CoreConfigHandler.GenerateClientConfig(item, fileName, out string msg, out string content) != 0)
{
Locator.Current.GetService<NoticeHandler>()?.Enqueue(msg);
}
else
{
msg = string.Format(ResUI.SaveClientConfigurationIn, fileName);
Locator.Current.GetService<NoticeHandler>()?.SendMessageAndEnqueue(msg);
}
}
public void Export2ShareUrl()

View File

@ -47,27 +47,7 @@ namespace v2rayN.ViewModels
return;
}
var item = LazyConfig.Instance.GetSubItem(SelectedSource.id);
if (item is null)
{
item = SelectedSource;
}
else
{
item.remarks = SelectedSource.remarks;
item.url = SelectedSource.url;
item.moreUrl = SelectedSource.moreUrl;
item.enabled = SelectedSource.enabled;
item.autoUpdateInterval = SelectedSource.autoUpdateInterval;
item.userAgent = SelectedSource.userAgent;
item.sort = SelectedSource.sort;
item.filter = SelectedSource.filter;
item.convertTarget = SelectedSource.convertTarget;
item.prevProfile = SelectedSource.prevProfile;
item.nextProfile = SelectedSource.nextProfile;
}
if (ConfigHandler.AddSubItem(_config, item) == 0)
if (ConfigHandler.AddSubItem(_config, SelectedSource) == 0)
{
_noticeHandler?.Enqueue(ResUI.OperationSuccess);
_updateView?.Invoke(EViewAction.CloseWindow, null);

View File

@ -7,9 +7,12 @@ using ReactiveUI;
using ReactiveUI.Fody.Helpers;
using Splat;
using System.Reactive.Linq;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Interop;
using v2rayN.Base;
using v2rayN.Handler;
using v2rayN.Models;
using v2rayN.Resx;
namespace v2rayN.ViewModels
@ -40,7 +43,7 @@ namespace v2rayN.ViewModels
{
_config = LazyConfig.Instance.Config;
_noticeHandler = Locator.Current.GetService<NoticeHandler>();
MainFormHandler.Instance.RegisterSystemColorSet(_config, Application.Current.MainWindow, (bool bl) => { ModifyTheme(bl); });
RegisterSystemColorSet(_config, Application.Current.MainWindow, (bool bl) => { ModifyTheme(bl); });
BindingUI();
RestoreUI();
@ -186,5 +189,27 @@ namespace v2rayN.ViewModels
_paletteHelper.SetTheme(theme);
}
public void RegisterSystemColorSet(Config config, Window window, Action<bool> update)
{
var helper = new WindowInteropHelper(window);
var hwndSource = HwndSource.FromHwnd(helper.EnsureHandle());
hwndSource.AddHook((IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) =>
{
if (config.uiItem.followSystemTheme)
{
const int WM_SETTINGCHANGE = 0x001A;
if (msg == WM_SETTINGCHANGE)
{
if (wParam == IntPtr.Zero && Marshal.PtrToStringUni(lParam) == "ImmersiveColorSet")
{
update(!WindowsUtils.IsLightTheme());
}
}
}
return IntPtr.Zero;
});
}
}
}

View File

@ -37,7 +37,7 @@ namespace v2rayN.Views
ViewModel = new MainWindowViewModel(UpdateViewHandler);
Locator.CurrentMutable.RegisterLazySingleton(() => ViewModel, typeof(MainWindowViewModel));
MainFormHandler.Instance.RegisterGlobalHotkey(_config, OnHotkeyHandler, null);
WindowsHandler.Instance.RegisterGlobalHotkey(_config, OnHotkeyHandler, null);
this.WhenActivated(disposables =>
{
@ -252,8 +252,8 @@ namespace v2rayN.Views
case EViewAction.DispatcherRefreshIcon:
Application.Current?.Dispatcher.Invoke((() =>
{
tbNotify.Icon = MainFormHandler.Instance.GetNotifyIcon(_config);
this.Icon = MainFormHandler.Instance.GetAppIcon(_config);
tbNotify.Icon = WindowsHandler.Instance.GetNotifyIcon(_config);
this.Icon = WindowsHandler.Instance.GetAppIcon(_config);
}), DispatcherPriority.Normal);
break;

View File

@ -1,4 +1,5 @@
using MaterialDesignThemes.Wpf;
using Microsoft.Win32;
using ReactiveUI;
using Splat;
using System.Reactive.Disposables;
@ -122,6 +123,21 @@ namespace v2rayN.Views
}
break;
case EViewAction.SaveFileDialog:
if (obj is null) return false;
SaveFileDialog fileDialog = new()
{
Filter = "Config|*.json",
FilterIndex = 2,
RestoreDirectory = true
};
if (fileDialog.ShowDialog() != true)
{
return false;
}
ViewModel?.Export2ClientConfigResult(fileDialog.FileName, (ProfileItem)obj);
break;
case EViewAction.AddServerWindow:
if (obj is null) return false;
return (new AddServerWindow((ProfileItem)obj)).ShowDialog() ?? false;
@ -188,7 +204,7 @@ namespace v2rayN.Views
}
else
{
ViewModel?.EditServer(false, EConfigType.Custom);
ViewModel?.EditServer(EConfigType.Custom);
}
}
@ -224,7 +240,7 @@ namespace v2rayN.Views
break;
case Key.D:
ViewModel?.EditServer(false, EConfigType.Custom);
ViewModel?.EditServer(EConfigType.Custom);
break;
case Key.F: