From 9e9808e48988c71c2ce4105d01a332b444e4047f Mon Sep 17 00:00:00 2001 From: 2dust <31833384+2dust@users.noreply.github.com> Date: Sun, 11 Aug 2024 15:45:55 +0800 Subject: [PATCH] Refactor code to decouple view and viewmodel --- v2rayN/v2rayN/Enums/EViewAction.cs | 10 + v2rayN/v2rayN/Handler/HotkeyHandler.cs | 6 +- v2rayN/v2rayN/Handler/SpeedtestHandler.cs | 6 +- v2rayN/v2rayN/Models/SpeedTestResult.cs | 12 ++ .../ViewModels/ClashConnectionsViewModel.cs | 11 +- .../ViewModels/ClashProxiesViewModel.cs | 78 ++++---- .../v2rayN/ViewModels/MainWindowViewModel.cs | 173 +++++++----------- v2rayN/v2rayN/ViewModels/ProfilesViewModel.cs | 94 +++++----- .../ViewModels/RoutingRuleSettingViewModel.cs | 14 +- .../v2rayN/Views/ClashConnectionsView.xaml.cs | 22 ++- v2rayN/v2rayN/Views/ClashProxiesView.xaml.cs | 30 ++- v2rayN/v2rayN/Views/MainWindow.xaml.cs | 113 +++++++++--- v2rayN/v2rayN/Views/ProfilesView.xaml.cs | 74 +++++--- 13 files changed, 359 insertions(+), 284 deletions(-) create mode 100644 v2rayN/v2rayN/Models/SpeedTestResult.cs diff --git a/v2rayN/v2rayN/Enums/EViewAction.cs b/v2rayN/v2rayN/Enums/EViewAction.cs index 8160166c2e6..2db8b30f131 100644 --- a/v2rayN/v2rayN/Enums/EViewAction.cs +++ b/v2rayN/v2rayN/Enums/EViewAction.cs @@ -9,6 +9,7 @@ public enum EViewAction ProfilesFocus, ShareSub, ShareServer, + ShowHideWindow, SubEditWindow, RoutingRuleSettingWindow, RoutingRuleDetailsWindow, @@ -19,5 +20,14 @@ public enum EViewAction OptionSettingWindow, GlobalHotkeySettingWindow, SubSettingWindow, + DispatcherSpeedTest, + DispatcherRefreshConnections, + DispatcherRefreshProxyGroups, + DispatcherProxiesDelayTest, + + DispatcherStatistics, + DispatcherServerAvailability, + DispatcherReload, + DispatcherRefreshServersBiz, } } \ No newline at end of file diff --git a/v2rayN/v2rayN/Handler/HotkeyHandler.cs b/v2rayN/v2rayN/Handler/HotkeyHandler.cs index 623f9de26f5..31a733c46d9 100644 --- a/v2rayN/v2rayN/Handler/HotkeyHandler.cs +++ b/v2rayN/v2rayN/Handler/HotkeyHandler.cs @@ -72,7 +72,7 @@ public void Load() bool isSuccess = false; string msg; - Application.Current.Dispatcher.Invoke(() => + Application.Current?.Dispatcher.Invoke(() => { isSuccess = RegisterHotKey(IntPtr.Zero, _hotkeyCode, hotkeyInfo.fsModifiers, hotkeyInfo.vKey); }); @@ -96,7 +96,7 @@ public void ReLoad() { foreach (var hotkey in _hotkeyTriggerDic.Keys) { - Application.Current.Dispatcher.Invoke(() => + Application.Current?.Dispatcher.Invoke(() => { UnregisterHotKey(IntPtr.Zero, hotkey); }); @@ -137,7 +137,7 @@ private void OnThreadPreProcessMessage(ref MSG msg, ref bool handled) var _hotKeyCode = (int)msg.lParam; if (IsPause) { - Application.Current.Dispatcher.Invoke(() => + Application.Current?.Dispatcher.Invoke(() => { UIElement? element = Keyboard.FocusedElement as UIElement; if (element != null) diff --git a/v2rayN/v2rayN/Handler/SpeedtestHandler.cs b/v2rayN/v2rayN/Handler/SpeedtestHandler.cs index 14fc635afb0..179ffd82a78 100644 --- a/v2rayN/v2rayN/Handler/SpeedtestHandler.cs +++ b/v2rayN/v2rayN/Handler/SpeedtestHandler.cs @@ -14,14 +14,14 @@ internal class SpeedtestHandler private CoreHandler _coreHandler; private List _selecteds; private ESpeedActionType _actionType; - private Action _updateFunc; + private Action _updateFunc; public SpeedtestHandler(Config config) { _config = config; } - public SpeedtestHandler(Config config, CoreHandler coreHandler, List selecteds, ESpeedActionType actionType, Action update) + public SpeedtestHandler(Config config, CoreHandler coreHandler, List selecteds, ESpeedActionType actionType, Action update) { _config = config; _coreHandler = coreHandler; @@ -408,7 +408,7 @@ private string FormatOut(object time, string unit) private void UpdateFunc(string indexId, string delay, string speed = "") { - _updateFunc(indexId, delay, speed); + _updateFunc(new() { IndexId = indexId, Delay = delay, Speed = speed }); } } } \ No newline at end of file diff --git a/v2rayN/v2rayN/Models/SpeedTestResult.cs b/v2rayN/v2rayN/Models/SpeedTestResult.cs new file mode 100644 index 00000000000..08fc38fa3dc --- /dev/null +++ b/v2rayN/v2rayN/Models/SpeedTestResult.cs @@ -0,0 +1,12 @@ +namespace v2rayN.Models +{ + [Serializable] + public class SpeedTestResult + { + public string? IndexId { get; set; } + + public string? Delay { get; set; } + + public string? Speed { get; set; } + } +} \ No newline at end of file diff --git a/v2rayN/v2rayN/ViewModels/ClashConnectionsViewModel.cs b/v2rayN/v2rayN/ViewModels/ClashConnectionsViewModel.cs index b71c41bd699..e93f9e167e2 100644 --- a/v2rayN/v2rayN/ViewModels/ClashConnectionsViewModel.cs +++ b/v2rayN/v2rayN/ViewModels/ClashConnectionsViewModel.cs @@ -4,7 +4,6 @@ using ReactiveUI.Fody.Helpers; using System.Reactive; using System.Reactive.Linq; -using System.Windows; using v2rayN.Base; using v2rayN.Enums; using v2rayN.Handler; @@ -30,9 +29,10 @@ public class ClashConnectionsViewModel : MyReactiveObject [Reactive] public bool AutoRefresh { get; set; } - public ClashConnectionsViewModel() + public ClashConnectionsViewModel(Func? updateView) { _config = LazyConfig.Instance.GetConfig(); + _updateView = updateView; SortingSelected = _config.clashUIItem.connectionsSorting; AutoRefresh = _config.clashUIItem.connectionsAutoRefresh; @@ -110,14 +110,11 @@ private void GetClashConnections() return; } - Application.Current?.Dispatcher.Invoke((Action)(() => - { - RefreshConnections(it?.connections); - })); + _updateView?.Invoke(EViewAction.DispatcherRefreshConnections, it?.connections); }); } - private void RefreshConnections(List? connections) + public void RefreshConnections(List? connections) { _connectionItems.Clear(); diff --git a/v2rayN/v2rayN/ViewModels/ClashProxiesViewModel.cs b/v2rayN/v2rayN/ViewModels/ClashProxiesViewModel.cs index fb6f28a1ebd..97c04f8c828 100644 --- a/v2rayN/v2rayN/ViewModels/ClashProxiesViewModel.cs +++ b/v2rayN/v2rayN/ViewModels/ClashProxiesViewModel.cs @@ -5,7 +5,6 @@ using Splat; using System.Reactive; using System.Reactive.Linq; -using System.Windows; using v2rayN.Base; using v2rayN.Enums; using v2rayN.Handler; @@ -48,10 +47,11 @@ public class ClashProxiesViewModel : MyReactiveObject [Reactive] public bool AutoRefresh { get; set; } - public ClashProxiesViewModel() + public ClashProxiesViewModel(Func? updateView) { _noticeHandler = Locator.Current.GetService(); _config = LazyConfig.Instance.GetConfig(); + _updateView = updateView; SelectedGroup = new(); SelectedDetail = new(); @@ -149,20 +149,6 @@ public void ProxiesReload() ProxiesDelayTest(); } - public void ProxiesClear() - { - proxies = null; - providers = null; - - ClashApiHandler.Instance.SetProxies(proxies); - - Application.Current?.Dispatcher.Invoke((Action)(() => - { - _proxyGroups.Clear(); - _proxyDetails.Clear(); - })); - } - public void ProxiesDelayTest() { ProxiesDelayTest(true); @@ -197,15 +183,12 @@ private void GetClashProxies(bool refreshUI) } if (refreshUI) { - Application.Current?.Dispatcher.Invoke((Action)(() => - { - RefreshProxyGroups(); - })); + _updateView?.Invoke(EViewAction.DispatcherRefreshProxyGroups, null); } }); } - private void RefreshProxyGroups() + public void RefreshProxyGroups() { var selectedName = SelectedGroup?.name; _proxyGroups.Clear(); @@ -425,34 +408,37 @@ private void ProxiesDelayTest(bool blAll) { return; } - Application.Current?.Dispatcher.Invoke((Action)(() => - { - //UpdateHandler(false, $"{item.name}={result}"); - var detail = _proxyDetails.Where(it => it.name == item.name).FirstOrDefault(); - if (detail != null) - { - var dicResult = JsonUtils.Deserialize>(result); - if (dicResult != null && dicResult.ContainsKey("delay")) - { - detail.delay = Convert.ToInt32(dicResult["delay"].ToString()); - detail.delayName = $"{detail.delay}ms"; - } - else if (dicResult != null && dicResult.ContainsKey("message")) - { - detail.delay = delayTimeout; - detail.delayName = $"{dicResult["message"]}"; - } - else - { - detail.delay = delayTimeout; - detail.delayName = String.Empty; - } - _proxyDetails.Replace(detail, JsonUtils.DeepCopy(detail)); - } - })); + + _updateView?.Invoke(EViewAction.DispatcherProxiesDelayTest, new SpeedTestResult() { IndexId = item.name, Delay = result }); }); } + public void ProxiesDelayTestResult(SpeedTestResult result) + { + //UpdateHandler(false, $"{item.name}={result}"); + var detail = _proxyDetails.Where(it => it.name == result.IndexId).FirstOrDefault(); + if (detail != null) + { + var dicResult = JsonUtils.Deserialize>(result.Delay); + if (dicResult != null && dicResult.ContainsKey("delay")) + { + detail.delay = Convert.ToInt32(dicResult["delay"].ToString()); + detail.delayName = $"{detail.delay}ms"; + } + else if (dicResult != null && dicResult.ContainsKey("message")) + { + detail.delay = delayTimeout; + detail.delayName = $"{dicResult["message"]}"; + } + else + { + detail.delay = delayTimeout; + detail.delayName = String.Empty; + } + _proxyDetails.Replace(detail, JsonUtils.DeepCopy(detail)); + } + } + #endregion proxy function #region task diff --git a/v2rayN/v2rayN/ViewModels/MainWindowViewModel.cs b/v2rayN/v2rayN/ViewModels/MainWindowViewModel.cs index 08a981a5c68..fcff69a4ab9 100644 --- a/v2rayN/v2rayN/ViewModels/MainWindowViewModel.cs +++ b/v2rayN/v2rayN/ViewModels/MainWindowViewModel.cs @@ -25,8 +25,6 @@ public class MainWindowViewModel : MyReactiveObject private CoreHandler _coreHandler; - private bool _showInTaskbar; - #endregion private prop #region ObservableCollection @@ -175,7 +173,7 @@ public MainWindowViewModel(Func? updateView) _updateView = updateView; ThreadPool.RegisterWaitForSingleObject(App.ProgramStarted, OnProgramStarted, null, -1, false); - MessageBus.Current.Listen(Global.CommandRefreshProfiles).Subscribe(x => RefreshServersBiz()); + MessageBus.Current.Listen(Global.CommandRefreshProfiles).Subscribe(x => _updateView?.Invoke(EViewAction.DispatcherRefreshServersBiz, null)); SelectedRouting = new(); SelectedServer = new(); @@ -352,7 +350,7 @@ public MainWindowViewModel(Func? updateView) NotifyLeftClickCmd = ReactiveCommand.Create(() => { - ShowHideWindow(null); + _updateView?.Invoke(EViewAction.ShowHideWindow, null); }); //System proxy @@ -377,8 +375,7 @@ public MainWindowViewModel(Func? updateView) AutoHideStartup(); - _showInTaskbar = true; - _config.uiItem.showInTaskbar = _showInTaskbar; + _config.uiItem.showInTaskbar = true; } private void Init() @@ -405,10 +402,7 @@ private void Init() private void OnProgramStarted(object state, bool timeout) { - Application.Current?.Dispatcher.Invoke((Action)(() => - { - ShowHideWindow(true); - })); + _updateView?.Invoke(EViewAction.ShowHideWindow, true); } #endregion Init @@ -417,7 +411,7 @@ private void OnProgramStarted(object state, bool timeout) private void UpdateHandler(bool notify, string msg) { - if (!_showInTaskbar) + if (!_config.uiItem.showInTaskbar) { return; } @@ -443,24 +437,25 @@ private void UpdateTaskHandler(bool success, string msg) } private void UpdateStatisticsHandler(ServerSpeedItem update) + { + if (!_config.uiItem.showInTaskbar) + { + return; + } + _updateView?.Invoke(EViewAction.DispatcherStatistics, update); + } + + public void SetStatisticsResult(ServerSpeedItem update) { try { - if (!_showInTaskbar) - { - return; - } + SpeedProxyDisplay = string.Format(ResUI.SpeedDisplayText, Global.ProxyTag, Utils.HumanFy(update.proxyUp), Utils.HumanFy(update.proxyDown)); + SpeedDirectDisplay = string.Format(ResUI.SpeedDisplayText, Global.DirectTag, Utils.HumanFy(update.directUp), Utils.HumanFy(update.directDown)); - Application.Current?.Dispatcher.Invoke((Action)(() => + if ((update.proxyUp + update.proxyDown) > 0 && DateTime.Now.Second % 3 == 0) { - SpeedProxyDisplay = string.Format(ResUI.SpeedDisplayText, Global.ProxyTag, Utils.HumanFy(update.proxyUp), Utils.HumanFy(update.proxyDown)); - SpeedDirectDisplay = string.Format(ResUI.SpeedDisplayText, Global.DirectTag, Utils.HumanFy(update.directUp), Utils.HumanFy(update.directDown)); - - if ((update.proxyUp + update.proxyDown) > 0 && DateTime.Now.Second % 3 == 0) - { - Locator.Current.GetService()?.UpdateStatistics(update); - } - })); + Locator.Current.GetService()?.UpdateStatistics(update); + } } catch (Exception ex) { @@ -473,7 +468,7 @@ private void OnHotkeyHandler(EGlobalHotkey e) switch (e) { case EGlobalHotkey.ShowForm: - ShowHideWindow(null); + _updateView?.Invoke(EViewAction.ShowHideWindow, null); break; case EGlobalHotkey.SystemProxyClear: @@ -535,25 +530,22 @@ private void RefreshServers() MessageBus.Current.SendMessage("", Global.CommandRefreshProfiles); } - private void RefreshServersBiz() + public void RefreshServersBiz() { - Application.Current?.Dispatcher.Invoke((Action)(() => - { - RefreshServersMenu(); + RefreshServersMenu(); - //display running server - var running = ConfigHandler.GetDefaultServer(_config); - if (running != null) - { - RunningServerDisplay = - RunningServerToolTipText = running.GetSummary(); - } - else - { - RunningServerDisplay = - RunningServerToolTipText = ResUI.CheckServerSettings; - } - })); + //display running server + var running = ConfigHandler.GetDefaultServer(_config); + if (running != null) + { + RunningServerDisplay = + RunningServerToolTipText = running.GetSummary(); + } + else + { + RunningServerDisplay = + RunningServerToolTipText = ResUI.CheckServerSettings; + } } private void RefreshServersMenu() @@ -633,7 +625,7 @@ public void AddServerViaClipboard() public async Task ScanScreenTaskAsync() { - ShowHideWindow(false); + _updateView?.Invoke(EViewAction.ShowHideWindow, false); var dpiXY = QRCodeHelper.GetDpiXY(Application.Current.MainWindow); string result = await Task.Run(() => @@ -641,7 +633,7 @@ public async Task ScanScreenTaskAsync() return QRCodeHelper.ScanScreen(dpiXY.Item1, dpiXY.Item2); }); - ShowHideWindow(true); + _updateView?.Invoke(EViewAction.ShowHideWindow, true); if (Utils.IsNullOrEmpty(result)) { @@ -710,17 +702,20 @@ public void TestServerAvailability() (new UpdateHandle()).RunAvailabilityCheck((bool success, string msg) => { _noticeHandler?.SendMessage(msg, true); - Application.Current?.Dispatcher.Invoke((Action)(() => + + if (!_config.uiItem.showInTaskbar) { - if (!_showInTaskbar) - { - return; - } - RunningInfoDisplay = msg; - })); + return; + } + _updateView?.Invoke(EViewAction.DispatcherServerAvailability, msg); }); } + public void TestServerAvailabilityResult(string msg) + { + RunningInfoDisplay = msg; + } + #endregion Add Servers #region Subscription @@ -854,29 +849,28 @@ public void Reload() { TestServerAvailability(); - Application.Current?.Dispatcher.Invoke((Action)(() => - { - BlReloadEnabled = true; - ShowClashUI = _config.IsRunningCore(ECoreType.clash); - if (ShowClashUI) - { - Locator.Current.GetService()?.ProxiesReload(); - } - else { TabMainSelectedIndex = 0; } - })); + _updateView?.Invoke(EViewAction.DispatcherReload, null); }); } + public void ReloadResult() + { + ChangeSystemProxyStatus(_config.systemProxyItem.sysProxyType, false); + BlReloadEnabled = true; + ShowClashUI = _config.IsRunningCore(ECoreType.clash); + if (ShowClashUI) + { + Locator.Current.GetService()?.ProxiesReload(); + } + else { TabMainSelectedIndex = 0; } + } + private async Task LoadCore() { await Task.Run(() => { var node = ConfigHandler.GetDefaultServer(_config); _coreHandler.LoadCore(node); - - //ConfigHandler.SaveConfig(_config, false); - - ChangeSystemProxyStatus(_config.systemProxyItem.sysProxyType, false); }); } @@ -911,21 +905,18 @@ private void ChangeSystemProxyStatus(ESysProxyType type, bool blChange) SysProxyHandle.UpdateSysProxy(_config, _config.tunModeItem.enableTun ? true : false); _noticeHandler?.SendMessage($"{ResUI.TipChangeSystemProxy} - {_config.systemProxyItem.sysProxyType.ToString()}", true); - Application.Current?.Dispatcher.Invoke((Action)(() => - { - BlSystemProxyClear = (type == ESysProxyType.ForcedClear); - BlSystemProxySet = (type == ESysProxyType.ForcedChange); - BlSystemProxyNothing = (type == ESysProxyType.Unchanged); - BlSystemProxyPac = (type == ESysProxyType.Pac); + BlSystemProxyClear = (type == ESysProxyType.ForcedClear); + BlSystemProxySet = (type == ESysProxyType.ForcedChange); + BlSystemProxyNothing = (type == ESysProxyType.Unchanged); + BlSystemProxyPac = (type == ESysProxyType.Pac); - InboundDisplayStaus(); + InboundDisplayStaus(); - if (blChange) - { - NotifyIcon = MainFormHandler.Instance.GetNotifyIcon(_config); - AppIcon = MainFormHandler.Instance.GetAppIcon(_config); - } - })); + if (blChange) + { + NotifyIcon = MainFormHandler.Instance.GetNotifyIcon(_config); + AppIcon = MainFormHandler.Instance.GetAppIcon(_config); + } } private void RefreshRoutingsMenu() @@ -1013,27 +1004,6 @@ private void DoEnableTun(bool c) #region UI - public void ShowHideWindow(bool? blShow) - { - var bl = blShow ?? !_showInTaskbar; - if (bl) - { - Application.Current.MainWindow.Show(); - if (Application.Current.MainWindow.WindowState == WindowState.Minimized) - { - Application.Current.MainWindow.WindowState = WindowState.Normal; - } - Application.Current.MainWindow.Activate(); - Application.Current.MainWindow.Focus(); - } - else - { - Application.Current.MainWindow.Hide(); - } - _showInTaskbar = bl; - _config.uiItem.showInTaskbar = _showInTaskbar; - } - public void InboundDisplayStaus() { StringBuilder sb = new(); @@ -1078,10 +1048,7 @@ private void AutoHideStartup() .Delay(TimeSpan.FromSeconds(1)) .Subscribe(x => { - Application.Current?.Dispatcher.Invoke(() => - { - ShowHideWindow(false); - }); + _updateView?.Invoke(EViewAction.ShowHideWindow, false); }); } } diff --git a/v2rayN/v2rayN/ViewModels/ProfilesViewModel.cs b/v2rayN/v2rayN/ViewModels/ProfilesViewModel.cs index 3e4db0e906c..a504d20d2ae 100644 --- a/v2rayN/v2rayN/ViewModels/ProfilesViewModel.cs +++ b/v2rayN/v2rayN/ViewModels/ProfilesViewModel.cs @@ -6,7 +6,6 @@ using System.Reactive; using System.Reactive.Linq; using System.Text; -using System.Windows; using v2rayN.Base; using v2rayN.Enums; using v2rayN.Handler; @@ -106,7 +105,7 @@ public ProfilesViewModel(Func? updateView) _noticeHandler = Locator.Current.GetService(); _updateView = updateView; - MessageBus.Current.Listen(Global.CommandRefreshProfiles).Subscribe(x => RefreshServersBiz()); + MessageBus.Current.Listen(Global.CommandRefreshProfiles).Subscribe(x => _updateView?.Invoke(EViewAction.DispatcherRefreshServersBiz, null)); SelectedProfile = new(); SelectedSub = new(); @@ -246,34 +245,31 @@ private void Reload() Locator.Current.GetService()?.Reload(); } - private void UpdateSpeedtestHandler(string indexId, string delay, string speed) + private void UpdateSpeedtestHandler(SpeedTestResult result) { - Application.Current?.Dispatcher.Invoke((Action)(() => - { - SetTestResult(indexId, delay, speed); - })); + _updateView?.Invoke(EViewAction.DispatcherSpeedTest, result); } - private void SetTestResult(string indexId, string delay, string speed) + public void SetSpeedTestResult(SpeedTestResult result) { - if (Utils.IsNullOrEmpty(indexId)) + if (Utils.IsNullOrEmpty(result.IndexId)) { - _noticeHandler?.SendMessage(delay, true); - _noticeHandler?.Enqueue(delay); + _noticeHandler?.SendMessage(result.Delay, true); + _noticeHandler?.Enqueue(result.Delay); return; } - var item = _profileItems.Where(it => it.indexId == indexId).FirstOrDefault(); + var item = _profileItems.Where(it => it.indexId == result.IndexId).FirstOrDefault(); if (item != null) { - if (!Utils.IsNullOrEmpty(delay)) + if (!Utils.IsNullOrEmpty(result.Delay)) { - int.TryParse(delay, out int temp); + int.TryParse(result.Delay, out int temp); item.delay = temp; - item.delayVal = $"{delay} {Global.DelayUnit}"; + item.delayVal = $"{result.Delay} {Global.DelayUnit}"; } - if (!Utils.IsNullOrEmpty(speed)) + if (!Utils.IsNullOrEmpty(result.Speed)) { - item.speedVal = $"{speed} {Global.SpeedUnit}"; + item.speedVal = $"{result.Speed} {Global.SpeedUnit}"; } _profileItems.Replace(item, JsonUtils.DeepCopy(item)); } @@ -283,28 +279,25 @@ public void UpdateStatistics(ServerSpeedItem update) { try { - Application.Current?.Dispatcher.Invoke((Action)(() => + var item = _profileItems.Where(it => it.indexId == update.indexId).FirstOrDefault(); + if (item != null) { - var item = _profileItems.Where(it => it.indexId == update.indexId).FirstOrDefault(); - if (item != null) - { - item.todayDown = Utils.HumanFy(update.todayDown); - item.todayUp = Utils.HumanFy(update.todayUp); - item.totalDown = Utils.HumanFy(update.totalDown); - item.totalUp = Utils.HumanFy(update.totalUp); + item.todayDown = Utils.HumanFy(update.todayDown); + item.todayUp = Utils.HumanFy(update.todayUp); + item.totalDown = Utils.HumanFy(update.totalDown); + item.totalUp = Utils.HumanFy(update.totalUp); - if (SelectedProfile?.indexId == item.indexId) - { - var temp = JsonUtils.DeepCopy(item); - _profileItems.Replace(item, temp); - SelectedProfile = temp; - } - else - { - _profileItems.Replace(item, JsonUtils.DeepCopy(item)); - } + if (SelectedProfile?.indexId == item.indexId) + { + var temp = JsonUtils.DeepCopy(item); + _profileItems.Replace(item, temp); + SelectedProfile = temp; + } + else + { + _profileItems.Replace(item, JsonUtils.DeepCopy(item)); } - })); + } } catch { @@ -346,7 +339,7 @@ public void RefreshServers() MessageBus.Current.SendMessage("", Global.CommandRefreshProfiles); } - private void RefreshServersBiz() + public void RefreshServersBiz() { var lstModel = LazyConfig.Instance.ProfileItems(_config.subIndexId, _serverFilter); @@ -381,25 +374,22 @@ from t33 in t3b.DefaultIfEmpty() totalDown = t22 == null ? "" : Utils.HumanFy(t22.totalDown), totalUp = t22 == null ? "" : Utils.HumanFy(t22.totalUp) }).OrderBy(t => t.sort).ToList(); - _lstProfile = JsonUtils.Deserialize>(JsonUtils.Serialize(lstModel)); + _lstProfile = JsonUtils.Deserialize>(JsonUtils.Serialize(lstModel)) ?? []; - Application.Current?.Dispatcher.Invoke((Action)(() => + _profileItems.Clear(); + _profileItems.AddRange(lstModel); + if (lstModel.Count > 0) { - _profileItems.Clear(); - _profileItems.AddRange(lstModel); - if (lstModel.Count > 0) + var selected = lstModel.FirstOrDefault(t => t.indexId == _config.indexId); + if (selected != null) { - var selected = lstModel.FirstOrDefault(t => t.indexId == _config.indexId); - if (selected != null) - { - SelectedProfile = selected; - } - else - { - SelectedProfile = lstModel[0]; - } + SelectedProfile = selected; + } + else + { + SelectedProfile = lstModel[0]; } - })); + } } public void RefreshSubscriptions() diff --git a/v2rayN/v2rayN/ViewModels/RoutingRuleSettingViewModel.cs b/v2rayN/v2rayN/ViewModels/RoutingRuleSettingViewModel.cs index caba06a3516..17715d932fa 100644 --- a/v2rayN/v2rayN/ViewModels/RoutingRuleSettingViewModel.cs +++ b/v2rayN/v2rayN/ViewModels/RoutingRuleSettingViewModel.cs @@ -8,7 +8,6 @@ using v2rayN.Handler; using v2rayN.Models; using v2rayN.Resx; -using Application = System.Windows.Application; namespace v2rayN.ViewModels { @@ -76,9 +75,9 @@ public RoutingRuleSettingViewModel(RoutingItem routingItem, Func + ImportRulesFromUrlCmd = ReactiveCommand.Create(() => { - return ImportRulesFromUrl(); + ImportRulesFromUrl(); }); RuleRemoveCmd = ReactiveCommand.Create(() => @@ -292,7 +291,7 @@ private void ImportRulesFromClipboard() } } - private async Task ImportRulesFromUrl() + private void ImportRulesFromUrl() { var url = SelectedRouting.url; if (Utils.IsNullOrEmpty(url)) @@ -302,13 +301,10 @@ private async Task ImportRulesFromUrl() } DownloadHandle downloadHandle = new DownloadHandle(); - var result = await downloadHandle.TryDownloadString(url, true, ""); + var result = downloadHandle.TryDownloadString(url, true, "").Result; if (AddBatchRoutingRules(SelectedRouting, result) == 0) { - Application.Current.Dispatcher.Invoke((Action)(() => - { - RefreshRulesItems(); - })); + RefreshRulesItems(); _noticeHandler?.Enqueue(ResUI.OperationSuccess); } } diff --git a/v2rayN/v2rayN/Views/ClashConnectionsView.xaml.cs b/v2rayN/v2rayN/Views/ClashConnectionsView.xaml.cs index 83dc599b6f9..2bdfe7024f4 100644 --- a/v2rayN/v2rayN/Views/ClashConnectionsView.xaml.cs +++ b/v2rayN/v2rayN/Views/ClashConnectionsView.xaml.cs @@ -1,5 +1,9 @@ using ReactiveUI; using System.Reactive.Disposables; +using System.Windows; +using System.Windows.Threading; +using v2rayN.Enums; +using v2rayN.Models; using v2rayN.ViewModels; namespace v2rayN.Views @@ -12,7 +16,7 @@ public partial class ClashConnectionsView public ClashConnectionsView() { InitializeComponent(); - ViewModel = new ClashConnectionsViewModel(); + ViewModel = new ClashConnectionsViewModel(UpdateViewHandler); this.WhenActivated(disposables => { @@ -28,6 +32,22 @@ public ClashConnectionsView() }); } + private bool UpdateViewHandler(EViewAction action, object? obj) + { + switch (action) + { + case EViewAction.DispatcherRefreshConnections: + if (obj is null) return false; + Application.Current?.Dispatcher.Invoke((() => + { + ViewModel?.RefreshConnections((List?)obj); + }), DispatcherPriority.Normal); + break; + } + + return true; + } + private void btnClose_Click(object sender, System.Windows.RoutedEventArgs e) { ViewModel?.ClashConnectionClose(false); diff --git a/v2rayN/v2rayN/Views/ClashProxiesView.xaml.cs b/v2rayN/v2rayN/Views/ClashProxiesView.xaml.cs index 09b46feffb9..811b36accc4 100644 --- a/v2rayN/v2rayN/Views/ClashProxiesView.xaml.cs +++ b/v2rayN/v2rayN/Views/ClashProxiesView.xaml.cs @@ -1,7 +1,11 @@ using ReactiveUI; using Splat; using System.Reactive.Disposables; +using System.Windows; using System.Windows.Input; +using System.Windows.Threading; +using v2rayN.Enums; +using v2rayN.Models; using v2rayN.ViewModels; namespace v2rayN.Views @@ -14,7 +18,7 @@ public partial class ClashProxiesView public ClashProxiesView() { InitializeComponent(); - ViewModel = new ClashProxiesViewModel(); + ViewModel = new ClashProxiesViewModel(UpdateViewHandler); Locator.CurrentMutable.RegisterLazySingleton(() => ViewModel, typeof(ClashProxiesViewModel)); lstProxyDetails.PreviewMouseDoubleClick += lstProxyDetails_PreviewMouseDoubleClick; @@ -38,6 +42,30 @@ public ClashProxiesView() }); } + private bool UpdateViewHandler(EViewAction action, object? obj) + { + switch (action) + { + case EViewAction.DispatcherRefreshProxyGroups: + Application.Current?.Dispatcher.Invoke((() => + { + ViewModel?.RefreshProxyGroups(); + }), DispatcherPriority.Normal); + break; + + case EViewAction.DispatcherProxiesDelayTest: + + if (obj is null) return false; + Application.Current?.Dispatcher.Invoke((() => + { + ViewModel?.ProxiesDelayTestResult((SpeedTestResult)obj); + }), DispatcherPriority.Normal); + break; + } + + return true; + } + private void ProxiesView_KeyDown(object sender, KeyEventArgs e) { switch (e.Key) diff --git a/v2rayN/v2rayN/Views/MainWindow.xaml.cs b/v2rayN/v2rayN/Views/MainWindow.xaml.cs index a2152489dee..d93a3227aee 100644 --- a/v2rayN/v2rayN/Views/MainWindow.xaml.cs +++ b/v2rayN/v2rayN/Views/MainWindow.xaml.cs @@ -7,6 +7,7 @@ using System.Windows.Input; using System.Windows.Interop; using System.Windows.Media; +using System.Windows.Threading; using v2rayN.Enums; using v2rayN.Handler; using v2rayN.Models; @@ -184,35 +185,67 @@ public MainWindow() private bool UpdateViewHandler(EViewAction action, object? obj) { - if (action == EViewAction.AddServerWindow) + switch (action) { - if (obj is null) return false; - return (new AddServerWindow((ProfileItem)obj)).ShowDialog() ?? false; - } - else if (action == EViewAction.AddServer2Window) - { - if (obj is null) return false; - return (new AddServer2Window((ProfileItem)obj)).ShowDialog() ?? false; - } - else if (action == EViewAction.DNSSettingWindow) - { - return (new DNSSettingWindow().ShowDialog() ?? false); - } - else if (action == EViewAction.RoutingSettingWindow) - { - return (new RoutingSettingWindow().ShowDialog() ?? false); - } - else if (action == EViewAction.OptionSettingWindow) - { - return (new OptionSettingWindow().ShowDialog() ?? false); - } - else if (action == EViewAction.GlobalHotkeySettingWindow) - { - return (new GlobalHotkeySettingWindow().ShowDialog() ?? false); - } - else if (action == EViewAction.SubSettingWindow) - { - return (new SubSettingWindow().ShowDialog() ?? false); + case EViewAction.AddServerWindow: + if (obj is null) return false; + return (new AddServerWindow((ProfileItem)obj)).ShowDialog() ?? false; + + case EViewAction.AddServer2Window: + if (obj is null) return false; + return (new AddServer2Window((ProfileItem)obj)).ShowDialog() ?? false; + + case EViewAction.DNSSettingWindow: + return (new DNSSettingWindow().ShowDialog() ?? false); + + case EViewAction.RoutingSettingWindow: + return (new RoutingSettingWindow().ShowDialog() ?? false); + + case EViewAction.OptionSettingWindow: + return (new OptionSettingWindow().ShowDialog() ?? false); + + case EViewAction.GlobalHotkeySettingWindow: + return (new GlobalHotkeySettingWindow().ShowDialog() ?? false); + + case EViewAction.SubSettingWindow: + return (new SubSettingWindow().ShowDialog() ?? false); + + case EViewAction.ShowHideWindow: + Application.Current?.Dispatcher.Invoke((() => + { + ShowHideWindow((bool?)obj); + }), DispatcherPriority.Normal); + break; + + case EViewAction.DispatcherStatistics: + if (obj is null) return false; + Application.Current?.Dispatcher.Invoke((() => + { + ViewModel?.SetStatisticsResult((ServerSpeedItem)obj); + }), DispatcherPriority.Normal); + break; + + case EViewAction.DispatcherServerAvailability: + if (obj is null) return false; + Application.Current?.Dispatcher.Invoke((() => + { + ViewModel?.TestServerAvailabilityResult((string)obj); + }), DispatcherPriority.Normal); + break; + + case EViewAction.DispatcherReload: + Application.Current?.Dispatcher.Invoke((() => + { + ViewModel?.ReloadResult(); + }), DispatcherPriority.Normal); + break; + + case EViewAction.DispatcherRefreshServersBiz: + Application.Current?.Dispatcher.Invoke((() => + { + ViewModel?.RefreshServersBiz(); + }), DispatcherPriority.Normal); + break; } return true; @@ -223,7 +256,7 @@ private bool UpdateViewHandler(EViewAction action, object? obj) private void MainWindow_Closing(object? sender, CancelEventArgs e) { e.Cancel = true; - ViewModel?.ShowHideWindow(false); + ShowHideWindow(false); } private void menuExit_Click(object sender, RoutedEventArgs e) @@ -269,7 +302,7 @@ private void MainWindow_PreviewKeyDown(object sender, KeyEventArgs e) private void menuClose_Click(object sender, RoutedEventArgs e) { StorageUI(); - ViewModel?.ShowHideWindow(false); + ShowHideWindow(false); } private void menuPromotion_Click(object sender, RoutedEventArgs e) @@ -291,6 +324,26 @@ private void menuSettingsSetUWP_Click(object sender, RoutedEventArgs e) #region UI + public void ShowHideWindow(bool? blShow) + { + var bl = blShow ?? !_config.uiItem.showInTaskbar; + if (bl) + { + Application.Current.MainWindow.Show(); + if (Application.Current.MainWindow.WindowState == WindowState.Minimized) + { + Application.Current.MainWindow.WindowState = WindowState.Normal; + } + Application.Current.MainWindow.Activate(); + Application.Current.MainWindow.Focus(); + } + else + { + Application.Current.MainWindow.Hide(); + } + _config.uiItem.showInTaskbar = bl; + } + private void RestoreUI() { if (_config.uiItem.mainWidth > 0 && _config.uiItem.mainHeight > 0) diff --git a/v2rayN/v2rayN/Views/ProfilesView.xaml.cs b/v2rayN/v2rayN/Views/ProfilesView.xaml.cs index e22a327c906..2c70f8cd1ea 100644 --- a/v2rayN/v2rayN/Views/ProfilesView.xaml.cs +++ b/v2rayN/v2rayN/Views/ProfilesView.xaml.cs @@ -7,6 +7,7 @@ using System.Windows.Controls.Primitives; using System.Windows.Input; using System.Windows.Media; +using System.Windows.Threading; using v2rayN.Base; using v2rayN.Enums; using v2rayN.Handler; @@ -89,6 +90,7 @@ public ProfilesView() }); RestoreUI(); + ViewModel?.RefreshServers(); } #region Event @@ -100,36 +102,50 @@ private void Current_Exit(object sender, ExitEventArgs e) private bool UpdateViewHandler(EViewAction action, object? obj) { - if (action == EViewAction.ProfilesFocus) + switch (action) { - lstProfiles.Focus(); - } - else if (action == EViewAction.ShowYesNo) - { - if (UI.ShowYesNo(ResUI.RemoveServer) == MessageBoxResult.No) - { - return false; - } - } - else if (action == EViewAction.AddServerWindow) - { - if (obj is null) return false; - return (new AddServerWindow((ProfileItem)obj)).ShowDialog() ?? false; - } - else if (action == EViewAction.AddServer2Window) - { - if (obj is null) return false; - return (new AddServer2Window((ProfileItem)obj)).ShowDialog() ?? false; - } - else if (action == EViewAction.ShareServer) - { - if (obj is null) return false; - ShareServer((string)obj); - } - else if (action == EViewAction.SubEditWindow) - { - if (obj is null) return false; - return (new SubEditWindow((SubItem)obj)).ShowDialog() ?? false; + case EViewAction.ProfilesFocus: + lstProfiles.Focus(); + break; + + case EViewAction.ShowYesNo: + if (UI.ShowYesNo(ResUI.RemoveServer) == MessageBoxResult.No) + { + return false; + } + break; + + case EViewAction.AddServerWindow: + if (obj is null) return false; + return (new AddServerWindow((ProfileItem)obj)).ShowDialog() ?? false; + + case EViewAction.AddServer2Window: + if (obj is null) return false; + return (new AddServer2Window((ProfileItem)obj)).ShowDialog() ?? false; + + case EViewAction.ShareServer: + if (obj is null) return false; + ShareServer((string)obj); + break; + + case EViewAction.SubEditWindow: + if (obj is null) return false; + return (new SubEditWindow((SubItem)obj)).ShowDialog() ?? false; + + case EViewAction.DispatcherSpeedTest: + if (obj is null) return false; + Application.Current?.Dispatcher.Invoke((() => + { + ViewModel?.SetSpeedTestResult((SpeedTestResult)obj); + }), DispatcherPriority.Normal); + break; + + case EViewAction.DispatcherRefreshServersBiz: + Application.Current?.Dispatcher.Invoke((() => + { + ViewModel?.RefreshServersBiz(); + }), DispatcherPriority.Normal); + break; } return true;