From 7618f9f7d46ff85747ea67bd7213cf8f218d05e0 Mon Sep 17 00:00:00 2001 From: 2dust <31833384+2dust@users.noreply.github.com> Date: Sat, 12 Oct 2024 15:45:21 +0800 Subject: [PATCH] Refactor new StatusBarViewModel --- .../ViewModels/MainWindowViewModel.cs | 476 ++---------------- .../ViewModels/ProfilesViewModel.cs | 8 +- .../ViewModels/StatusBarViewModel.cs | 459 +++++++++++++++++ v2rayN/v2rayN.Desktop/App.axaml | 8 +- v2rayN/v2rayN.Desktop/App.axaml.cs | 30 +- .../v2rayN.Desktop/ViewModels/AppViewModel.cs | 2 +- v2rayN/v2rayN.Desktop/Views/MainWindow.axaml | 68 +-- .../v2rayN.Desktop/Views/MainWindow.axaml.cs | 80 +-- .../v2rayN.Desktop/Views/StatusBarView.axaml | 81 +++ .../Views/StatusBarView.axaml.cs | 136 +++++ v2rayN/v2rayN/Views/MainWindow.xaml | 188 +------ v2rayN/v2rayN/Views/MainWindow.xaml.cs | 106 +--- v2rayN/v2rayN/Views/StatusBarView.xaml | 198 ++++++++ v2rayN/v2rayN/Views/StatusBarView.xaml.cs | 124 +++++ 14 files changed, 1095 insertions(+), 869 deletions(-) create mode 100644 v2rayN/ServiceLib/ViewModels/StatusBarViewModel.cs create mode 100644 v2rayN/v2rayN.Desktop/Views/StatusBarView.axaml create mode 100644 v2rayN/v2rayN.Desktop/Views/StatusBarView.axaml.cs create mode 100644 v2rayN/v2rayN/Views/StatusBarView.xaml create mode 100644 v2rayN/v2rayN/Views/StatusBarView.xaml.cs diff --git a/v2rayN/ServiceLib/ViewModels/MainWindowViewModel.cs b/v2rayN/ServiceLib/ViewModels/MainWindowViewModel.cs index 0ba71e7e..8ccb9033 100644 --- a/v2rayN/ServiceLib/ViewModels/MainWindowViewModel.cs +++ b/v2rayN/ServiceLib/ViewModels/MainWindowViewModel.cs @@ -1,41 +1,14 @@ -using DynamicData.Binding; using ReactiveUI; using ReactiveUI.Fody.Helpers; using Splat; using System.Diagnostics; using System.Reactive; using System.Reactive.Linq; -using System.Text; namespace ServiceLib.ViewModels { public class MainWindowViewModel : MyReactiveObject { - #region private prop - - private bool _isAdministrator { get; set; } - - #endregion private prop - - #region ObservableCollection - - private IObservableCollection _routingItems = new ObservableCollectionExtended(); - public IObservableCollection RoutingItems => _routingItems; - - private IObservableCollection _servers = new ObservableCollectionExtended(); - public IObservableCollection Servers => _servers; - - [Reactive] - public RoutingItem SelectedRouting { get; set; } - - [Reactive] - public ComboItem SelectedServer { get; set; } - - [Reactive] - public bool BlServers { get; set; } - - #endregion ObservableCollection - #region Menu //servers @@ -76,120 +49,27 @@ namespace ServiceLib.ViewModels [Reactive] public bool BlReloadEnabled { get; set; } - public ReactiveCommand NotifyLeftClickCmd { get; } - - #endregion Menu - - #region System Proxy - - [Reactive] - public bool BlSystemProxyClear { get; set; } - - [Reactive] - public bool BlSystemProxySet { get; set; } - - [Reactive] - public bool BlSystemProxyNothing { get; set; } - - [Reactive] - public bool BlSystemProxyPac { get; set; } - - public ReactiveCommand SystemProxyClearCmd { get; } - public ReactiveCommand SystemProxySetCmd { get; } - public ReactiveCommand SystemProxyNothingCmd { get; } - public ReactiveCommand SystemProxyPacCmd { get; } - - [Reactive] - public bool BlRouting { get; set; } - - [Reactive] - public int SystemProxySelected { get; set; } - - #endregion System Proxy - - #region UI - - [Reactive] - public string InboundDisplay { get; set; } - - [Reactive] - public string InboundLanDisplay { get; set; } - - [Reactive] - public string RunningServerDisplay { get; set; } - - [Reactive] - public string RunningServerToolTipText { get; set; } - - [Reactive] - public string RunningInfoDisplay { get; set; } - - [Reactive] - public string SpeedProxyDisplay { get; set; } - - [Reactive] - public string SpeedDirectDisplay { get; set; } - - [Reactive] - public bool EnableTun { get; set; } - [Reactive] public bool ShowClashUI { get; set; } [Reactive] public int TabMainSelectedIndex { get; set; } - #endregion UI + #endregion Menu #region Init - public MainWindowViewModel(bool isAdministrator, Func>? updateView) + public MainWindowViewModel(Func>? updateView) { _config = AppHandler.Instance.Config; - _updateView = updateView; - _isAdministrator = isAdministrator; - - MessageBus.Current.Listen(EMsgCommand.RefreshProfiles.ToString()).Subscribe(async x => await _updateView?.Invoke(EViewAction.DispatcherRefreshServersBiz, null)); - - SelectedRouting = new(); - SelectedServer = new(); Init(); _config.uiItem.showInTaskbar = true; - if (_config.tunModeItem.enableTun && _isAdministrator) - { - EnableTun = true; - } - else - { - _config.tunModeItem.enableTun = EnableTun = false; - } #region WhenAnyValue && ReactiveCommand - this.WhenAnyValue( - x => x.SelectedRouting, - y => y != null && !y.remarks.IsNullOrEmpty()) - .Subscribe(c => RoutingSelectedChangedAsync(c)); - - this.WhenAnyValue( - x => x.SelectedServer, - y => y != null && !y.Text.IsNullOrEmpty()) - .Subscribe(c => ServerSelectedChanged(c)); - - SystemProxySelected = (int)_config.systemProxyItem.sysProxyType; - this.WhenAnyValue( - x => x.SystemProxySelected, - y => y >= 0) - .Subscribe(c => DoSystemProxySelected(c)); - - this.WhenAnyValue( - x => x.EnableTun, - y => y == true) - .Subscribe(c => DoEnableTun(c)); - //servers AddVmessServerCmd = ReactiveCommand.CreateFromTask(async () => { @@ -237,7 +117,7 @@ namespace ServiceLib.ViewModels }); AddServerViaScanCmd = ReactiveCommand.CreateFromTask(async () => { - await _updateView?.Invoke(EViewAction.ScanScreenTask, null); + await AddServerViaScanTaskAsync(); }); //Subscription @@ -301,29 +181,6 @@ namespace ServiceLib.ViewModels await Reload(); }); - NotifyLeftClickCmd = ReactiveCommand.CreateFromTask(async () => - { - await _updateView?.Invoke(EViewAction.ShowHideWindow, null); - }); - - //System proxy - SystemProxyClearCmd = ReactiveCommand.CreateFromTask(async () => - { - await SetListenerType(ESysProxyType.ForcedClear); - }); - SystemProxySetCmd = ReactiveCommand.CreateFromTask(async () => - { - await SetListenerType(ESysProxyType.ForcedChange); - }); - SystemProxyNothingCmd = ReactiveCommand.CreateFromTask(async () => - { - await SetListenerType(ESysProxyType.Unchanged); - }); - SystemProxyPacCmd = ReactiveCommand.CreateFromTask(async () => - { - await SetListenerType(ESysProxyType.Pac); - }); - #endregion WhenAnyValue && ReactiveCommand AutoHideStartup(); @@ -334,19 +191,14 @@ namespace ServiceLib.ViewModels ConfigHandler.InitBuiltinRouting(_config); ConfigHandler.InitBuiltinDNS(_config); CoreHandler.Instance.Init(_config, UpdateHandler); + TaskHandler.Instance.RegUpdateTask(_config, UpdateTaskHandler); if (_config.guiItem.enableStatistics) { StatisticsHandler.Instance.Init(_config, UpdateStatisticsHandler); } - TaskHandler.Instance.RegUpdateTask(_config, UpdateTaskHandler); - RefreshRoutingsMenu(); - InboundDisplayStaus(); - //RefreshServers(); - Reload(); - ChangeSystemProxyStatusAsync(_config.systemProxyItem.sysProxyType, true); } #endregion Init @@ -393,9 +245,7 @@ namespace ServiceLib.ViewModels { try { - 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)); - + Locator.Current.GetService()?.UpdateStatistics(update); if ((update.proxyUp + update.proxyDown) > 0 && DateTime.Now.Second % 3 == 0) { Locator.Current.GetService()?.UpdateStatistics(update); @@ -448,6 +298,11 @@ namespace ServiceLib.ViewModels } } + public void ShowHideWindow(bool? blShow) + { + _updateView?.Invoke(EViewAction.ShowHideWindow, blShow); + } + #endregion Actions #region Servers && Groups @@ -457,50 +312,6 @@ namespace ServiceLib.ViewModels MessageBus.Current.SendMessage("", EMsgCommand.RefreshProfiles.ToString()); } - public void RefreshServersBiz() - { - RefreshServersMenu(); - - //display running server - var running = ConfigHandler.GetDefaultServer(_config); - if (running != null) - { - RunningServerDisplay = - RunningServerToolTipText = running.GetSummary(); - } - else - { - RunningServerDisplay = - RunningServerToolTipText = ResUI.CheckServerSettings; - } - } - - private void RefreshServersMenu() - { - var lstModel = AppHandler.Instance.ProfileItems(_config.subIndexId, ""); - - _servers.Clear(); - if (lstModel.Count > _config.guiItem.trayMenuServersLimit) - { - BlServers = false; - return; - } - - BlServers = true; - for (int k = 0; k < lstModel.Count; k++) - { - ProfileItem it = lstModel[k]; - string name = it.GetSummary(); - - var item = new ComboItem() { ID = it.indexId, Text = name }; - _servers.Add(item); - if (_config.indexId == it.indexId) - { - SelectedServer = item; - } - } - } - private void RefreshSubscriptions() { Locator.Current.GetService()?.RefreshSubscriptions(); @@ -554,7 +365,12 @@ namespace ServiceLib.ViewModels } } - public void ScanScreenTaskAsync(string result) + public async Task AddServerViaScanTaskAsync() + { + _updateView?.Invoke(EViewAction.ScanScreenTask, null); + } + + public void ScanScreenResult(string result) { if (Utils.IsNullOrEmpty(result)) { @@ -572,66 +388,6 @@ namespace ServiceLib.ViewModels } } - private void SetDefaultServer(string indexId) - { - if (Utils.IsNullOrEmpty(indexId)) - { - return; - } - if (indexId == _config.indexId) - { - return; - } - var item = AppHandler.Instance.GetProfileItem(indexId); - if (item is null) - { - NoticeHandler.Instance.Enqueue(ResUI.PleaseSelectServer); - return; - } - - if (ConfigHandler.SetDefaultServerIndex(_config, indexId) == 0) - { - RefreshServers(); - Reload(); - } - } - - private void ServerSelectedChanged(bool c) - { - if (!c) - { - return; - } - if (SelectedServer == null) - { - return; - } - if (Utils.IsNullOrEmpty(SelectedServer.ID)) - { - return; - } - SetDefaultServer(SelectedServer.ID); - } - - public async Task TestServerAvailability() - { - var item = ConfigHandler.GetDefaultServer(_config); - if (item == null) - { - return; - } - await (new UpdateService()).RunAvailabilityCheck(async (bool success, string msg) => - { - NoticeHandler.Instance.SendMessageEx(msg); - _updateView?.Invoke(EViewAction.DispatcherServerAvailability, msg); - }); - } - - public void TestServerAvailabilityResult(string msg) - { - RunningInfoDisplay = msg; - } - #endregion Add Servers #region Subscription @@ -658,8 +414,7 @@ namespace ServiceLib.ViewModels var ret = await _updateView?.Invoke(EViewAction.OptionSettingWindow, null); if (ret == true) { - InboundDisplayStaus(); - //RefreshServers(); + Locator.Current.GetService()?.InboundDisplayStaus(); Reload(); } } @@ -670,8 +425,7 @@ namespace ServiceLib.ViewModels if (ret == true) { ConfigHandler.InitBuiltinRouting(_config); - RefreshRoutingsMenu(); - //RefreshServers(); + Locator.Current.GetService()?.RefreshRoutingsMenu(); Reload(); } } @@ -685,20 +439,20 @@ namespace ServiceLib.ViewModels } } - private async Task RebootAsAdmin() + public async Task RebootAsAdmin() { - ProcessStartInfo startInfo = new() - { - UseShellExecute = true, - Arguments = Global.RebootAs, - WorkingDirectory = Utils.StartupPath(), - FileName = Utils.GetExePath().AppendQuotes(), - Verb = "runas", - }; try { + ProcessStartInfo startInfo = new() + { + UseShellExecute = true, + Arguments = Global.RebootAs, + WorkingDirectory = Utils.StartupPath(), + FileName = Utils.GetExePath().AppendQuotes(), + Verb = "runas", + }; Process.Start(startInfo); - MyAppExitAsync(false); + await MyAppExitAsync(false); } catch { } } @@ -730,13 +484,13 @@ namespace ServiceLib.ViewModels BlReloadEnabled = false; await LoadCore(); - await TestServerAvailability(); + Locator.Current.GetService()?.TestServerAvailability(); _updateView?.Invoke(EViewAction.DispatcherReload, null); } public void ReloadResult() { - ChangeSystemProxyStatusAsync(_config.systemProxyItem.sysProxyType, false); + //ChangeSystemProxyStatusAsync(_config.systemProxyItem.sysProxyType, false); BlReloadEnabled = true; ShowClashUI = _config.IsRunningCore(ECoreType.sing_box); if (ShowClashUI) @@ -764,180 +518,22 @@ namespace ServiceLib.ViewModels public void CloseCore() { ConfigHandler.SaveConfig(_config, false); - - ChangeSystemProxyStatusAsync(ESysProxyType.ForcedClear, false); - CoreHandler.Instance.CoreStop(); } - #endregion core job - - #region System proxy and Routings - - public async Task SetListenerType(ESysProxyType type) - { - if (_config.systemProxyItem.sysProxyType == type) - { - return; - } - _config.systemProxyItem.sysProxyType = type; - ChangeSystemProxyStatusAsync(type, true); - - SystemProxySelected = (int)_config.systemProxyItem.sysProxyType; - ConfigHandler.SaveConfig(_config, false); - } - - private async Task ChangeSystemProxyStatusAsync(ESysProxyType type, bool blChange) - { - //await _updateView?.Invoke(EViewAction.UpdateSysProxy, _config.tunModeItem.enableTun ? true : false); - _updateView?.Invoke(EViewAction.UpdateSysProxy, false); - NoticeHandler.Instance.SendMessageEx($"{ResUI.TipChangeSystemProxy} - {_config.systemProxyItem.sysProxyType.ToString()}"); - - BlSystemProxyClear = (type == ESysProxyType.ForcedClear); - BlSystemProxySet = (type == ESysProxyType.ForcedChange); - BlSystemProxyNothing = (type == ESysProxyType.Unchanged); - BlSystemProxyPac = (type == ESysProxyType.Pac); - - if (blChange) - { - _updateView?.Invoke(EViewAction.DispatcherRefreshIcon, null); - } - } - - private void RefreshRoutingsMenu() - { - _routingItems.Clear(); - if (!_config.routingBasicItem.enableRoutingAdvanced) - { - BlRouting = false; - return; - } - - BlRouting = true; - var routings = AppHandler.Instance.RoutingItems(); - foreach (var item in routings) - { - _routingItems.Add(item); - if (item.id == _config.routingBasicItem.routingIndexId) - { - SelectedRouting = item; - } - } - } - - private async Task RoutingSelectedChangedAsync(bool c) - { - if (!c) - { - return; - } - - if (SelectedRouting == null) - { - return; - } - - var item = AppHandler.Instance.GetRoutingItem(SelectedRouting?.id); - if (item is null) - { - return; - } - if (_config.routingBasicItem.routingIndexId == item.id) - { - return; - } - - if (ConfigHandler.SetDefaultRouting(_config, item) == 0) - { - NoticeHandler.Instance.SendMessageEx(ResUI.TipChangeRouting); - Reload(); - _updateView?.Invoke(EViewAction.DispatcherRefreshIcon, null); - } - } - - private void DoSystemProxySelected(bool c) - { - if (!c) - { - return; - } - if (_config.systemProxyItem.sysProxyType == (ESysProxyType)SystemProxySelected) - { - return; - } - SetListenerType((ESysProxyType)SystemProxySelected); - } - - private void DoEnableTun(bool c) - { - if (_config.tunModeItem.enableTun != EnableTun) - { - _config.tunModeItem.enableTun = EnableTun; - // When running as a non-administrator, reboot to administrator mode - if (EnableTun && !_isAdministrator) - { - _config.tunModeItem.enableTun = false; - RebootAsAdmin(); - return; - } - ConfigHandler.SaveConfig(_config); - Reload(); - } - } - - #endregion System proxy and Routings - - #region UI - - public void InboundDisplayStaus() - { - StringBuilder sb = new(); - sb.Append($"[{EInboundProtocol.socks}:{AppHandler.Instance.GetLocalPort(EInboundProtocol.socks)}]"); - sb.Append(" | "); - //if (_config.systemProxyItem.sysProxyType == ESysProxyType.ForcedChange) - //{ - // sb.Append($"[{Global.InboundHttp}({ResUI.SystemProxy}):{LazyConfig.Instance.GetLocalPort(Global.InboundHttp)}]"); - //} - //else - //{ - sb.Append($"[{EInboundProtocol.http}:{AppHandler.Instance.GetLocalPort(EInboundProtocol.http)}]"); - //} - InboundDisplay = $"{ResUI.LabLocal}:{sb}"; - - if (_config.inbound[0].allowLANConn) - { - if (_config.inbound[0].newPort4LAN) - { - StringBuilder sb2 = new(); - sb2.Append($"[{EInboundProtocol.socks}:{AppHandler.Instance.GetLocalPort(EInboundProtocol.socks2)}]"); - sb2.Append(" | "); - sb2.Append($"[{EInboundProtocol.http}:{AppHandler.Instance.GetLocalPort(EInboundProtocol.http2)}]"); - InboundLanDisplay = $"{ResUI.LabLAN}:{sb2}"; - } - else - { - InboundLanDisplay = $"{ResUI.LabLAN}:{sb}"; - } - } - else - { - InboundLanDisplay = $"{ResUI.LabLAN}:None"; - } - } - private void AutoHideStartup() { if (_config.uiItem.autoHideStartup) { Observable.Range(1, 1) - .Delay(TimeSpan.FromSeconds(1)) - .Subscribe(async x => - { - await _updateView?.Invoke(EViewAction.ShowHideWindow, false); - }); + .Delay(TimeSpan.FromSeconds(1)) + .Subscribe(async x => + { + ShowHideWindow(false); + }); } } - #endregion UI + #endregion core job } } \ No newline at end of file diff --git a/v2rayN/ServiceLib/ViewModels/ProfilesViewModel.cs b/v2rayN/ServiceLib/ViewModels/ProfilesViewModel.cs index fc121d93..7adcaa3c 100644 --- a/v2rayN/ServiceLib/ViewModels/ProfilesViewModel.cs +++ b/v2rayN/ServiceLib/ViewModels/ProfilesViewModel.cs @@ -15,7 +15,6 @@ namespace ServiceLib.ViewModels private List _lstProfile; private string _serverFilter = string.Empty; - private Dictionary _dicHeaderSort = new(); private SpeedtestService? _speedtestHandler; @@ -57,7 +56,6 @@ namespace ServiceLib.ViewModels //servers delete public ReactiveCommand EditServerCmd { get; } - public ReactiveCommand RemoveServerCmd { get; } public ReactiveCommand RemoveDuplicateServerCmd { get; } public ReactiveCommand CopyServerCmd { get; } @@ -68,14 +66,12 @@ namespace ServiceLib.ViewModels //servers move public ReactiveCommand MoveTopCmd { get; } - public ReactiveCommand MoveUpCmd { get; } public ReactiveCommand MoveDownCmd { get; } public ReactiveCommand MoveBottomCmd { get; } //servers ping public ReactiveCommand MixedTestServerCmd { get; } - public ReactiveCommand TcpingServerCmd { get; } public ReactiveCommand RealPingServerCmd { get; } public ReactiveCommand SpeedServerCmd { get; } @@ -83,7 +79,6 @@ namespace ServiceLib.ViewModels //servers export public ReactiveCommand Export2ClientConfigCmd { get; } - public ReactiveCommand Export2ClientConfigClipboardCmd { get; } public ReactiveCommand Export2ShareUrlCmd { get; } public ReactiveCommand Export2ShareUrlBase64Cmd { get; } @@ -98,7 +93,6 @@ namespace ServiceLib.ViewModels public ProfilesViewModel(Func>? updateView) { _config = AppHandler.Instance.Config; - _updateView = updateView; MessageBus.Current.Listen(EMsgCommand.RefreshProfiles.ToString()).Subscribe(async x => await _updateView?.Invoke(EViewAction.DispatcherRefreshServersBiz, null)); @@ -505,7 +499,7 @@ namespace ServiceLib.ViewModels SetDefaultServer(SelectedProfile.indexId); } - private async Task SetDefaultServer(string indexId) + public async Task SetDefaultServer(string indexId) { if (Utils.IsNullOrEmpty(indexId)) { diff --git a/v2rayN/ServiceLib/ViewModels/StatusBarViewModel.cs b/v2rayN/ServiceLib/ViewModels/StatusBarViewModel.cs new file mode 100644 index 00000000..397cbb38 --- /dev/null +++ b/v2rayN/ServiceLib/ViewModels/StatusBarViewModel.cs @@ -0,0 +1,459 @@ +using DynamicData.Binding; +using ReactiveUI; +using ReactiveUI.Fody.Helpers; +using Splat; +using System.Reactive; +using System.Reactive.Linq; +using System.Text; + +namespace ServiceLib.ViewModels +{ + public class StatusBarViewModel : MyReactiveObject + { + private bool _isAdministrator { get; set; } + + #region ObservableCollection + + private IObservableCollection _routingItems = new ObservableCollectionExtended(); + public IObservableCollection RoutingItems => _routingItems; + + private IObservableCollection _servers = new ObservableCollectionExtended(); + public IObservableCollection Servers => _servers; + + [Reactive] + public RoutingItem SelectedRouting { get; set; } + + [Reactive] + public ComboItem SelectedServer { get; set; } + + [Reactive] + public bool BlServers { get; set; } + + #endregion ObservableCollection + + public ReactiveCommand AddServerViaClipboardCmd { get; } + public ReactiveCommand AddServerViaScanCmd { get; } + public ReactiveCommand SubUpdateCmd { get; } + public ReactiveCommand SubUpdateViaProxyCmd { get; } + public ReactiveCommand NotifyLeftClickCmd { get; } + public ReactiveCommand ExitCmd { get; } + + #region System Proxy + + [Reactive] + public bool BlSystemProxyClear { get; set; } + + [Reactive] + public bool BlSystemProxySet { get; set; } + + [Reactive] + public bool BlSystemProxyNothing { get; set; } + + [Reactive] + public bool BlSystemProxyPac { get; set; } + + public ReactiveCommand SystemProxyClearCmd { get; } + public ReactiveCommand SystemProxySetCmd { get; } + public ReactiveCommand SystemProxyNothingCmd { get; } + public ReactiveCommand SystemProxyPacCmd { get; } + + [Reactive] + public bool BlRouting { get; set; } + + [Reactive] + public int SystemProxySelected { get; set; } + + #endregion System Proxy + + #region UI + + [Reactive] + public string InboundDisplay { get; set; } + + [Reactive] + public string InboundLanDisplay { get; set; } + + [Reactive] + public string RunningServerDisplay { get; set; } + + [Reactive] + public string RunningServerToolTipText { get; set; } + + [Reactive] + public string RunningInfoDisplay { get; set; } + + [Reactive] + public string SpeedProxyDisplay { get; set; } + + [Reactive] + public string SpeedDirectDisplay { get; set; } + + [Reactive] + public bool EnableTun { get; set; } + + #endregion UI + + public StatusBarViewModel(Func>? updateView) + { + _config = AppHandler.Instance.Config; + _updateView = updateView; + + if (_updateView != null) + { + MessageBus.Current.Listen(EMsgCommand.RefreshProfiles.ToString()) + .Subscribe(async x => await _updateView?.Invoke(EViewAction.DispatcherRefreshServersBiz, null)); + } + + SelectedRouting = new(); + SelectedServer = new(); + + _isAdministrator = Utils.IsAdministrator(); + if (_config.tunModeItem.enableTun && _isAdministrator) + { + EnableTun = true; + } + else + { + _config.tunModeItem.enableTun = EnableTun = false; + } + + RefreshRoutingsMenu(); + InboundDisplayStaus(); + ChangeSystemProxyAsync(_config.systemProxyItem.sysProxyType, true); + + #region WhenAnyValue && ReactiveCommand + + this.WhenAnyValue( + x => x.SelectedRouting, + y => y != null && !y.remarks.IsNullOrEmpty()) + .Subscribe(c => RoutingSelectedChangedAsync(c)); + + this.WhenAnyValue( + x => x.SelectedServer, + y => y != null && !y.Text.IsNullOrEmpty()) + .Subscribe(c => ServerSelectedChanged(c)); + + SystemProxySelected = (int)_config.systemProxyItem.sysProxyType; + this.WhenAnyValue( + x => x.SystemProxySelected, + y => y >= 0) + .Subscribe(c => DoSystemProxySelected(c)); + + this.WhenAnyValue( + x => x.EnableTun, + y => y == true) + .Subscribe(c => DoEnableTun(c)); + + NotifyLeftClickCmd = ReactiveCommand.CreateFromTask(async () => + { + Locator.Current.GetService()?.ShowHideWindow(null); + }); + + AddServerViaClipboardCmd = ReactiveCommand.CreateFromTask(async () => + { + await AddServerViaClipboard(); + }); + AddServerViaScanCmd = ReactiveCommand.CreateFromTask(async () => + { + await AddServerViaScan(); + }); + SubUpdateCmd = ReactiveCommand.CreateFromTask(async () => + { + await UpdateSubscriptionProcess(false); + }); + SubUpdateViaProxyCmd = ReactiveCommand.CreateFromTask(async () => + { + await UpdateSubscriptionProcess(true); + }); + + //System proxy + SystemProxyClearCmd = ReactiveCommand.CreateFromTask(async () => + { + await SetListenerType(ESysProxyType.ForcedClear); + }); + SystemProxySetCmd = ReactiveCommand.CreateFromTask(async () => + { + await SetListenerType(ESysProxyType.ForcedChange); + }); + SystemProxyNothingCmd = ReactiveCommand.CreateFromTask(async () => + { + await SetListenerType(ESysProxyType.Unchanged); + }); + SystemProxyPacCmd = ReactiveCommand.CreateFromTask(async () => + { + await SetListenerType(ESysProxyType.Pac); + }); + + #endregion WhenAnyValue && ReactiveCommand + } + + public void Init(Func>? updateView) + { + _updateView = updateView; + if (_updateView != null) + { + MessageBus.Current.Listen(EMsgCommand.RefreshProfiles.ToString()) + .Subscribe(async x => await _updateView?.Invoke(EViewAction.DispatcherRefreshServersBiz, null)); + } + } + + private async Task AddServerViaClipboard() + { + var service = Locator.Current.GetService(); + if (service != null) await service.AddServerViaClipboardAsync(null); + } + + private async Task AddServerViaScan() + { + var service = Locator.Current.GetService(); + if (service != null) await service.AddServerViaScanTaskAsync(); + } + + private async Task UpdateSubscriptionProcess(bool blProxy) + { + var service = Locator.Current.GetService(); + if (service != null) await service.UpdateSubscriptionProcess("", blProxy); + } + + public void RefreshServersBiz() + { + RefreshServersMenu(); + + //display running server + var running = ConfigHandler.GetDefaultServer(_config); + if (running != null) + { + RunningServerDisplay = + RunningServerToolTipText = running.GetSummary(); + } + else + { + RunningServerDisplay = + RunningServerToolTipText = ResUI.CheckServerSettings; + } + } + + private void RefreshServersMenu() + { + var lstModel = AppHandler.Instance.ProfileItems(_config.subIndexId, ""); + + _servers.Clear(); + if (lstModel.Count > _config.guiItem.trayMenuServersLimit) + { + BlServers = false; + return; + } + + BlServers = true; + for (int k = 0; k < lstModel.Count; k++) + { + ProfileItem it = lstModel[k]; + string name = it.GetSummary(); + + var item = new ComboItem() { ID = it.indexId, Text = name }; + _servers.Add(item); + if (_config.indexId == it.indexId) + { + SelectedServer = item; + } + } + } + + private void ServerSelectedChanged(bool c) + { + if (!c) + { + return; + } + if (SelectedServer == null) + { + return; + } + if (Utils.IsNullOrEmpty(SelectedServer.ID)) + { + return; + } + Locator.Current.GetService()?.SetDefaultServer(SelectedServer.ID); + } + + public async Task TestServerAvailability() + { + var item = ConfigHandler.GetDefaultServer(_config); + if (item == null) + { + return; + } + await (new UpdateService()).RunAvailabilityCheck(async (bool success, string msg) => + { + NoticeHandler.Instance.SendMessageEx(msg); + _updateView?.Invoke(EViewAction.DispatcherServerAvailability, msg); + }); + } + + public void TestServerAvailabilityResult(string msg) + { + RunningInfoDisplay = msg; + } + + #region System proxy and Routings + + public async Task SetListenerType(ESysProxyType type) + { + if (_config.systemProxyItem.sysProxyType == type) + { + return; + } + _config.systemProxyItem.sysProxyType = type; + ChangeSystemProxyAsync(type, true); + NoticeHandler.Instance.SendMessageEx($"{ResUI.TipChangeSystemProxy} - {_config.systemProxyItem.sysProxyType.ToString()}"); + + SystemProxySelected = (int)_config.systemProxyItem.sysProxyType; + ConfigHandler.SaveConfig(_config, false); + } + + private async Task ChangeSystemProxyAsync(ESysProxyType type, bool blChange) + { + //await _updateView?.Invoke(EViewAction.UpdateSysProxy, _config.tunModeItem.enableTun ? true : false); + _updateView?.Invoke(EViewAction.UpdateSysProxy, false); + + BlSystemProxyClear = (type == ESysProxyType.ForcedClear); + BlSystemProxySet = (type == ESysProxyType.ForcedChange); + BlSystemProxyNothing = (type == ESysProxyType.Unchanged); + BlSystemProxyPac = (type == ESysProxyType.Pac); + + if (blChange) + { + _updateView?.Invoke(EViewAction.DispatcherRefreshIcon, null); + } + } + + public void RefreshRoutingsMenu() + { + _routingItems.Clear(); + if (!_config.routingBasicItem.enableRoutingAdvanced) + { + BlRouting = false; + return; + } + + BlRouting = true; + var routings = AppHandler.Instance.RoutingItems(); + foreach (var item in routings) + { + _routingItems.Add(item); + if (item.id == _config.routingBasicItem.routingIndexId) + { + SelectedRouting = item; + } + } + } + + private async Task RoutingSelectedChangedAsync(bool c) + { + if (!c) + { + return; + } + + if (SelectedRouting == null) + { + return; + } + + var item = AppHandler.Instance.GetRoutingItem(SelectedRouting?.id); + if (item is null) + { + return; + } + if (_config.routingBasicItem.routingIndexId == item.id) + { + return; + } + + if (ConfigHandler.SetDefaultRouting(_config, item) == 0) + { + NoticeHandler.Instance.SendMessageEx(ResUI.TipChangeRouting); + Locator.Current.GetService()?.Reload(); + _updateView?.Invoke(EViewAction.DispatcherRefreshIcon, null); + } + } + + private void DoSystemProxySelected(bool c) + { + if (!c) + { + return; + } + if (_config.systemProxyItem.sysProxyType == (ESysProxyType)SystemProxySelected) + { + return; + } + SetListenerType((ESysProxyType)SystemProxySelected); + } + + private void DoEnableTun(bool c) + { + if (_config.tunModeItem.enableTun != EnableTun) + { + _config.tunModeItem.enableTun = EnableTun; + // When running as a non-administrator, reboot to administrator mode + if (EnableTun && !_isAdministrator) + { + _config.tunModeItem.enableTun = false; + Locator.Current.GetService()?.RebootAsAdmin(); + return; + } + ConfigHandler.SaveConfig(_config); + Locator.Current.GetService()?.Reload(); + } + } + + #endregion System proxy and Routings + + #region UI + + public void InboundDisplayStaus() + { + StringBuilder sb = new(); + sb.Append($"[{EInboundProtocol.socks}:{AppHandler.Instance.GetLocalPort(EInboundProtocol.socks)}]"); + sb.Append(" | "); + //if (_config.systemProxyItem.sysProxyType == ESysProxyType.ForcedChange) + //{ + // sb.Append($"[{Global.InboundHttp}({ResUI.SystemProxy}):{LazyConfig.Instance.GetLocalPort(Global.InboundHttp)}]"); + //} + //else + //{ + sb.Append($"[{EInboundProtocol.http}:{AppHandler.Instance.GetLocalPort(EInboundProtocol.http)}]"); + //} + InboundDisplay = $"{ResUI.LabLocal}:{sb}"; + + if (_config.inbound[0].allowLANConn) + { + if (_config.inbound[0].newPort4LAN) + { + StringBuilder sb2 = new(); + sb2.Append($"[{EInboundProtocol.socks}:{AppHandler.Instance.GetLocalPort(EInboundProtocol.socks2)}]"); + sb2.Append(" | "); + sb2.Append($"[{EInboundProtocol.http}:{AppHandler.Instance.GetLocalPort(EInboundProtocol.http2)}]"); + InboundLanDisplay = $"{ResUI.LabLAN}:{sb2}"; + } + else + { + InboundLanDisplay = $"{ResUI.LabLAN}:{sb}"; + } + } + else + { + InboundLanDisplay = $"{ResUI.LabLAN}:None"; + } + } + + public void UpdateStatistics(ServerSpeedItem update) + { + 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)); + } + + #endregion UI + } +} \ No newline at end of file diff --git a/v2rayN/v2rayN.Desktop/App.axaml b/v2rayN/v2rayN.Desktop/App.axaml index d8503ed2..4abccec4 100644 --- a/v2rayN/v2rayN.Desktop/App.axaml +++ b/v2rayN/v2rayN.Desktop/App.axaml @@ -2,9 +2,9 @@ x:Class="v2rayN.Desktop.App" xmlns="https://github.com/avaloniaui" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" - xmlns:local="using:v2rayN.Desktop.ViewModels" xmlns:resx="clr-namespace:ServiceLib.Resx;assembly=ServiceLib" - x:DataType="local:AppViewModel" + xmlns:vms="clr-namespace:ServiceLib.ViewModels;assembly=ServiceLib" + x:DataType="vms:StatusBarViewModel" RequestedThemeVariant="Default"> @@ -37,13 +37,13 @@ - + - + diff --git a/v2rayN/v2rayN.Desktop/App.axaml.cs b/v2rayN/v2rayN.Desktop/App.axaml.cs index 308a200c..3e7251f2 100644 --- a/v2rayN/v2rayN.Desktop/App.axaml.cs +++ b/v2rayN/v2rayN.Desktop/App.axaml.cs @@ -1,7 +1,8 @@ using Avalonia; using Avalonia.Controls.ApplicationLifetimes; using Avalonia.Markup.Xaml; -using v2rayN.Desktop.ViewModels; +using Splat; +using v2rayN.Desktop.Common; using v2rayN.Desktop.Views; namespace v2rayN.Desktop; @@ -22,7 +23,9 @@ public partial class App : Application AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException; TaskScheduler.UnobservedTaskException += TaskScheduler_UnobservedTaskException; - this.DataContext = new AppViewModel(); + var ViewModel = new StatusBarViewModel(null); + Locator.CurrentMutable.RegisterLazySingleton(() => ViewModel, typeof(StatusBarViewModel)); + this.DataContext = ViewModel; } public override void OnFrameworkInitializationCompleted() @@ -85,4 +88,27 @@ public partial class App : Application } } } + + private void MenuAddServerViaClipboardClick(object? sender, EventArgs e) + { + if (Application.Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) + { + if (desktop.MainWindow != null) + { + var clipboardData = AvaUtils.GetClipboardData(desktop.MainWindow).Result; + var service = Locator.Current.GetService(); + if (service != null) _ = service.AddServerViaClipboardAsync(clipboardData); + } + } + } + + private void MenuExit_Click(object? sender, EventArgs e) + { + if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) + { + Locator.Current.GetService()?.MyAppExitAsync(false); + + desktop.Shutdown(); + } + } } \ No newline at end of file diff --git a/v2rayN/v2rayN.Desktop/ViewModels/AppViewModel.cs b/v2rayN/v2rayN.Desktop/ViewModels/AppViewModel.cs index db9e11f5..4b56a9a5 100644 --- a/v2rayN/v2rayN.Desktop/ViewModels/AppViewModel.cs +++ b/v2rayN/v2rayN.Desktop/ViewModels/AppViewModel.cs @@ -61,7 +61,7 @@ namespace v2rayN.Desktop.ViewModels return; } - var service = Locator.Current.GetService(); + var service = Locator.Current.GetService(); if (service != null) await service.SetListenerType(type); } diff --git a/v2rayN/v2rayN.Desktop/Views/MainWindow.axaml b/v2rayN/v2rayN.Desktop/Views/MainWindow.axaml index 65f2017a..e86bd461 100644 --- a/v2rayN/v2rayN.Desktop/Views/MainWindow.axaml +++ b/v2rayN/v2rayN.Desktop/Views/MainWindow.axaml @@ -6,6 +6,7 @@ xmlns:dialogHost="clr-namespace:DialogHostAvalonia;assembly=DialogHost.Avalonia" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:resx="clr-namespace:ServiceLib.Resx;assembly=ServiceLib" + xmlns:view="using:v2rayN.Desktop.Views" xmlns:vms="clr-namespace:ServiceLib.ViewModels;assembly=ServiceLib" Title="v2rayN" Width="900" @@ -118,72 +119,7 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + diff --git a/v2rayN/v2rayN.Desktop/Views/MainWindow.axaml.cs b/v2rayN/v2rayN.Desktop/Views/MainWindow.axaml.cs index c41bfdb3..83933ef7 100644 --- a/v2rayN/v2rayN.Desktop/Views/MainWindow.axaml.cs +++ b/v2rayN/v2rayN.Desktop/Views/MainWindow.axaml.cs @@ -12,7 +12,6 @@ using Splat; using System.ComponentModel; using System.Reactive.Disposables; using v2rayN.Desktop.Common; -using v2rayN.Desktop.Handler; namespace v2rayN.Desktop.Views { @@ -40,9 +39,8 @@ namespace v2rayN.Desktop.Views menuCheckUpdate.Click += MenuCheckUpdate_Click; menuBackupAndRestore.Click += MenuBackupAndRestore_Click; - var IsAdministrator = Utils.IsAdministrator(); MessageBus.Current.Listen(EMsgCommand.SendSnackMsg.ToString()).Subscribe(x => DelegateSnackMsg(x)); - ViewModel = new MainWindowViewModel(IsAdministrator, UpdateViewHandler); + ViewModel = new MainWindowViewModel(UpdateViewHandler); Locator.CurrentMutable.RegisterLazySingleton(() => ViewModel, typeof(MainWindowViewModel)); //WindowsHandler.Instance.RegisterGlobalHotkey(_config, OnHotkeyHandler, null); @@ -82,19 +80,6 @@ namespace v2rayN.Desktop.Views this.BindCommand(ViewModel, vm => vm.ReloadCmd, v => v.menuReload).DisposeWith(disposables); this.OneWayBind(ViewModel, vm => vm.BlReloadEnabled, v => v.menuReload.IsEnabled).DisposeWith(disposables); - //status bar - this.OneWayBind(ViewModel, vm => vm.InboundDisplay, v => v.txtInboundDisplay.Text).DisposeWith(disposables); - this.OneWayBind(ViewModel, vm => vm.InboundLanDisplay, v => v.txtInboundLanDisplay.Text).DisposeWith(disposables); - this.OneWayBind(ViewModel, vm => vm.RunningServerDisplay, v => v.txtRunningServerDisplay.Text).DisposeWith(disposables); - this.OneWayBind(ViewModel, vm => vm.RunningInfoDisplay, v => v.txtRunningInfoDisplay.Text).DisposeWith(disposables); - this.OneWayBind(ViewModel, vm => vm.SpeedProxyDisplay, v => v.txtSpeedProxyDisplay.Text).DisposeWith(disposables); - this.OneWayBind(ViewModel, vm => vm.SpeedDirectDisplay, v => v.txtSpeedDirectDisplay.Text).DisposeWith(disposables); - this.Bind(ViewModel, vm => vm.EnableTun, v => v.togEnableTun.IsChecked).DisposeWith(disposables); - - this.Bind(ViewModel, vm => vm.SystemProxySelected, v => v.cmbSystemProxy.SelectedIndex).DisposeWith(disposables); - //this.OneWayBind(ViewModel, vm => vm.RoutingItems, v => v.cmbRoutings2.ItemsSource).DisposeWith(disposables); - this.Bind(ViewModel, vm => vm.SelectedRouting, v => v.cmbRoutings2.SelectedItem).DisposeWith(disposables); - if (_config.uiItem.mainGirdOrientation == EGirdOrientation.Horizontal) { gridMain.IsVisible = true; @@ -118,7 +103,7 @@ namespace v2rayN.Desktop.Views } }); - this.Title = $"{Utils.GetVersion()} - {(IsAdministrator ? ResUI.RunAsAdmin : ResUI.NotRunAsAdmin)}"; + this.Title = $"{Utils.GetVersion()} - {(Utils.IsAdministrator() ? ResUI.RunAsAdmin : ResUI.NotRunAsAdmin)}"; if (Utils.IsWindows()) { menuGlobalHotkeySetting.IsVisible = false; @@ -128,10 +113,6 @@ namespace v2rayN.Desktop.Views menuRebootAsAdmin.IsVisible = false; menuSettingsSetUWP.IsVisible = false; menuGlobalHotkeySetting.IsVisible = false; - if (_config.tunModeItem.enableTun) - { - ViewModel.EnableTun = true; - } } if (_config.uiItem.mainGirdOrientation == EGirdOrientation.Horizontal) @@ -215,33 +196,12 @@ namespace v2rayN.Desktop.Views DispatcherPriority.Default); break; - case EViewAction.DispatcherServerAvailability: - if (obj is null) return false; - Dispatcher.UIThread.Post(() => - ViewModel?.TestServerAvailabilityResult((string)obj), - DispatcherPriority.Default); - break; - case EViewAction.DispatcherReload: Dispatcher.UIThread.Post(() => ViewModel?.ReloadResult(), DispatcherPriority.Default); break; - case EViewAction.DispatcherRefreshServersBiz: - Dispatcher.UIThread.Post(() => - ViewModel?.RefreshServersBiz(), - DispatcherPriority.Default); - break; - - case EViewAction.DispatcherRefreshIcon: - Dispatcher.UIThread.Post(() => - { - this.Icon = AvaUtils.GetAppIcon(_config.systemProxyItem.sysProxyType); - }, - DispatcherPriority.Default); - break; - case EViewAction.Shutdown: StorageUI(); if (Application.Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) @@ -251,12 +211,7 @@ namespace v2rayN.Desktop.Views break; case EViewAction.ScanScreenTask: - ScanScreenTaskAsync().ContinueWith(_ => { }); - break; - - case EViewAction.UpdateSysProxy: - if (obj is null) return false; - await SysProxyHandler.UpdateSysProxy(_config, (bool)obj); + await ScanScreenTaskAsync(); break; case EViewAction.AddServerViaClipboard: @@ -282,21 +237,21 @@ namespace v2rayN.Desktop.Views ShowHideWindow(null); break; - case EGlobalHotkey.SystemProxyClear: - ViewModel?.SetListenerType(ESysProxyType.ForcedClear); - break; + //case EGlobalHotkey.SystemProxyClear: + // ViewModel?.SetListenerType(ESysProxyType.ForcedClear); + // break; - case EGlobalHotkey.SystemProxySet: - ViewModel?.SetListenerType(ESysProxyType.ForcedChange); - break; + //case EGlobalHotkey.SystemProxySet: + // ViewModel?.SetListenerType(ESysProxyType.ForcedChange); + // break; - case EGlobalHotkey.SystemProxyUnchanged: - ViewModel?.SetListenerType(ESysProxyType.Unchanged); - break; + //case EGlobalHotkey.SystemProxyUnchanged: + // ViewModel?.SetListenerType(ESysProxyType.Unchanged); + // break; - case EGlobalHotkey.SystemProxyPac: - ViewModel?.SetListenerType(ESysProxyType.Pac); - break; + //case EGlobalHotkey.SystemProxyPac: + // ViewModel?.SetListenerType(ESysProxyType.Pac); + // break; } } @@ -342,11 +297,6 @@ namespace v2rayN.Desktop.Views Utils.ProcessStart($"{Utils.Base64Decode(Global.PromotionUrl)}?t={DateTime.Now.Ticks}"); } - private void TxtRunningServerDisplay_Tapped(object? sender, Avalonia.Input.TappedEventArgs e) - { - ViewModel?.TestServerAvailability(); - } - private void menuSettingsSetUWP_Click(object? sender, RoutedEventArgs e) { Utils.ProcessStart(Utils.GetBinPath("EnableLoopback.exe")); diff --git a/v2rayN/v2rayN.Desktop/Views/StatusBarView.axaml b/v2rayN/v2rayN.Desktop/Views/StatusBarView.axaml new file mode 100644 index 00000000..e5de9e7a --- /dev/null +++ b/v2rayN/v2rayN.Desktop/Views/StatusBarView.axaml @@ -0,0 +1,81 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v2rayN/v2rayN.Desktop/Views/StatusBarView.axaml.cs b/v2rayN/v2rayN.Desktop/Views/StatusBarView.axaml.cs new file mode 100644 index 00000000..2fc63d8e --- /dev/null +++ b/v2rayN/v2rayN.Desktop/Views/StatusBarView.axaml.cs @@ -0,0 +1,136 @@ +using Avalonia; +using Avalonia.Controls.ApplicationLifetimes; +using Avalonia.ReactiveUI; +using Avalonia.Threading; +using ReactiveUI; +using Splat; +using System.Reactive.Disposables; +using v2rayN.Desktop.Common; +using v2rayN.Desktop.Handler; + +namespace v2rayN.Desktop.Views +{ + public partial class StatusBarView : ReactiveUserControl + { + private static Config _config; + + public StatusBarView() + { + InitializeComponent(); + + _config = AppHandler.Instance.Config; + //ViewModel = new StatusBarViewModel(UpdateViewHandler); + //Locator.CurrentMutable.RegisterLazySingleton(() => ViewModel, typeof(StatusBarViewModel)); + ViewModel = Locator.Current.GetService(); + ViewModel?.Init(UpdateViewHandler); + + txtRunningServerDisplay.Tapped += TxtRunningServerDisplay_Tapped; + txtRunningInfoDisplay.Tapped += TxtRunningServerDisplay_Tapped; + + this.WhenActivated(disposables => + { + //status bar + this.OneWayBind(ViewModel, vm => vm.InboundDisplay, v => v.txtInboundDisplay.Text).DisposeWith(disposables); + this.OneWayBind(ViewModel, vm => vm.InboundLanDisplay, v => v.txtInboundLanDisplay.Text).DisposeWith(disposables); + this.OneWayBind(ViewModel, vm => vm.RunningServerDisplay, v => v.txtRunningServerDisplay.Text).DisposeWith(disposables); + this.OneWayBind(ViewModel, vm => vm.RunningInfoDisplay, v => v.txtRunningInfoDisplay.Text).DisposeWith(disposables); + this.OneWayBind(ViewModel, vm => vm.SpeedProxyDisplay, v => v.txtSpeedProxyDisplay.Text).DisposeWith(disposables); + this.OneWayBind(ViewModel, vm => vm.SpeedDirectDisplay, v => v.txtSpeedDirectDisplay.Text).DisposeWith(disposables); + this.Bind(ViewModel, vm => vm.EnableTun, v => v.togEnableTun.IsChecked).DisposeWith(disposables); + + this.Bind(ViewModel, vm => vm.SystemProxySelected, v => v.cmbSystemProxy.SelectedIndex).DisposeWith(disposables); + //this.OneWayBind(ViewModel, vm => vm.RoutingItems, v => v.cmbRoutings2.ItemsSource).DisposeWith(disposables); + this.Bind(ViewModel, vm => vm.SelectedRouting, v => v.cmbRoutings2.SelectedItem).DisposeWith(disposables); + + ////system proxy + //this.OneWayBind(ViewModel, vm => vm.BlSystemProxyClear, v => v.menuSystemProxyClear2.Visibility, conversionHint: BooleanToVisibilityHint.UseHidden, vmToViewConverterOverride: new BooleanToVisibilityTypeConverter()).DisposeWith(disposables); + //this.OneWayBind(ViewModel, vm => vm.BlSystemProxySet, v => v.menuSystemProxySet2.Visibility, conversionHint: BooleanToVisibilityHint.UseHidden, vmToViewConverterOverride: new BooleanToVisibilityTypeConverter()).DisposeWith(disposables); + //this.OneWayBind(ViewModel, vm => vm.BlSystemProxyNothing, v => v.menuSystemProxyNothing2.Visibility, conversionHint: BooleanToVisibilityHint.UseHidden, vmToViewConverterOverride: new BooleanToVisibilityTypeConverter()).DisposeWith(disposables); + //this.OneWayBind(ViewModel, vm => vm.BlSystemProxyPac, v => v.menuSystemProxyPac2.Visibility, conversionHint: BooleanToVisibilityHint.UseHidden, vmToViewConverterOverride: new BooleanToVisibilityTypeConverter()).DisposeWith(disposables); + //this.BindCommand(ViewModel, vm => vm.SystemProxyClearCmd, v => v.menuSystemProxyClear).DisposeWith(disposables); + //this.BindCommand(ViewModel, vm => vm.SystemProxySetCmd, v => v.menuSystemProxySet).DisposeWith(disposables); + //this.BindCommand(ViewModel, vm => vm.SystemProxyPacCmd, v => v.menuSystemProxyPac).DisposeWith(disposables); + //this.BindCommand(ViewModel, vm => vm.SystemProxyNothingCmd, v => v.menuSystemProxyNothing).DisposeWith(disposables); + + ////routings and servers + //this.OneWayBind(ViewModel, vm => vm.RoutingItems, v => v.cmbRoutings.ItemsSource).DisposeWith(disposables); + //this.Bind(ViewModel, vm => vm.SelectedRouting, v => v.cmbRoutings.SelectedItem).DisposeWith(disposables); + //this.OneWayBind(ViewModel, vm => vm.BlRouting, v => v.menuRoutings.Visibility).DisposeWith(disposables); + //this.OneWayBind(ViewModel, vm => vm.BlRouting, v => v.sepRoutings.Visibility).DisposeWith(disposables); + + //this.OneWayBind(ViewModel, vm => vm.Servers, v => v.cmbServers.ItemsSource).DisposeWith(disposables); + //this.Bind(ViewModel, vm => vm.SelectedServer, v => v.cmbServers.SelectedItem).DisposeWith(disposables); + //this.OneWayBind(ViewModel, vm => vm.BlServers, v => v.cmbServers.Visibility).DisposeWith(disposables); + + ////tray menu + //this.BindCommand(ViewModel, vm => vm.AddServerViaClipboardCmd, v => v.menuAddServerViaClipboard2).DisposeWith(disposables); + //this.BindCommand(ViewModel, vm => vm.AddServerViaScanCmd, v => v.menuAddServerViaScan2).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.OneWayBind(ViewModel, vm => vm.RunningServerToolTipText, v => v.tbNotify.ToolTipText).DisposeWith(disposables); + //this.OneWayBind(ViewModel, vm => vm.NotifyLeftClickCmd, v => v.tbNotify.LeftClickCommand).DisposeWith(disposables); + + ////status bar + //this.OneWayBind(ViewModel, vm => vm.InboundDisplay, v => v.txtInboundDisplay.Text).DisposeWith(disposables); + //this.OneWayBind(ViewModel, vm => vm.InboundLanDisplay, v => v.txtInboundLanDisplay.Text).DisposeWith(disposables); + //this.OneWayBind(ViewModel, vm => vm.RunningServerDisplay, v => v.txtRunningServerDisplay.Text).DisposeWith(disposables); + //this.OneWayBind(ViewModel, vm => vm.RunningInfoDisplay, v => v.txtRunningInfoDisplay.Text).DisposeWith(disposables); + //this.OneWayBind(ViewModel, vm => vm.SpeedProxyDisplay, v => v.txtSpeedProxyDisplay.Text).DisposeWith(disposables); + //this.OneWayBind(ViewModel, vm => vm.SpeedDirectDisplay, v => v.txtSpeedDirectDisplay.Text).DisposeWith(disposables); + //this.Bind(ViewModel, vm => vm.EnableTun, v => v.togEnableTun.IsChecked).DisposeWith(disposables); + + //this.Bind(ViewModel, vm => vm.SystemProxySelected, v => v.cmbSystemProxy.SelectedIndex).DisposeWith(disposables); + //this.OneWayBind(ViewModel, vm => vm.RoutingItems, v => v.cmbRoutings2.ItemsSource).DisposeWith(disposables); + //this.Bind(ViewModel, vm => vm.SelectedRouting, v => v.cmbRoutings2.SelectedItem).DisposeWith(disposables); + //this.OneWayBind(ViewModel, vm => vm.BlRouting, v => v.cmbRoutings2.Visibility).DisposeWith(disposables); + }); + } + + private async Task UpdateViewHandler(EViewAction action, object? obj) + { + switch (action) + { + case EViewAction.UpdateSysProxy: + if (obj is null) return false; + await SysProxyHandler.UpdateSysProxy(_config, (bool)obj); + break; + + case EViewAction.DispatcherServerAvailability: + if (obj is null) return false; + Dispatcher.UIThread.Post(() => + ViewModel?.TestServerAvailabilityResult((string)obj), + DispatcherPriority.Default); + break; + + case EViewAction.DispatcherRefreshServersBiz: + Dispatcher.UIThread.Post(() => + ViewModel?.RefreshServersBiz(), + DispatcherPriority.Default); + break; + + case EViewAction.DispatcherRefreshIcon: + Dispatcher.UIThread.Post(() => + { + RefreshIcon(); + }, + DispatcherPriority.Default); + break; + } + return await Task.FromResult(true); + } + + private void RefreshIcon() + { + if (Application.Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) + { + desktop.MainWindow.Icon = AvaUtils.GetAppIcon(_config.systemProxyItem.sysProxyType); + } + } + + private void TxtRunningServerDisplay_Tapped(object? sender, Avalonia.Input.TappedEventArgs e) + { + ViewModel?.TestServerAvailability(); + } + } +} \ No newline at end of file diff --git a/v2rayN/v2rayN/Views/MainWindow.xaml b/v2rayN/v2rayN/Views/MainWindow.xaml index 9ed581b0..1fff8ded 100644 --- a/v2rayN/v2rayN/Views/MainWindow.xaml +++ b/v2rayN/v2rayN/Views/MainWindow.xaml @@ -8,7 +8,7 @@ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:reactiveui="http://reactiveui.net" xmlns:resx="clr-namespace:ServiceLib.Resx;assembly=ServiceLib" - xmlns:tb="clr-namespace:H.NotifyIcon;assembly=H.NotifyIcon.Wpf" + xmlns:view="clr-namespace:v2rayN.Views" xmlns:vms="clr-namespace:ServiceLib.ViewModels;assembly=ServiceLib" Title="v2rayN" Width="900" @@ -276,84 +276,7 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + @@ -505,113 +428,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/v2rayN/v2rayN/Views/MainWindow.xaml.cs b/v2rayN/v2rayN/Views/MainWindow.xaml.cs index 40936791..c9be54e9 100644 --- a/v2rayN/v2rayN/Views/MainWindow.xaml.cs +++ b/v2rayN/v2rayN/Views/MainWindow.xaml.cs @@ -26,19 +26,18 @@ namespace v2rayN.Views _config = AppHandler.Instance.Config; ThreadPool.RegisterWaitForSingleObject(App.ProgramStarted, OnProgramStarted, null, -1, false); + Application.Current.Exit += Current_Exit; App.Current.SessionEnding += Current_SessionEnding; this.Closing += MainWindow_Closing; this.PreviewKeyDown += MainWindow_PreviewKeyDown; menuSettingsSetUWP.Click += menuSettingsSetUWP_Click; menuPromotion.Click += menuPromotion_Click; menuClose.Click += menuClose_Click; - menuExit.Click += menuExit_Click; menuCheckUpdate.Click += MenuCheckUpdate_Click; menuBackupAndRestore.Click += MenuBackupAndRestore_Click; - var IsAdministrator = Utils.IsAdministrator(); MessageBus.Current.Listen(EMsgCommand.SendSnackMsg.ToString()).Subscribe(x => DelegateSnackMsg(x)); - ViewModel = new MainWindowViewModel(IsAdministrator, UpdateViewHandler); + ViewModel = new MainWindowViewModel(UpdateViewHandler); Locator.CurrentMutable.RegisterLazySingleton(() => ViewModel, typeof(MainWindowViewModel)); WindowsHandler.Instance.RegisterGlobalHotkey(_config, OnHotkeyHandler, null); @@ -100,49 +99,6 @@ namespace v2rayN.Views this.BindCommand(ViewModel, vm => vm.ReloadCmd, v => v.menuReload).DisposeWith(disposables); this.OneWayBind(ViewModel, vm => vm.BlReloadEnabled, v => v.menuReload.IsEnabled).DisposeWith(disposables); - //system proxy - this.OneWayBind(ViewModel, vm => vm.BlSystemProxyClear, v => v.menuSystemProxyClear2.Visibility, conversionHint: BooleanToVisibilityHint.UseHidden, vmToViewConverterOverride: new BooleanToVisibilityTypeConverter()).DisposeWith(disposables); - this.OneWayBind(ViewModel, vm => vm.BlSystemProxySet, v => v.menuSystemProxySet2.Visibility, conversionHint: BooleanToVisibilityHint.UseHidden, vmToViewConverterOverride: new BooleanToVisibilityTypeConverter()).DisposeWith(disposables); - this.OneWayBind(ViewModel, vm => vm.BlSystemProxyNothing, v => v.menuSystemProxyNothing2.Visibility, conversionHint: BooleanToVisibilityHint.UseHidden, vmToViewConverterOverride: new BooleanToVisibilityTypeConverter()).DisposeWith(disposables); - this.OneWayBind(ViewModel, vm => vm.BlSystemProxyPac, v => v.menuSystemProxyPac2.Visibility, conversionHint: BooleanToVisibilityHint.UseHidden, vmToViewConverterOverride: new BooleanToVisibilityTypeConverter()).DisposeWith(disposables); - this.BindCommand(ViewModel, vm => vm.SystemProxyClearCmd, v => v.menuSystemProxyClear).DisposeWith(disposables); - this.BindCommand(ViewModel, vm => vm.SystemProxySetCmd, v => v.menuSystemProxySet).DisposeWith(disposables); - this.BindCommand(ViewModel, vm => vm.SystemProxyPacCmd, v => v.menuSystemProxyPac).DisposeWith(disposables); - this.BindCommand(ViewModel, vm => vm.SystemProxyNothingCmd, v => v.menuSystemProxyNothing).DisposeWith(disposables); - - //routings and servers - this.OneWayBind(ViewModel, vm => vm.RoutingItems, v => v.cmbRoutings.ItemsSource).DisposeWith(disposables); - this.Bind(ViewModel, vm => vm.SelectedRouting, v => v.cmbRoutings.SelectedItem).DisposeWith(disposables); - this.OneWayBind(ViewModel, vm => vm.BlRouting, v => v.menuRoutings.Visibility).DisposeWith(disposables); - this.OneWayBind(ViewModel, vm => vm.BlRouting, v => v.sepRoutings.Visibility).DisposeWith(disposables); - - this.OneWayBind(ViewModel, vm => vm.Servers, v => v.cmbServers.ItemsSource).DisposeWith(disposables); - this.Bind(ViewModel, vm => vm.SelectedServer, v => v.cmbServers.SelectedItem).DisposeWith(disposables); - this.OneWayBind(ViewModel, vm => vm.BlServers, v => v.cmbServers.Visibility).DisposeWith(disposables); - - //tray menu - this.BindCommand(ViewModel, vm => vm.AddServerViaClipboardCmd, v => v.menuAddServerViaClipboard2).DisposeWith(disposables); - this.BindCommand(ViewModel, vm => vm.AddServerViaScanCmd, v => v.menuAddServerViaScan2).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.OneWayBind(ViewModel, vm => vm.RunningServerToolTipText, v => v.tbNotify.ToolTipText).DisposeWith(disposables); - this.OneWayBind(ViewModel, vm => vm.NotifyLeftClickCmd, v => v.tbNotify.LeftClickCommand).DisposeWith(disposables); - - //status bar - this.OneWayBind(ViewModel, vm => vm.InboundDisplay, v => v.txtInboundDisplay.Text).DisposeWith(disposables); - this.OneWayBind(ViewModel, vm => vm.InboundLanDisplay, v => v.txtInboundLanDisplay.Text).DisposeWith(disposables); - this.OneWayBind(ViewModel, vm => vm.RunningServerDisplay, v => v.txtRunningServerDisplay.Text).DisposeWith(disposables); - this.OneWayBind(ViewModel, vm => vm.RunningInfoDisplay, v => v.txtRunningInfoDisplay.Text).DisposeWith(disposables); - this.OneWayBind(ViewModel, vm => vm.SpeedProxyDisplay, v => v.txtSpeedProxyDisplay.Text).DisposeWith(disposables); - this.OneWayBind(ViewModel, vm => vm.SpeedDirectDisplay, v => v.txtSpeedDirectDisplay.Text).DisposeWith(disposables); - this.Bind(ViewModel, vm => vm.EnableTun, v => v.togEnableTun.IsChecked).DisposeWith(disposables); - - this.Bind(ViewModel, vm => vm.SystemProxySelected, v => v.cmbSystemProxy.SelectedIndex).DisposeWith(disposables); - this.OneWayBind(ViewModel, vm => vm.RoutingItems, v => v.cmbRoutings2.ItemsSource).DisposeWith(disposables); - this.Bind(ViewModel, vm => vm.SelectedRouting, v => v.cmbRoutings2.SelectedItem).DisposeWith(disposables); - this.OneWayBind(ViewModel, vm => vm.BlRouting, v => v.cmbRoutings2.Visibility).DisposeWith(disposables); - if (_config.uiItem.mainGirdOrientation == EGirdOrientation.Horizontal) { gridMain.Visibility = Visibility.Visible; @@ -166,7 +122,7 @@ namespace v2rayN.Views } }); - this.Title = $"{Utils.GetVersion()} - {(IsAdministrator ? ResUI.RunAsAdmin : ResUI.NotRunAsAdmin)}"; + this.Title = $"{Utils.GetVersion()} - {(Utils.IsAdministrator() ? ResUI.RunAsAdmin : ResUI.NotRunAsAdmin)}"; if (!_config.guiItem.enableHWA) { @@ -237,14 +193,6 @@ namespace v2rayN.Views }), 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((() => { @@ -252,21 +200,6 @@ namespace v2rayN.Views }), DispatcherPriority.Normal); break; - case EViewAction.DispatcherRefreshServersBiz: - Application.Current?.Dispatcher.Invoke((() => - { - ViewModel?.RefreshServersBiz(); - }), DispatcherPriority.Normal); - break; - - case EViewAction.DispatcherRefreshIcon: - Application.Current?.Dispatcher.Invoke((() => - { - tbNotify.Icon = WindowsHandler.Instance.GetNotifyIcon(_config); - this.Icon = WindowsHandler.Instance.GetAppIcon(_config); - }), DispatcherPriority.Normal); - break; - case EViewAction.Shutdown: Application.Current?.Dispatcher.Invoke((() => { @@ -275,12 +208,7 @@ namespace v2rayN.Views break; case EViewAction.ScanScreenTask: - ScanScreenTaskAsync().ContinueWith(_ => { }); - break; - - case EViewAction.UpdateSysProxy: - if (obj is null) return false; - SysProxyHandler.UpdateSysProxy(_config, (bool)obj); + await ScanScreenTaskAsync(); break; case EViewAction.AddServerViaClipboard: @@ -308,19 +236,10 @@ namespace v2rayN.Views 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); + Locator.Current.GetService()?.SetListenerType((ESysProxyType)((int)e - 1)); break; } } @@ -331,13 +250,9 @@ namespace v2rayN.Views ShowHideWindow(false); } - private void menuExit_Click(object sender, RoutedEventArgs e) + private void Current_Exit(object sender, ExitEventArgs e) { - tabProfiles = null; - - tbNotify.Dispose(); StorageUI(); - ViewModel?.MyAppExitAsync(false); } private void Current_SessionEnding(object sender, SessionEndingCancelEventArgs e) @@ -383,17 +298,12 @@ namespace v2rayN.Views Utils.ProcessStart($"{Utils.Base64Decode(Global.PromotionUrl)}?t={DateTime.Now.Ticks}"); } - private void txtRunningInfoDisplay_MouseDoubleClick(object sender, MouseButtonEventArgs e) - { - ViewModel?.TestServerAvailability(); - } - private void menuSettingsSetUWP_Click(object sender, RoutedEventArgs e) { Utils.ProcessStart(Utils.GetBinPath("EnableLoopback.exe")); } - public async Task ScanScreenTaskAsync() + private async Task ScanScreenTaskAsync() { ShowHideWindow(false); @@ -405,7 +315,7 @@ namespace v2rayN.Views ShowHideWindow(true); - ViewModel?.ScanScreenTaskAsync(result); + ViewModel?.ScanScreenResult(result); } private void MenuCheckUpdate_Click(object sender, RoutedEventArgs e) diff --git a/v2rayN/v2rayN/Views/StatusBarView.xaml b/v2rayN/v2rayN/Views/StatusBarView.xaml new file mode 100644 index 00000000..71d7090f --- /dev/null +++ b/v2rayN/v2rayN/Views/StatusBarView.xaml @@ -0,0 +1,198 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/v2rayN/v2rayN/Views/StatusBarView.xaml.cs b/v2rayN/v2rayN/Views/StatusBarView.xaml.cs new file mode 100644 index 00000000..7d7cf1e2 --- /dev/null +++ b/v2rayN/v2rayN/Views/StatusBarView.xaml.cs @@ -0,0 +1,124 @@ +using ReactiveUI; +using Splat; +using System.Reactive.Disposables; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Controls.Primitives; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Threading; +using v2rayN.Base; +using v2rayN.Handler; + +namespace v2rayN.Views +{ + public partial class StatusBarView + { + private static Config _config; + + public StatusBarView() + { + InitializeComponent(); + _config = AppHandler.Instance.Config; + ViewModel = new StatusBarViewModel(UpdateViewHandler); + Locator.CurrentMutable.RegisterLazySingleton(() => ViewModel, typeof(StatusBarViewModel)); + + menuExit.Click += menuExit_Click; + txtRunningServerDisplay.PreviewMouseDown += txtRunningInfoDisplay_MouseDoubleClick; + txtRunningInfoDisplay.PreviewMouseDown += txtRunningInfoDisplay_MouseDoubleClick; + + this.WhenActivated(disposables => + { + //system proxy + this.OneWayBind(ViewModel, vm => vm.BlSystemProxyClear, v => v.menuSystemProxyClear2.Visibility, conversionHint: BooleanToVisibilityHint.UseHidden, vmToViewConverterOverride: new BooleanToVisibilityTypeConverter()).DisposeWith(disposables); + this.OneWayBind(ViewModel, vm => vm.BlSystemProxySet, v => v.menuSystemProxySet2.Visibility, conversionHint: BooleanToVisibilityHint.UseHidden, vmToViewConverterOverride: new BooleanToVisibilityTypeConverter()).DisposeWith(disposables); + this.OneWayBind(ViewModel, vm => vm.BlSystemProxyNothing, v => v.menuSystemProxyNothing2.Visibility, conversionHint: BooleanToVisibilityHint.UseHidden, vmToViewConverterOverride: new BooleanToVisibilityTypeConverter()).DisposeWith(disposables); + this.OneWayBind(ViewModel, vm => vm.BlSystemProxyPac, v => v.menuSystemProxyPac2.Visibility, conversionHint: BooleanToVisibilityHint.UseHidden, vmToViewConverterOverride: new BooleanToVisibilityTypeConverter()).DisposeWith(disposables); + this.BindCommand(ViewModel, vm => vm.SystemProxyClearCmd, v => v.menuSystemProxyClear).DisposeWith(disposables); + this.BindCommand(ViewModel, vm => vm.SystemProxySetCmd, v => v.menuSystemProxySet).DisposeWith(disposables); + this.BindCommand(ViewModel, vm => vm.SystemProxyPacCmd, v => v.menuSystemProxyPac).DisposeWith(disposables); + this.BindCommand(ViewModel, vm => vm.SystemProxyNothingCmd, v => v.menuSystemProxyNothing).DisposeWith(disposables); + + //routings and servers + this.OneWayBind(ViewModel, vm => vm.RoutingItems, v => v.cmbRoutings.ItemsSource).DisposeWith(disposables); + this.Bind(ViewModel, vm => vm.SelectedRouting, v => v.cmbRoutings.SelectedItem).DisposeWith(disposables); + this.OneWayBind(ViewModel, vm => vm.BlRouting, v => v.menuRoutings.Visibility).DisposeWith(disposables); + this.OneWayBind(ViewModel, vm => vm.BlRouting, v => v.sepRoutings.Visibility).DisposeWith(disposables); + + this.OneWayBind(ViewModel, vm => vm.Servers, v => v.cmbServers.ItemsSource).DisposeWith(disposables); + this.Bind(ViewModel, vm => vm.SelectedServer, v => v.cmbServers.SelectedItem).DisposeWith(disposables); + this.OneWayBind(ViewModel, vm => vm.BlServers, v => v.cmbServers.Visibility).DisposeWith(disposables); + + //tray menu + this.BindCommand(ViewModel, vm => vm.AddServerViaClipboardCmd, v => v.menuAddServerViaClipboard2).DisposeWith(disposables); + this.BindCommand(ViewModel, vm => vm.AddServerViaScanCmd, v => v.menuAddServerViaScan2).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.OneWayBind(ViewModel, vm => vm.RunningServerToolTipText, v => v.tbNotify.ToolTipText).DisposeWith(disposables); + this.OneWayBind(ViewModel, vm => vm.NotifyLeftClickCmd, v => v.tbNotify.LeftClickCommand).DisposeWith(disposables); + + //status bar + this.OneWayBind(ViewModel, vm => vm.InboundDisplay, v => v.txtInboundDisplay.Text).DisposeWith(disposables); + this.OneWayBind(ViewModel, vm => vm.InboundLanDisplay, v => v.txtInboundLanDisplay.Text).DisposeWith(disposables); + this.OneWayBind(ViewModel, vm => vm.RunningServerDisplay, v => v.txtRunningServerDisplay.Text).DisposeWith(disposables); + this.OneWayBind(ViewModel, vm => vm.RunningInfoDisplay, v => v.txtRunningInfoDisplay.Text).DisposeWith(disposables); + this.OneWayBind(ViewModel, vm => vm.SpeedProxyDisplay, v => v.txtSpeedProxyDisplay.Text).DisposeWith(disposables); + this.OneWayBind(ViewModel, vm => vm.SpeedDirectDisplay, v => v.txtSpeedDirectDisplay.Text).DisposeWith(disposables); + this.Bind(ViewModel, vm => vm.EnableTun, v => v.togEnableTun.IsChecked).DisposeWith(disposables); + + this.Bind(ViewModel, vm => vm.SystemProxySelected, v => v.cmbSystemProxy.SelectedIndex).DisposeWith(disposables); + this.OneWayBind(ViewModel, vm => vm.RoutingItems, v => v.cmbRoutings2.ItemsSource).DisposeWith(disposables); + this.Bind(ViewModel, vm => vm.SelectedRouting, v => v.cmbRoutings2.SelectedItem).DisposeWith(disposables); + this.OneWayBind(ViewModel, vm => vm.BlRouting, v => v.cmbRoutings2.Visibility).DisposeWith(disposables); + }); + } + + private async Task UpdateViewHandler(EViewAction action, object? obj) + { + switch (action) + { + case EViewAction.DispatcherServerAvailability: + if (obj is null) return false; + Application.Current?.Dispatcher.Invoke((() => + { + ViewModel?.TestServerAvailabilityResult((string)obj); + }), DispatcherPriority.Normal); + break; + + case EViewAction.DispatcherRefreshServersBiz: + Application.Current?.Dispatcher.Invoke((() => + { + ViewModel?.RefreshServersBiz(); + }), DispatcherPriority.Normal); + break; + + case EViewAction.DispatcherRefreshIcon: + Application.Current?.Dispatcher.Invoke((() => + { + tbNotify.Icon = WindowsHandler.Instance.GetNotifyIcon(_config); + Application.Current.MainWindow.Icon = WindowsHandler.Instance.GetAppIcon(_config); + }), DispatcherPriority.Normal); + break; + + case EViewAction.UpdateSysProxy: + if (obj is null) return false; + SysProxyHandler.UpdateSysProxy(_config, (bool)obj); + break; + } + return await Task.FromResult(true); + } + + private void menuExit_Click(object sender, RoutedEventArgs e) + { + tbNotify.Dispose(); + var service = Locator.Current.GetService(); + if (service != null) service.MyAppExitAsync(false); + } + + private void txtRunningInfoDisplay_MouseDoubleClick(object sender, MouseButtonEventArgs e) + { + ViewModel?.TestServerAvailability(); + } + } +} \ No newline at end of file