Refactor code to decouple view and viewmodel

pull/5550/head
2dust 2024-08-11 15:45:55 +08:00
parent 3dd75b17cf
commit 9e9808e489
13 changed files with 360 additions and 285 deletions

View File

@ -9,6 +9,7 @@
ProfilesFocus, ProfilesFocus,
ShareSub, ShareSub,
ShareServer, ShareServer,
ShowHideWindow,
SubEditWindow, SubEditWindow,
RoutingRuleSettingWindow, RoutingRuleSettingWindow,
RoutingRuleDetailsWindow, RoutingRuleDetailsWindow,
@ -19,5 +20,14 @@
OptionSettingWindow, OptionSettingWindow,
GlobalHotkeySettingWindow, GlobalHotkeySettingWindow,
SubSettingWindow, SubSettingWindow,
DispatcherSpeedTest,
DispatcherRefreshConnections,
DispatcherRefreshProxyGroups,
DispatcherProxiesDelayTest,
DispatcherStatistics,
DispatcherServerAvailability,
DispatcherReload,
DispatcherRefreshServersBiz,
} }
} }

View File

@ -72,7 +72,7 @@ namespace v2rayN.Handler
bool isSuccess = false; bool isSuccess = false;
string msg; string msg;
Application.Current.Dispatcher.Invoke(() => Application.Current?.Dispatcher.Invoke(() =>
{ {
isSuccess = RegisterHotKey(IntPtr.Zero, _hotkeyCode, hotkeyInfo.fsModifiers, hotkeyInfo.vKey); isSuccess = RegisterHotKey(IntPtr.Zero, _hotkeyCode, hotkeyInfo.fsModifiers, hotkeyInfo.vKey);
}); });
@ -96,7 +96,7 @@ namespace v2rayN.Handler
{ {
foreach (var hotkey in _hotkeyTriggerDic.Keys) foreach (var hotkey in _hotkeyTriggerDic.Keys)
{ {
Application.Current.Dispatcher.Invoke(() => Application.Current?.Dispatcher.Invoke(() =>
{ {
UnregisterHotKey(IntPtr.Zero, hotkey); UnregisterHotKey(IntPtr.Zero, hotkey);
}); });
@ -137,7 +137,7 @@ namespace v2rayN.Handler
var _hotKeyCode = (int)msg.lParam; var _hotKeyCode = (int)msg.lParam;
if (IsPause) if (IsPause)
{ {
Application.Current.Dispatcher.Invoke(() => Application.Current?.Dispatcher.Invoke(() =>
{ {
UIElement? element = Keyboard.FocusedElement as UIElement; UIElement? element = Keyboard.FocusedElement as UIElement;
if (element != null) if (element != null)

View File

@ -14,14 +14,14 @@ namespace v2rayN.Handler
private CoreHandler _coreHandler; private CoreHandler _coreHandler;
private List<ServerTestItem> _selecteds; private List<ServerTestItem> _selecteds;
private ESpeedActionType _actionType; private ESpeedActionType _actionType;
private Action<string, string, string> _updateFunc; private Action<SpeedTestResult> _updateFunc;
public SpeedtestHandler(Config config) public SpeedtestHandler(Config config)
{ {
_config = config; _config = config;
} }
public SpeedtestHandler(Config config, CoreHandler coreHandler, List<ProfileItem> selecteds, ESpeedActionType actionType, Action<string, string, string> update) public SpeedtestHandler(Config config, CoreHandler coreHandler, List<ProfileItem> selecteds, ESpeedActionType actionType, Action<SpeedTestResult> update)
{ {
_config = config; _config = config;
_coreHandler = coreHandler; _coreHandler = coreHandler;
@ -408,7 +408,7 @@ namespace v2rayN.Handler
private void UpdateFunc(string indexId, string delay, string speed = "") private void UpdateFunc(string indexId, string delay, string speed = "")
{ {
_updateFunc(indexId, delay, speed); _updateFunc(new() { IndexId = indexId, Delay = delay, Speed = speed });
} }
} }
} }

View File

@ -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; }
}
}

View File

@ -4,7 +4,6 @@ using ReactiveUI;
using ReactiveUI.Fody.Helpers; using ReactiveUI.Fody.Helpers;
using System.Reactive; using System.Reactive;
using System.Reactive.Linq; using System.Reactive.Linq;
using System.Windows;
using v2rayN.Base; using v2rayN.Base;
using v2rayN.Enums; using v2rayN.Enums;
using v2rayN.Handler; using v2rayN.Handler;
@ -30,9 +29,10 @@ namespace v2rayN.ViewModels
[Reactive] [Reactive]
public bool AutoRefresh { get; set; } public bool AutoRefresh { get; set; }
public ClashConnectionsViewModel() public ClashConnectionsViewModel(Func<EViewAction, object?, bool>? updateView)
{ {
_config = LazyConfig.Instance.GetConfig(); _config = LazyConfig.Instance.GetConfig();
_updateView = updateView;
SortingSelected = _config.clashUIItem.connectionsSorting; SortingSelected = _config.clashUIItem.connectionsSorting;
AutoRefresh = _config.clashUIItem.connectionsAutoRefresh; AutoRefresh = _config.clashUIItem.connectionsAutoRefresh;
@ -110,14 +110,11 @@ namespace v2rayN.ViewModels
return; return;
} }
Application.Current?.Dispatcher.Invoke((Action)(() => _updateView?.Invoke(EViewAction.DispatcherRefreshConnections, it?.connections);
{
RefreshConnections(it?.connections);
}));
}); });
} }
private void RefreshConnections(List<ConnectionItem>? connections) public void RefreshConnections(List<ConnectionItem>? connections)
{ {
_connectionItems.Clear(); _connectionItems.Clear();

View File

@ -5,7 +5,6 @@ using ReactiveUI.Fody.Helpers;
using Splat; using Splat;
using System.Reactive; using System.Reactive;
using System.Reactive.Linq; using System.Reactive.Linq;
using System.Windows;
using v2rayN.Base; using v2rayN.Base;
using v2rayN.Enums; using v2rayN.Enums;
using v2rayN.Handler; using v2rayN.Handler;
@ -48,10 +47,11 @@ namespace v2rayN.ViewModels
[Reactive] [Reactive]
public bool AutoRefresh { get; set; } public bool AutoRefresh { get; set; }
public ClashProxiesViewModel() public ClashProxiesViewModel(Func<EViewAction, object?, bool>? updateView)
{ {
_noticeHandler = Locator.Current.GetService<NoticeHandler>(); _noticeHandler = Locator.Current.GetService<NoticeHandler>();
_config = LazyConfig.Instance.GetConfig(); _config = LazyConfig.Instance.GetConfig();
_updateView = updateView;
SelectedGroup = new(); SelectedGroup = new();
SelectedDetail = new(); SelectedDetail = new();
@ -149,20 +149,6 @@ namespace v2rayN.ViewModels
ProxiesDelayTest(); ProxiesDelayTest();
} }
public void ProxiesClear()
{
proxies = null;
providers = null;
ClashApiHandler.Instance.SetProxies(proxies);
Application.Current?.Dispatcher.Invoke((Action)(() =>
{
_proxyGroups.Clear();
_proxyDetails.Clear();
}));
}
public void ProxiesDelayTest() public void ProxiesDelayTest()
{ {
ProxiesDelayTest(true); ProxiesDelayTest(true);
@ -197,15 +183,12 @@ namespace v2rayN.ViewModels
} }
if (refreshUI) if (refreshUI)
{ {
Application.Current?.Dispatcher.Invoke((Action)(() => _updateView?.Invoke(EViewAction.DispatcherRefreshProxyGroups, null);
{
RefreshProxyGroups();
}));
} }
}); });
} }
private void RefreshProxyGroups() public void RefreshProxyGroups()
{ {
var selectedName = SelectedGroup?.name; var selectedName = SelectedGroup?.name;
_proxyGroups.Clear(); _proxyGroups.Clear();
@ -425,34 +408,37 @@ namespace v2rayN.ViewModels
{ {
return; return;
} }
Application.Current?.Dispatcher.Invoke((Action)(() =>
{ _updateView?.Invoke(EViewAction.DispatcherProxiesDelayTest, new SpeedTestResult() { IndexId = item.name, Delay = result });
//UpdateHandler(false, $"{item.name}={result}");
var detail = _proxyDetails.Where(it => it.name == item.name).FirstOrDefault();
if (detail != null)
{
var dicResult = JsonUtils.Deserialize<Dictionary<string, object>>(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));
}
}));
}); });
} }
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<Dictionary<string, object>>(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 #endregion proxy function
#region task #region task

View File

@ -25,8 +25,6 @@ namespace v2rayN.ViewModels
private CoreHandler _coreHandler; private CoreHandler _coreHandler;
private bool _showInTaskbar;
#endregion private prop #endregion private prop
#region ObservableCollection #region ObservableCollection
@ -175,7 +173,7 @@ namespace v2rayN.ViewModels
_updateView = updateView; _updateView = updateView;
ThreadPool.RegisterWaitForSingleObject(App.ProgramStarted, OnProgramStarted, null, -1, false); ThreadPool.RegisterWaitForSingleObject(App.ProgramStarted, OnProgramStarted, null, -1, false);
MessageBus.Current.Listen<string>(Global.CommandRefreshProfiles).Subscribe(x => RefreshServersBiz()); MessageBus.Current.Listen<string>(Global.CommandRefreshProfiles).Subscribe(x => _updateView?.Invoke(EViewAction.DispatcherRefreshServersBiz, null));
SelectedRouting = new(); SelectedRouting = new();
SelectedServer = new(); SelectedServer = new();
@ -352,7 +350,7 @@ namespace v2rayN.ViewModels
NotifyLeftClickCmd = ReactiveCommand.Create(() => NotifyLeftClickCmd = ReactiveCommand.Create(() =>
{ {
ShowHideWindow(null); _updateView?.Invoke(EViewAction.ShowHideWindow, null);
}); });
//System proxy //System proxy
@ -377,8 +375,7 @@ namespace v2rayN.ViewModels
AutoHideStartup(); AutoHideStartup();
_showInTaskbar = true; _config.uiItem.showInTaskbar = true;
_config.uiItem.showInTaskbar = _showInTaskbar;
} }
private void Init() private void Init()
@ -405,10 +402,7 @@ namespace v2rayN.ViewModels
private void OnProgramStarted(object state, bool timeout) private void OnProgramStarted(object state, bool timeout)
{ {
Application.Current?.Dispatcher.Invoke((Action)(() => _updateView?.Invoke(EViewAction.ShowHideWindow, true);
{
ShowHideWindow(true);
}));
} }
#endregion Init #endregion Init
@ -417,7 +411,7 @@ namespace v2rayN.ViewModels
private void UpdateHandler(bool notify, string msg) private void UpdateHandler(bool notify, string msg)
{ {
if (!_showInTaskbar) if (!_config.uiItem.showInTaskbar)
{ {
return; return;
} }
@ -443,24 +437,25 @@ namespace v2rayN.ViewModels
} }
private void UpdateStatisticsHandler(ServerSpeedItem update) private void UpdateStatisticsHandler(ServerSpeedItem update)
{
if (!_config.uiItem.showInTaskbar)
{
return;
}
_updateView?.Invoke(EViewAction.DispatcherStatistics, update);
}
public void SetStatisticsResult(ServerSpeedItem update)
{ {
try try
{ {
if (!_showInTaskbar) 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)
{ {
return; Locator.Current.GetService<ProfilesViewModel>()?.UpdateStatistics(update);
} }
Application.Current?.Dispatcher.Invoke((Action)(() =>
{
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<ProfilesViewModel>()?.UpdateStatistics(update);
}
}));
} }
catch (Exception ex) catch (Exception ex)
{ {
@ -473,7 +468,7 @@ namespace v2rayN.ViewModels
switch (e) switch (e)
{ {
case EGlobalHotkey.ShowForm: case EGlobalHotkey.ShowForm:
ShowHideWindow(null); _updateView?.Invoke(EViewAction.ShowHideWindow, null);
break; break;
case EGlobalHotkey.SystemProxyClear: case EGlobalHotkey.SystemProxyClear:
@ -535,25 +530,22 @@ namespace v2rayN.ViewModels
MessageBus.Current.SendMessage("", Global.CommandRefreshProfiles); MessageBus.Current.SendMessage("", Global.CommandRefreshProfiles);
} }
private void RefreshServersBiz() public void RefreshServersBiz()
{ {
Application.Current?.Dispatcher.Invoke((Action)(() => RefreshServersMenu();
{
RefreshServersMenu();
//display running server //display running server
var running = ConfigHandler.GetDefaultServer(_config); var running = ConfigHandler.GetDefaultServer(_config);
if (running != null) if (running != null)
{ {
RunningServerDisplay = RunningServerDisplay =
RunningServerToolTipText = running.GetSummary(); RunningServerToolTipText = running.GetSummary();
} }
else else
{ {
RunningServerDisplay = RunningServerDisplay =
RunningServerToolTipText = ResUI.CheckServerSettings; RunningServerToolTipText = ResUI.CheckServerSettings;
} }
}));
} }
private void RefreshServersMenu() private void RefreshServersMenu()
@ -633,7 +625,7 @@ namespace v2rayN.ViewModels
public async Task ScanScreenTaskAsync() public async Task ScanScreenTaskAsync()
{ {
ShowHideWindow(false); _updateView?.Invoke(EViewAction.ShowHideWindow, false);
var dpiXY = QRCodeHelper.GetDpiXY(Application.Current.MainWindow); var dpiXY = QRCodeHelper.GetDpiXY(Application.Current.MainWindow);
string result = await Task.Run(() => string result = await Task.Run(() =>
@ -641,7 +633,7 @@ namespace v2rayN.ViewModels
return QRCodeHelper.ScanScreen(dpiXY.Item1, dpiXY.Item2); return QRCodeHelper.ScanScreen(dpiXY.Item1, dpiXY.Item2);
}); });
ShowHideWindow(true); _updateView?.Invoke(EViewAction.ShowHideWindow, true);
if (Utils.IsNullOrEmpty(result)) if (Utils.IsNullOrEmpty(result))
{ {
@ -710,17 +702,20 @@ namespace v2rayN.ViewModels
(new UpdateHandle()).RunAvailabilityCheck((bool success, string msg) => (new UpdateHandle()).RunAvailabilityCheck((bool success, string msg) =>
{ {
_noticeHandler?.SendMessage(msg, true); _noticeHandler?.SendMessage(msg, true);
Application.Current?.Dispatcher.Invoke((Action)(() =>
if (!_config.uiItem.showInTaskbar)
{ {
if (!_showInTaskbar) return;
{ }
return; _updateView?.Invoke(EViewAction.DispatcherServerAvailability, msg);
}
RunningInfoDisplay = msg;
}));
}); });
} }
public void TestServerAvailabilityResult(string msg)
{
RunningInfoDisplay = msg;
}
#endregion Add Servers #endregion Add Servers
#region Subscription #region Subscription
@ -854,29 +849,28 @@ namespace v2rayN.ViewModels
{ {
TestServerAvailability(); TestServerAvailability();
Application.Current?.Dispatcher.Invoke((Action)(() => _updateView?.Invoke(EViewAction.DispatcherReload, null);
{
BlReloadEnabled = true;
ShowClashUI = _config.IsRunningCore(ECoreType.clash);
if (ShowClashUI)
{
Locator.Current.GetService<ClashProxiesViewModel>()?.ProxiesReload();
}
else { TabMainSelectedIndex = 0; }
}));
}); });
} }
public void ReloadResult()
{
ChangeSystemProxyStatus(_config.systemProxyItem.sysProxyType, false);
BlReloadEnabled = true;
ShowClashUI = _config.IsRunningCore(ECoreType.clash);
if (ShowClashUI)
{
Locator.Current.GetService<ClashProxiesViewModel>()?.ProxiesReload();
}
else { TabMainSelectedIndex = 0; }
}
private async Task LoadCore() private async Task LoadCore()
{ {
await Task.Run(() => await Task.Run(() =>
{ {
var node = ConfigHandler.GetDefaultServer(_config); var node = ConfigHandler.GetDefaultServer(_config);
_coreHandler.LoadCore(node); _coreHandler.LoadCore(node);
//ConfigHandler.SaveConfig(_config, false);
ChangeSystemProxyStatus(_config.systemProxyItem.sysProxyType, false);
}); });
} }
@ -911,21 +905,18 @@ namespace v2rayN.ViewModels
SysProxyHandle.UpdateSysProxy(_config, _config.tunModeItem.enableTun ? true : false); SysProxyHandle.UpdateSysProxy(_config, _config.tunModeItem.enableTun ? true : false);
_noticeHandler?.SendMessage($"{ResUI.TipChangeSystemProxy} - {_config.systemProxyItem.sysProxyType.ToString()}", true); _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);
InboundDisplayStaus();
if (blChange)
{ {
BlSystemProxyClear = (type == ESysProxyType.ForcedClear); NotifyIcon = MainFormHandler.Instance.GetNotifyIcon(_config);
BlSystemProxySet = (type == ESysProxyType.ForcedChange); AppIcon = MainFormHandler.Instance.GetAppIcon(_config);
BlSystemProxyNothing = (type == ESysProxyType.Unchanged); }
BlSystemProxyPac = (type == ESysProxyType.Pac);
InboundDisplayStaus();
if (blChange)
{
NotifyIcon = MainFormHandler.Instance.GetNotifyIcon(_config);
AppIcon = MainFormHandler.Instance.GetAppIcon(_config);
}
}));
} }
private void RefreshRoutingsMenu() private void RefreshRoutingsMenu()
@ -1013,27 +1004,6 @@ namespace v2rayN.ViewModels
#region UI #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() public void InboundDisplayStaus()
{ {
StringBuilder sb = new(); StringBuilder sb = new();
@ -1078,10 +1048,7 @@ namespace v2rayN.ViewModels
.Delay(TimeSpan.FromSeconds(1)) .Delay(TimeSpan.FromSeconds(1))
.Subscribe(x => .Subscribe(x =>
{ {
Application.Current?.Dispatcher.Invoke(() => _updateView?.Invoke(EViewAction.ShowHideWindow, false);
{
ShowHideWindow(false);
});
}); });
} }
} }

View File

@ -6,7 +6,6 @@ using Splat;
using System.Reactive; using System.Reactive;
using System.Reactive.Linq; using System.Reactive.Linq;
using System.Text; using System.Text;
using System.Windows;
using v2rayN.Base; using v2rayN.Base;
using v2rayN.Enums; using v2rayN.Enums;
using v2rayN.Handler; using v2rayN.Handler;
@ -106,7 +105,7 @@ namespace v2rayN.ViewModels
_noticeHandler = Locator.Current.GetService<NoticeHandler>(); _noticeHandler = Locator.Current.GetService<NoticeHandler>();
_updateView = updateView; _updateView = updateView;
MessageBus.Current.Listen<string>(Global.CommandRefreshProfiles).Subscribe(x => RefreshServersBiz()); MessageBus.Current.Listen<string>(Global.CommandRefreshProfiles).Subscribe(x => _updateView?.Invoke(EViewAction.DispatcherRefreshServersBiz, null));
SelectedProfile = new(); SelectedProfile = new();
SelectedSub = new(); SelectedSub = new();
@ -246,34 +245,31 @@ namespace v2rayN.ViewModels
Locator.Current.GetService<MainWindowViewModel>()?.Reload(); Locator.Current.GetService<MainWindowViewModel>()?.Reload();
} }
private void UpdateSpeedtestHandler(string indexId, string delay, string speed) private void UpdateSpeedtestHandler(SpeedTestResult result)
{ {
Application.Current?.Dispatcher.Invoke((Action)(() => _updateView?.Invoke(EViewAction.DispatcherSpeedTest, result);
{
SetTestResult(indexId, delay, speed);
}));
} }
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?.SendMessage(result.Delay, true);
_noticeHandler?.Enqueue(delay); _noticeHandler?.Enqueue(result.Delay);
return; return;
} }
var item = _profileItems.Where(it => it.indexId == indexId).FirstOrDefault(); var item = _profileItems.Where(it => it.indexId == result.IndexId).FirstOrDefault();
if (item != null) 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.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)); _profileItems.Replace(item, JsonUtils.DeepCopy(item));
} }
@ -283,28 +279,25 @@ namespace v2rayN.ViewModels
{ {
try 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(); item.todayDown = Utils.HumanFy(update.todayDown);
if (item != null) item.todayUp = Utils.HumanFy(update.todayUp);
{ item.totalDown = Utils.HumanFy(update.totalDown);
item.todayDown = Utils.HumanFy(update.todayDown); item.totalUp = Utils.HumanFy(update.totalUp);
item.todayUp = Utils.HumanFy(update.todayUp);
item.totalDown = Utils.HumanFy(update.totalDown);
item.totalUp = Utils.HumanFy(update.totalUp);
if (SelectedProfile?.indexId == item.indexId) if (SelectedProfile?.indexId == item.indexId)
{ {
var temp = JsonUtils.DeepCopy(item); var temp = JsonUtils.DeepCopy(item);
_profileItems.Replace(item, temp); _profileItems.Replace(item, temp);
SelectedProfile = temp; SelectedProfile = temp;
}
else
{
_profileItems.Replace(item, JsonUtils.DeepCopy(item));
}
} }
})); else
{
_profileItems.Replace(item, JsonUtils.DeepCopy(item));
}
}
} }
catch catch
{ {
@ -346,7 +339,7 @@ namespace v2rayN.ViewModels
MessageBus.Current.SendMessage("", Global.CommandRefreshProfiles); MessageBus.Current.SendMessage("", Global.CommandRefreshProfiles);
} }
private void RefreshServersBiz() public void RefreshServersBiz()
{ {
var lstModel = LazyConfig.Instance.ProfileItems(_config.subIndexId, _serverFilter); var lstModel = LazyConfig.Instance.ProfileItems(_config.subIndexId, _serverFilter);
@ -381,25 +374,22 @@ namespace v2rayN.ViewModels
totalDown = t22 == null ? "" : Utils.HumanFy(t22.totalDown), totalDown = t22 == null ? "" : Utils.HumanFy(t22.totalDown),
totalUp = t22 == null ? "" : Utils.HumanFy(t22.totalUp) totalUp = t22 == null ? "" : Utils.HumanFy(t22.totalUp)
}).OrderBy(t => t.sort).ToList(); }).OrderBy(t => t.sort).ToList();
_lstProfile = JsonUtils.Deserialize<List<ProfileItem>>(JsonUtils.Serialize(lstModel)); _lstProfile = JsonUtils.Deserialize<List<ProfileItem>>(JsonUtils.Serialize(lstModel)) ?? [];
Application.Current?.Dispatcher.Invoke((Action)(() => _profileItems.Clear();
_profileItems.AddRange(lstModel);
if (lstModel.Count > 0)
{ {
_profileItems.Clear(); var selected = lstModel.FirstOrDefault(t => t.indexId == _config.indexId);
_profileItems.AddRange(lstModel); if (selected != null)
if (lstModel.Count > 0)
{ {
var selected = lstModel.FirstOrDefault(t => t.indexId == _config.indexId); SelectedProfile = selected;
if (selected != null)
{
SelectedProfile = selected;
}
else
{
SelectedProfile = lstModel[0];
}
} }
})); else
{
SelectedProfile = lstModel[0];
}
}
} }
public void RefreshSubscriptions() public void RefreshSubscriptions()

View File

@ -8,7 +8,6 @@ using v2rayN.Enums;
using v2rayN.Handler; using v2rayN.Handler;
using v2rayN.Models; using v2rayN.Models;
using v2rayN.Resx; using v2rayN.Resx;
using Application = System.Windows.Application;
namespace v2rayN.ViewModels namespace v2rayN.ViewModels
{ {
@ -76,9 +75,9 @@ namespace v2rayN.ViewModels
{ {
ImportRulesFromClipboard(); ImportRulesFromClipboard();
}); });
ImportRulesFromUrlCmd = ReactiveCommand.CreateFromTask(() => ImportRulesFromUrlCmd = ReactiveCommand.Create(() =>
{ {
return ImportRulesFromUrl(); ImportRulesFromUrl();
}); });
RuleRemoveCmd = ReactiveCommand.Create(() => RuleRemoveCmd = ReactiveCommand.Create(() =>
@ -292,7 +291,7 @@ namespace v2rayN.ViewModels
} }
} }
private async Task ImportRulesFromUrl() private void ImportRulesFromUrl()
{ {
var url = SelectedRouting.url; var url = SelectedRouting.url;
if (Utils.IsNullOrEmpty(url)) if (Utils.IsNullOrEmpty(url))
@ -302,13 +301,10 @@ namespace v2rayN.ViewModels
} }
DownloadHandle downloadHandle = new DownloadHandle(); DownloadHandle downloadHandle = new DownloadHandle();
var result = await downloadHandle.TryDownloadString(url, true, ""); var result = downloadHandle.TryDownloadString(url, true, "").Result;
if (AddBatchRoutingRules(SelectedRouting, result) == 0) if (AddBatchRoutingRules(SelectedRouting, result) == 0)
{ {
Application.Current.Dispatcher.Invoke((Action)(() => RefreshRulesItems();
{
RefreshRulesItems();
}));
_noticeHandler?.Enqueue(ResUI.OperationSuccess); _noticeHandler?.Enqueue(ResUI.OperationSuccess);
} }
} }

View File

@ -1,5 +1,9 @@
using ReactiveUI; using ReactiveUI;
using System.Reactive.Disposables; using System.Reactive.Disposables;
using System.Windows;
using System.Windows.Threading;
using v2rayN.Enums;
using v2rayN.Models;
using v2rayN.ViewModels; using v2rayN.ViewModels;
namespace v2rayN.Views namespace v2rayN.Views
@ -12,7 +16,7 @@ namespace v2rayN.Views
public ClashConnectionsView() public ClashConnectionsView()
{ {
InitializeComponent(); InitializeComponent();
ViewModel = new ClashConnectionsViewModel(); ViewModel = new ClashConnectionsViewModel(UpdateViewHandler);
this.WhenActivated(disposables => this.WhenActivated(disposables =>
{ {
@ -28,6 +32,22 @@ namespace v2rayN.Views
}); });
} }
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<ConnectionItem>?)obj);
}), DispatcherPriority.Normal);
break;
}
return true;
}
private void btnClose_Click(object sender, System.Windows.RoutedEventArgs e) private void btnClose_Click(object sender, System.Windows.RoutedEventArgs e)
{ {
ViewModel?.ClashConnectionClose(false); ViewModel?.ClashConnectionClose(false);

View File

@ -1,7 +1,11 @@
using ReactiveUI; using ReactiveUI;
using Splat; using Splat;
using System.Reactive.Disposables; using System.Reactive.Disposables;
using System.Windows;
using System.Windows.Input; using System.Windows.Input;
using System.Windows.Threading;
using v2rayN.Enums;
using v2rayN.Models;
using v2rayN.ViewModels; using v2rayN.ViewModels;
namespace v2rayN.Views namespace v2rayN.Views
@ -14,7 +18,7 @@ namespace v2rayN.Views
public ClashProxiesView() public ClashProxiesView()
{ {
InitializeComponent(); InitializeComponent();
ViewModel = new ClashProxiesViewModel(); ViewModel = new ClashProxiesViewModel(UpdateViewHandler);
Locator.CurrentMutable.RegisterLazySingleton(() => ViewModel, typeof(ClashProxiesViewModel)); Locator.CurrentMutable.RegisterLazySingleton(() => ViewModel, typeof(ClashProxiesViewModel));
lstProxyDetails.PreviewMouseDoubleClick += lstProxyDetails_PreviewMouseDoubleClick; lstProxyDetails.PreviewMouseDoubleClick += lstProxyDetails_PreviewMouseDoubleClick;
@ -38,6 +42,30 @@ namespace v2rayN.Views
}); });
} }
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) private void ProxiesView_KeyDown(object sender, KeyEventArgs e)
{ {
switch (e.Key) switch (e.Key)

View File

@ -7,6 +7,7 @@ using System.Windows.Controls;
using System.Windows.Input; using System.Windows.Input;
using System.Windows.Interop; using System.Windows.Interop;
using System.Windows.Media; using System.Windows.Media;
using System.Windows.Threading;
using v2rayN.Enums; using v2rayN.Enums;
using v2rayN.Handler; using v2rayN.Handler;
using v2rayN.Models; using v2rayN.Models;
@ -184,35 +185,67 @@ namespace v2rayN.Views
private bool UpdateViewHandler(EViewAction action, object? obj) private bool UpdateViewHandler(EViewAction action, object? obj)
{ {
if (action == EViewAction.AddServerWindow) switch (action)
{ {
if (obj is null) return false; case EViewAction.AddServerWindow:
return (new AddServerWindow((ProfileItem)obj)).ShowDialog() ?? false; if (obj is null) return false;
} return (new AddServerWindow((ProfileItem)obj)).ShowDialog() ?? false;
else if (action == EViewAction.AddServer2Window)
{ case EViewAction.AddServer2Window:
if (obj is null) return false; if (obj is null) return false;
return (new AddServer2Window((ProfileItem)obj)).ShowDialog() ?? false; return (new AddServer2Window((ProfileItem)obj)).ShowDialog() ?? false;
}
else if (action == EViewAction.DNSSettingWindow) case EViewAction.DNSSettingWindow:
{ return (new DNSSettingWindow().ShowDialog() ?? false);
return (new DNSSettingWindow().ShowDialog() ?? false);
} case EViewAction.RoutingSettingWindow:
else if (action == EViewAction.RoutingSettingWindow) return (new RoutingSettingWindow().ShowDialog() ?? false);
{
return (new RoutingSettingWindow().ShowDialog() ?? false); case EViewAction.OptionSettingWindow:
} return (new OptionSettingWindow().ShowDialog() ?? false);
else if (action == EViewAction.OptionSettingWindow)
{ case EViewAction.GlobalHotkeySettingWindow:
return (new OptionSettingWindow().ShowDialog() ?? false); return (new GlobalHotkeySettingWindow().ShowDialog() ?? false);
}
else if (action == EViewAction.GlobalHotkeySettingWindow) case EViewAction.SubSettingWindow:
{ return (new SubSettingWindow().ShowDialog() ?? false);
return (new GlobalHotkeySettingWindow().ShowDialog() ?? false);
} case EViewAction.ShowHideWindow:
else if (action == EViewAction.SubSettingWindow) Application.Current?.Dispatcher.Invoke((() =>
{ {
return (new SubSettingWindow().ShowDialog() ?? false); 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; return true;
@ -223,7 +256,7 @@ namespace v2rayN.Views
private void MainWindow_Closing(object? sender, CancelEventArgs e) private void MainWindow_Closing(object? sender, CancelEventArgs e)
{ {
e.Cancel = true; e.Cancel = true;
ViewModel?.ShowHideWindow(false); ShowHideWindow(false);
} }
private void menuExit_Click(object sender, RoutedEventArgs e) private void menuExit_Click(object sender, RoutedEventArgs e)
@ -269,7 +302,7 @@ namespace v2rayN.Views
private void menuClose_Click(object sender, RoutedEventArgs e) private void menuClose_Click(object sender, RoutedEventArgs e)
{ {
StorageUI(); StorageUI();
ViewModel?.ShowHideWindow(false); ShowHideWindow(false);
} }
private void menuPromotion_Click(object sender, RoutedEventArgs e) private void menuPromotion_Click(object sender, RoutedEventArgs e)
@ -291,6 +324,26 @@ namespace v2rayN.Views
#region UI #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() private void RestoreUI()
{ {
if (_config.uiItem.mainWidth > 0 && _config.uiItem.mainHeight > 0) if (_config.uiItem.mainWidth > 0 && _config.uiItem.mainHeight > 0)

View File

@ -7,6 +7,7 @@ using System.Windows.Controls;
using System.Windows.Controls.Primitives; using System.Windows.Controls.Primitives;
using System.Windows.Input; using System.Windows.Input;
using System.Windows.Media; using System.Windows.Media;
using System.Windows.Threading;
using v2rayN.Base; using v2rayN.Base;
using v2rayN.Enums; using v2rayN.Enums;
using v2rayN.Handler; using v2rayN.Handler;
@ -89,6 +90,7 @@ namespace v2rayN.Views
}); });
RestoreUI(); RestoreUI();
ViewModel?.RefreshServers();
} }
#region Event #region Event
@ -100,36 +102,50 @@ namespace v2rayN.Views
private bool UpdateViewHandler(EViewAction action, object? obj) private bool UpdateViewHandler(EViewAction action, object? obj)
{ {
if (action == EViewAction.ProfilesFocus) switch (action)
{ {
lstProfiles.Focus(); case EViewAction.ProfilesFocus:
} lstProfiles.Focus();
else if (action == EViewAction.ShowYesNo) break;
{
if (UI.ShowYesNo(ResUI.RemoveServer) == MessageBoxResult.No) case EViewAction.ShowYesNo:
{ if (UI.ShowYesNo(ResUI.RemoveServer) == MessageBoxResult.No)
return false; {
} return false;
} }
else if (action == EViewAction.AddServerWindow) break;
{
if (obj is null) return false; case EViewAction.AddServerWindow:
return (new AddServerWindow((ProfileItem)obj)).ShowDialog() ?? false; if (obj is null) return false;
} return (new AddServerWindow((ProfileItem)obj)).ShowDialog() ?? false;
else if (action == EViewAction.AddServer2Window)
{ case EViewAction.AddServer2Window:
if (obj is null) return false; if (obj is null) return false;
return (new AddServer2Window((ProfileItem)obj)).ShowDialog() ?? false; return (new AddServer2Window((ProfileItem)obj)).ShowDialog() ?? false;
}
else if (action == EViewAction.ShareServer) case EViewAction.ShareServer:
{ if (obj is null) return false;
if (obj is null) return false; ShareServer((string)obj);
ShareServer((string)obj); break;
}
else if (action == EViewAction.SubEditWindow) case EViewAction.SubEditWindow:
{ if (obj is null) return false;
if (obj is null) return false; return (new SubEditWindow((SubItem)obj)).ShowDialog() ?? 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; return true;