From 7faabdc375b537d4c6398f9e21293f7a492b03a0 Mon Sep 17 00:00:00 2001 From: 2dust <31833384+2dust@users.noreply.github.com> Date: Sat, 17 Aug 2024 10:53:02 +0800 Subject: [PATCH] Refactor code to decouple view and viewmodel --- v2rayN/v2rayN/Enums/EViewAction.cs | 1 + v2rayN/v2rayN/Handler/ConfigHandler.cs | 101 ++++++++++++++++-- v2rayN/v2rayN/Handler/LazyConfig.cs | 40 +++++++ v2rayN/v2rayN/Handler/TaskHandler.cs | 78 ++++++++++++++ .../{MainFormHandler.cs => WindowsHandler.cs} | 70 +----------- .../v2rayN/ViewModels/AddServer2ViewModel.cs | 16 +-- .../v2rayN/ViewModels/AddServerViewModel.cs | 49 +-------- .../ViewModels/ClashProxiesViewModel.cs | 15 ++- .../v2rayN/ViewModels/MainWindowViewModel.cs | 70 +----------- v2rayN/v2rayN/ViewModels/ProfilesViewModel.cs | 88 ++++++--------- v2rayN/v2rayN/ViewModels/SubEditViewModel.cs | 22 +--- .../ViewModels/ThemeSettingViewModel.cs | 27 ++++- v2rayN/v2rayN/Views/MainWindow.xaml.cs | 6 +- v2rayN/v2rayN/Views/ProfilesView.xaml.cs | 20 +++- 14 files changed, 304 insertions(+), 299 deletions(-) create mode 100644 v2rayN/v2rayN/Handler/TaskHandler.cs rename v2rayN/v2rayN/Handler/{MainFormHandler.cs => WindowsHandler.cs} (64%) diff --git a/v2rayN/v2rayN/Enums/EViewAction.cs b/v2rayN/v2rayN/Enums/EViewAction.cs index 19156be2..b90682a1 100644 --- a/v2rayN/v2rayN/Enums/EViewAction.cs +++ b/v2rayN/v2rayN/Enums/EViewAction.cs @@ -4,6 +4,7 @@ { CloseWindow, ShowYesNo, + SaveFileDialog, AddBatchRoutingRulesYesNo, AdjustMainLvColWidth, ProfilesFocus, diff --git a/v2rayN/v2rayN/Handler/ConfigHandler.cs b/v2rayN/v2rayN/Handler/ConfigHandler.cs index 09c45c32..8e8c0853 100644 --- a/v2rayN/v2rayN/Handler/ConfigHandler.cs +++ b/v2rayN/v2rayN/Handler/ConfigHandler.cs @@ -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; + } + /// /// Add or edit server /// /// /// /// - 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 /// 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().Count() > 0) { maxSort = SQLiteHelper.Instance.Table().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; } diff --git a/v2rayN/v2rayN/Handler/LazyConfig.cs b/v2rayN/v2rayN/Handler/LazyConfig.cs index 62f45298..3017466f 100644 --- a/v2rayN/v2rayN/Handler/LazyConfig.cs +++ b/v2rayN/v2rayN/Handler/LazyConfig.cs @@ -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(sql).ToList(); } + public List 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)) diff --git a/v2rayN/v2rayN/Handler/TaskHandler.cs b/v2rayN/v2rayN/Handler/TaskHandler.cs new file mode 100644 index 00000000..e7657ccd --- /dev/null +++ b/v2rayN/v2rayN/Handler/TaskHandler.cs @@ -0,0 +1,78 @@ +using v2rayN.Models; + +namespace v2rayN.Handler +{ + internal class TaskHandler + { + private static readonly Lazy _instance = new(() => new()); + public static TaskHandler Instance => _instance.Value; + + public TaskHandler() + { + } + + public void RegUpdateTask(Config config, Action update) + { + Task.Run(() => UpdateTaskRunSubscription(config, update)); + Task.Run(() => UpdateTaskRunGeo(config, update)); + } + + private async Task UpdateTaskRunSubscription(Config config, Action 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 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); + } + } + } +} \ No newline at end of file diff --git a/v2rayN/v2rayN/Handler/MainFormHandler.cs b/v2rayN/v2rayN/Handler/WindowsHandler.cs similarity index 64% rename from v2rayN/v2rayN/Handler/MainFormHandler.cs rename to v2rayN/v2rayN/Handler/WindowsHandler.cs index 8547277b..4b6f62ba 100644 --- a/v2rayN/v2rayN/Handler/MainFormHandler.cs +++ b/v2rayN/v2rayN/Handler/WindowsHandler.cs @@ -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 instance = new(() => new()); - public static MainFormHandler Instance => instance.Value; + private static readonly Lazy 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()?.Enqueue(msg); - } - else - { - msg = string.Format(ResUI.SaveClientConfigurationIn, fileName); - Locator.Current.GetService()?.SendMessageAndEnqueue(msg); - } - } - public void RegisterGlobalHotkey(Config config, Action handler, Action? update) { HotkeyHandler.Instance.UpdateViewEvent += update; HotkeyHandler.Instance.HotkeyTriggerEvent += handler; HotkeyHandler.Instance.Load(); } - - public void RegisterSystemColorSet(Config config, Window window, Action 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; - }); - } } } \ No newline at end of file diff --git a/v2rayN/v2rayN/ViewModels/AddServer2ViewModel.cs b/v2rayN/v2rayN/ViewModels/AddServer2ViewModel.cs index aa70027e..4cc62f35 100644 --- a/v2rayN/v2rayN/ViewModels/AddServer2ViewModel.cs +++ b/v2rayN/v2rayN/ViewModels/AddServer2ViewModel.cs @@ -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); diff --git a/v2rayN/v2rayN/ViewModels/AddServerViewModel.cs b/v2rayN/v2rayN/ViewModels/AddServerViewModel.cs index bb9f4f0e..12c86f9c 100644 --- a/v2rayN/v2rayN/ViewModels/AddServerViewModel.cs +++ b/v2rayN/v2rayN/ViewModels/AddServerViewModel.cs @@ -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); diff --git a/v2rayN/v2rayN/ViewModels/ClashProxiesViewModel.cs b/v2rayN/v2rayN/ViewModels/ClashProxiesViewModel.cs index 7bb2d92c..48b4e91b 100644 --- a/v2rayN/v2rayN/ViewModels/ClashProxiesViewModel.cs +++ b/v2rayN/v2rayN/ViewModels/ClashProxiesViewModel.cs @@ -162,8 +162,10 @@ namespace v2rayN.ViewModels if (mode != ERuleMode.Unchanged) { - Dictionary headers = new Dictionary(); - headers.Add("mode", mode.ToString().ToLower()); + Dictionary 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) diff --git a/v2rayN/v2rayN/ViewModels/MainWindowViewModel.cs b/v2rayN/v2rayN/ViewModels/MainWindowViewModel.cs index 22cd0d44..7afacf58 100644 --- a/v2rayN/v2rayN/ViewModels/MainWindowViewModel.cs +++ b/v2rayN/v2rayN/ViewModels/MainWindowViewModel.cs @@ -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 update) - { - Task.Run(() => UpdateTaskRunSubscription(config, update)); - Task.Run(() => UpdateTaskRunGeo(config, update)); - } - - private async Task UpdateTaskRunSubscription(Config config, Action 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 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 } } \ No newline at end of file diff --git a/v2rayN/v2rayN/ViewModels/ProfilesViewModel.cs b/v2rayN/v2rayN/ViewModels/ProfilesViewModel.cs index 6cc41d1e..2eeb7f95 100644 --- a/v2rayN/v2rayN/ViewModels/ProfilesViewModel.cs +++ b/v2rayN/v2rayN/ViewModels/ProfilesViewModel.cs @@ -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>(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()?.Enqueue(msg); + } + else + { + msg = string.Format(ResUI.SaveClientConfigurationIn, fileName); + Locator.Current.GetService()?.SendMessageAndEnqueue(msg); + } } public void Export2ShareUrl() diff --git a/v2rayN/v2rayN/ViewModels/SubEditViewModel.cs b/v2rayN/v2rayN/ViewModels/SubEditViewModel.cs index 1f6dec86..8d243480 100644 --- a/v2rayN/v2rayN/ViewModels/SubEditViewModel.cs +++ b/v2rayN/v2rayN/ViewModels/SubEditViewModel.cs @@ -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); diff --git a/v2rayN/v2rayN/ViewModels/ThemeSettingViewModel.cs b/v2rayN/v2rayN/ViewModels/ThemeSettingViewModel.cs index ffb8cebe..cc43c4e9 100644 --- a/v2rayN/v2rayN/ViewModels/ThemeSettingViewModel.cs +++ b/v2rayN/v2rayN/ViewModels/ThemeSettingViewModel.cs @@ -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(); - 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 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; + }); + } } } \ No newline at end of file diff --git a/v2rayN/v2rayN/Views/MainWindow.xaml.cs b/v2rayN/v2rayN/Views/MainWindow.xaml.cs index 34082e9f..8f65ef90 100644 --- a/v2rayN/v2rayN/Views/MainWindow.xaml.cs +++ b/v2rayN/v2rayN/Views/MainWindow.xaml.cs @@ -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; diff --git a/v2rayN/v2rayN/Views/ProfilesView.xaml.cs b/v2rayN/v2rayN/Views/ProfilesView.xaml.cs index bff475ec..96a53920 100644 --- a/v2rayN/v2rayN/Views/ProfilesView.xaml.cs +++ b/v2rayN/v2rayN/Views/ProfilesView.xaml.cs @@ -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: