Compare commits

..

1 commit

Author SHA1 Message Date
DHR60
30e6b1aaed
Merge 4301415b4c into e96a4818c4 2025-09-23 09:59:47 +00:00
12 changed files with 99 additions and 97 deletions

View file

@ -20,7 +20,7 @@
<PackageVersion Include="ReactiveUI.WPF" Version="20.4.1" /> <PackageVersion Include="ReactiveUI.WPF" Version="20.4.1" />
<PackageVersion Include="Semi.Avalonia" Version="11.2.1.10" /> <PackageVersion Include="Semi.Avalonia" Version="11.2.1.10" />
<PackageVersion Include="Semi.Avalonia.DataGrid" Version="11.2.1.10" /> <PackageVersion Include="Semi.Avalonia.DataGrid" Version="11.2.1.10" />
<PackageVersion Include="NLog" Version="6.0.4" /> <PackageVersion Include="Splat.NLog" Version="17.0.1" />
<PackageVersion Include="sqlite-net-pcl" Version="1.9.172" /> <PackageVersion Include="sqlite-net-pcl" Version="1.9.172" />
<PackageVersion Include="TaskScheduler" Version="2.12.2" /> <PackageVersion Include="TaskScheduler" Version="2.12.2" />
<PackageVersion Include="WebDav.Client" Version="2.9.0" /> <PackageVersion Include="WebDav.Client" Version="2.9.0" />

View file

@ -12,6 +12,7 @@ public enum EViewAction
ProfilesFocus, ProfilesFocus,
ShareSub, ShareSub,
ShareServer, ShareServer,
ShowHideWindow,
ScanScreenTask, ScanScreenTask,
ScanImageTask, ScanImageTask,
BrowseServer, BrowseServer,

View file

@ -5,12 +5,6 @@ namespace ServiceLib.Handler;
public static class AppEvents public static class AppEvents
{ {
public static readonly Subject<Unit> ReloadRequested = new();
public static readonly Subject<bool?> ShowHideWindowRequested = new();
public static readonly Subject<Unit> AddServerViaScanRequested = new();
public static readonly Subject<Unit> AddServerViaClipboardRequested = new();
public static readonly Subject<bool> SubscriptionsUpdateRequested = new();
public static readonly Subject<Unit> ProfilesRefreshRequested = new(); public static readonly Subject<Unit> ProfilesRefreshRequested = new();
public static readonly Subject<Unit> SubscriptionsRefreshRequested = new(); public static readonly Subject<Unit> SubscriptionsRefreshRequested = new();
public static readonly Subject<Unit> ProxiesReloadRequested = new(); public static readonly Subject<Unit> ProxiesReloadRequested = new();

View file

@ -122,12 +122,6 @@ public sealed class AppManager
AppEvents.ShutdownRequested.OnNext(byUser); AppEvents.ShutdownRequested.OnNext(byUser);
} }
public async Task RebootAsAdmin()
{
ProcUtils.RebootAsAdmin();
await AppManager.Instance.AppExitAsync(true);
}
#endregion App #endregion App
#region Config #region Config

View file

@ -11,7 +11,7 @@
</PackageReference> </PackageReference>
<PackageReference Include="ReactiveUI.Fody" /> <PackageReference Include="ReactiveUI.Fody" />
<PackageReference Include="sqlite-net-pcl" /> <PackageReference Include="sqlite-net-pcl" />
<PackageReference Include="NLog" /> <PackageReference Include="Splat.NLog" />
<PackageReference Include="WebDav.Client" /> <PackageReference Include="WebDav.Client" />
<PackageReference Include="YamlDotNet" /> <PackageReference Include="YamlDotNet" />
<PackageReference Include="QRCoder" /> <PackageReference Include="QRCoder" />

View file

@ -2,9 +2,11 @@ using System.Reactive;
using System.Reactive.Disposables; using System.Reactive.Disposables;
using System.Reactive.Linq; using System.Reactive.Linq;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using DynamicData;
using DynamicData.Binding; using DynamicData.Binding;
using ReactiveUI; using ReactiveUI;
using ReactiveUI.Fody.Helpers; using ReactiveUI.Fody.Helpers;
using Splat;
namespace ServiceLib.ViewModels; namespace ServiceLib.ViewModels;
@ -223,11 +225,11 @@ public class CheckUpdateViewModel : MyReactiveObject
{ {
if (blReload) if (blReload)
{ {
AppEvents.ReloadRequested.OnNext(Unit.Default); Locator.Current.GetService<MainWindowViewModel>()?.Reload();
} }
else else
{ {
await CoreManager.Instance.CoreStop(); Locator.Current.GetService<MainWindowViewModel>()?.CloseCore();
} }
} }

View file

@ -1,6 +1,5 @@
using System.Reactive; using System.Reactive;
using System.Reactive.Concurrency; using System.Reactive.Concurrency;
using System.Reactive.Linq;
using ReactiveUI; using ReactiveUI;
using ReactiveUI.Fody.Helpers; using ReactiveUI.Fody.Helpers;
@ -184,7 +183,7 @@ public class MainWindowViewModel : MyReactiveObject
}); });
RebootAsAdminCmd = ReactiveCommand.CreateFromTask(async () => RebootAsAdminCmd = ReactiveCommand.CreateFromTask(async () =>
{ {
await AppManager.Instance.RebootAsAdmin(); await RebootAsAdmin();
}); });
ClearServerStatisticsCmd = ReactiveCommand.CreateFromTask(async () => ClearServerStatisticsCmd = ReactiveCommand.CreateFromTask(async () =>
{ {
@ -217,30 +216,6 @@ public class MainWindowViewModel : MyReactiveObject
#endregion WhenAnyValue && ReactiveCommand #endregion WhenAnyValue && ReactiveCommand
#region AppEvents
AppEvents.ReloadRequested
.AsObservable()
.ObserveOn(RxApp.MainThreadScheduler)
.Subscribe(async _ => await Reload());
AppEvents.AddServerViaScanRequested
.AsObservable()
.ObserveOn(RxApp.MainThreadScheduler)
.Subscribe(async _ => await AddServerViaScanAsync());
AppEvents.AddServerViaClipboardRequested
.AsObservable()
.ObserveOn(RxApp.MainThreadScheduler)
.Subscribe(async _ => await AddServerViaClipboardAsync(null));
AppEvents.SubscriptionsUpdateRequested
.AsObservable()
.ObserveOn(RxApp.MainThreadScheduler)
.Subscribe(async blProxy => await UpdateSubscriptionProcess("", blProxy));
#endregion AppEvents
_ = Init(); _ = Init();
} }
@ -306,6 +281,11 @@ public class MainWindowViewModel : MyReactiveObject
AppEvents.DispatcherStatisticsRequested.OnNext(update); AppEvents.DispatcherStatisticsRequested.OnNext(update);
} }
public void ShowHideWindow(bool? blShow)
{
_updateView?.Invoke(EViewAction.ShowHideWindow, blShow);
}
#endregion Actions #endregion Actions
#region Servers && Groups #region Servers && Groups
@ -485,6 +465,12 @@ public class MainWindowViewModel : MyReactiveObject
} }
} }
public async Task RebootAsAdmin()
{
ProcUtils.RebootAsAdmin();
await AppManager.Instance.AppExitAsync(true);
}
private async Task ClearServerStatistics() private async Task ClearServerStatistics()
{ {
await StatisticsManager.Instance.ClearAllServerStatistics(); await StatisticsManager.Instance.ClearAllServerStatistics();
@ -561,11 +547,17 @@ public class MainWindowViewModel : MyReactiveObject
await CoreManager.Instance.LoadCore(node); await CoreManager.Instance.LoadCore(node);
} }
public async Task CloseCore()
{
await ConfigHandler.SaveConfig(_config);
await CoreManager.Instance.CoreStop();
}
private async Task AutoHideStartup() private async Task AutoHideStartup()
{ {
if (_config.UiItem.AutoHideStartup) if (_config.UiItem.AutoHideStartup)
{ {
AppEvents.ShowHideWindowRequested.OnNext(false); ShowHideWindow(false);
} }
await Task.CompletedTask; await Task.CompletedTask;
} }

View file

@ -6,6 +6,7 @@ using DynamicData;
using DynamicData.Binding; using DynamicData.Binding;
using ReactiveUI; using ReactiveUI;
using ReactiveUI.Fody.Helpers; using ReactiveUI.Fody.Helpers;
using Splat;
namespace ServiceLib.ViewModels; namespace ServiceLib.ViewModels;
@ -275,7 +276,7 @@ public class ProfilesViewModel : MyReactiveObject
private void Reload() private void Reload()
{ {
AppEvents.ReloadRequested.OnNext(Unit.Default); Locator.Current.GetService<MainWindowViewModel>()?.Reload();
} }
public async Task SetSpeedTestResult(SpeedTestResult result) public async Task SetSpeedTestResult(SpeedTestResult result)

View file

@ -5,6 +5,7 @@ using System.Text;
using DynamicData.Binding; using DynamicData.Binding;
using ReactiveUI; using ReactiveUI;
using ReactiveUI.Fody.Helpers; using ReactiveUI.Fody.Helpers;
using Splat;
namespace ServiceLib.ViewModels; namespace ServiceLib.ViewModels;
@ -148,17 +149,17 @@ public class StatusBarViewModel : MyReactiveObject
NotifyLeftClickCmd = ReactiveCommand.CreateFromTask(async () => NotifyLeftClickCmd = ReactiveCommand.CreateFromTask(async () =>
{ {
AppEvents.ShowHideWindowRequested.OnNext(null); Locator.Current.GetService<MainWindowViewModel>()?.ShowHideWindow(null);
await Task.CompletedTask; await Task.CompletedTask;
}); });
ShowWindowCmd = ReactiveCommand.CreateFromTask(async () => ShowWindowCmd = ReactiveCommand.CreateFromTask(async () =>
{ {
AppEvents.ShowHideWindowRequested.OnNext(true); Locator.Current.GetService<MainWindowViewModel>()?.ShowHideWindow(true);
await Task.CompletedTask; await Task.CompletedTask;
}); });
HideWindowCmd = ReactiveCommand.CreateFromTask(async () => HideWindowCmd = ReactiveCommand.CreateFromTask(async () =>
{ {
AppEvents.ShowHideWindowRequested.OnNext(false); Locator.Current.GetService<MainWindowViewModel>()?.ShowHideWindow(false);
await Task.CompletedTask; await Task.CompletedTask;
}); });
@ -274,20 +275,23 @@ public class StatusBarViewModel : MyReactiveObject
private async Task AddServerViaClipboard() private async Task AddServerViaClipboard()
{ {
AppEvents.AddServerViaClipboardRequested.OnNext(Unit.Default); var service = Locator.Current.GetService<MainWindowViewModel>();
await Task.Delay(1000); if (service != null)
await service.AddServerViaClipboardAsync(null);
} }
private async Task AddServerViaScan() private async Task AddServerViaScan()
{ {
AppEvents.AddServerViaScanRequested.OnNext(Unit.Default); var service = Locator.Current.GetService<MainWindowViewModel>();
await Task.Delay(1000); if (service != null)
await service.AddServerViaScanAsync();
} }
private async Task UpdateSubscriptionProcess(bool blProxy) private async Task UpdateSubscriptionProcess(bool blProxy)
{ {
AppEvents.SubscriptionsUpdateRequested.OnNext(blProxy); var service = Locator.Current.GetService<MainWindowViewModel>();
await Task.Delay(1000); if (service != null)
await service.UpdateSubscriptionProcess("", blProxy);
} }
private async Task RefreshServersBiz() private async Task RefreshServersBiz()
@ -449,7 +453,7 @@ public class StatusBarViewModel : MyReactiveObject
if (await ConfigHandler.SetDefaultRouting(_config, item) == 0) if (await ConfigHandler.SetDefaultRouting(_config, item) == 0)
{ {
NoticeManager.Instance.SendMessageEx(ResUI.TipChangeRouting); NoticeManager.Instance.SendMessageEx(ResUI.TipChangeRouting);
AppEvents.ReloadRequested.OnNext(Unit.Default); Locator.Current.GetService<MainWindowViewModel>()?.Reload();
_updateView?.Invoke(EViewAction.DispatcherRefreshIcon, null); _updateView?.Invoke(EViewAction.DispatcherRefreshIcon, null);
} }
} }
@ -482,7 +486,7 @@ public class StatusBarViewModel : MyReactiveObject
if (Utils.IsWindows()) if (Utils.IsWindows())
{ {
_config.TunModeItem.EnableTun = false; _config.TunModeItem.EnableTun = false;
await AppManager.Instance.RebootAsAdmin(); Locator.Current.GetService<MainWindowViewModel>()?.RebootAsAdmin();
return; return;
} }
else else
@ -496,7 +500,7 @@ public class StatusBarViewModel : MyReactiveObject
} }
} }
await ConfigHandler.SaveConfig(_config); await ConfigHandler.SaveConfig(_config);
AppEvents.ReloadRequested.OnNext(Unit.Default); Locator.Current.GetService<MainWindowViewModel>()?.Reload();
} }
private bool AllowEnableTun() private bool AllowEnableTun()

View file

@ -1,7 +1,8 @@
using System.Reactive;
using Avalonia; using Avalonia;
using Avalonia.Controls.ApplicationLifetimes; using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Markup.Xaml; using Avalonia.Markup.Xaml;
using Splat;
using v2rayN.Desktop.Common;
using v2rayN.Desktop.Views; using v2rayN.Desktop.Views;
namespace v2rayN.Desktop; namespace v2rayN.Desktop;
@ -54,8 +55,16 @@ public partial class App : Application
{ {
if (desktop.MainWindow != null) if (desktop.MainWindow != null)
{ {
AppEvents.AddServerViaClipboardRequested.OnNext(Unit.Default); var clipboardData = await AvaUtils.GetClipboardData(desktop.MainWindow);
await Task.Delay(1000); if (clipboardData.IsNullOrEmpty())
{
return;
}
var service = Locator.Current.GetService<MainWindowViewModel>();
if (service != null)
{
_ = service.AddServerViaClipboardAsync(clipboardData);
}
} }
} }
} }

View file

@ -10,6 +10,7 @@ using Avalonia.Threading;
using DialogHostAvalonia; using DialogHostAvalonia;
using MsBox.Avalonia.Enums; using MsBox.Avalonia.Enums;
using ReactiveUI; using ReactiveUI;
using Splat;
using v2rayN.Desktop.Base; using v2rayN.Desktop.Base;
using v2rayN.Desktop.Common; using v2rayN.Desktop.Common;
using v2rayN.Desktop.Manager; using v2rayN.Desktop.Manager;
@ -39,6 +40,7 @@ public partial class MainWindow : WindowBase<MainWindowViewModel>
menuClose.Click += MenuClose_Click; menuClose.Click += MenuClose_Click;
ViewModel = new MainWindowViewModel(UpdateViewHandler); ViewModel = new MainWindowViewModel(UpdateViewHandler);
Locator.CurrentMutable.RegisterLazySingleton(() => ViewModel, typeof(MainWindowViewModel));
switch (_config.UiItem.MainGirdOrientation) switch (_config.UiItem.MainGirdOrientation)
{ {
@ -151,12 +153,6 @@ public partial class MainWindow : WindowBase<MainWindowViewModel>
.ObserveOn(RxApp.MainThreadScheduler) .ObserveOn(RxApp.MainThreadScheduler)
.Subscribe(content => Shutdown(content)) .Subscribe(content => Shutdown(content))
.DisposeWith(disposables); .DisposeWith(disposables);
AppEvents.ShowHideWindowRequested
.AsObservable()
.ObserveOn(RxApp.MainThreadScheduler)
.Subscribe(blShow => ShowHideWindow(blShow))
.DisposeWith(disposables);
}); });
if (Utils.IsWindows()) if (Utils.IsWindows())
@ -225,6 +221,12 @@ public partial class MainWindow : WindowBase<MainWindowViewModel>
case EViewAction.SubSettingWindow: case EViewAction.SubSettingWindow:
return await new SubSettingWindow().ShowDialog<bool>(this); return await new SubSettingWindow().ShowDialog<bool>(this);
case EViewAction.ShowHideWindow:
Dispatcher.UIThread.Post(() =>
ShowHideWindow((bool?)obj),
DispatcherPriority.Default);
break;
case EViewAction.ScanScreenTask: case EViewAction.ScanScreenTask:
await ScanScreenTaskAsync(); await ScanScreenTaskAsync();
break; break;
@ -234,7 +236,11 @@ public partial class MainWindow : WindowBase<MainWindowViewModel>
break; break;
case EViewAction.AddServerViaClipboard: case EViewAction.AddServerViaClipboard:
await AddServerViaClipboardAsync(); var clipboardData = await AvaUtils.GetClipboardData(this);
if (clipboardData.IsNotEmpty() && ViewModel != null)
{
await ViewModel.AddServerViaClipboardAsync(clipboardData);
}
break; break;
} }
@ -289,7 +295,11 @@ public partial class MainWindow : WindowBase<MainWindowViewModel>
switch (e.Key) switch (e.Key)
{ {
case Key.V: case Key.V:
await AddServerViaClipboardAsync(); var clipboardData = await AvaUtils.GetClipboardData(this);
if (clipboardData.IsNotEmpty() && ViewModel != null)
{
await ViewModel.AddServerViaClipboardAsync(clipboardData);
}
break; break;
case Key.S: case Key.S:
@ -316,15 +326,6 @@ public partial class MainWindow : WindowBase<MainWindowViewModel>
ProcUtils.ProcessStart(Utils.GetBinPath("EnableLoopback.exe")); ProcUtils.ProcessStart(Utils.GetBinPath("EnableLoopback.exe"));
} }
public async Task AddServerViaClipboardAsync()
{
var clipboardData = await AvaUtils.GetClipboardData(this);
if (clipboardData.IsNotEmpty() && ViewModel != null)
{
await ViewModel.AddServerViaClipboardAsync(clipboardData);
}
}
public async Task ScanScreenTaskAsync() public async Task ScanScreenTaskAsync()
{ {
//ShowHideWindow(false); //ShowHideWindow(false);

View file

@ -6,8 +6,10 @@ 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 MaterialDesignThemes.Wpf; using MaterialDesignThemes.Wpf;
using ReactiveUI; using ReactiveUI;
using Splat;
using v2rayN.Manager; using v2rayN.Manager;
namespace v2rayN.Views; namespace v2rayN.Views;
@ -35,6 +37,7 @@ public partial class MainWindow
menuBackupAndRestore.Click += MenuBackupAndRestore_Click; menuBackupAndRestore.Click += MenuBackupAndRestore_Click;
ViewModel = new MainWindowViewModel(UpdateViewHandler); ViewModel = new MainWindowViewModel(UpdateViewHandler);
Locator.CurrentMutable.RegisterLazySingleton(() => ViewModel, typeof(MainWindowViewModel));
switch (_config.UiItem.MainGirdOrientation) switch (_config.UiItem.MainGirdOrientation)
{ {
@ -143,16 +146,10 @@ public partial class MainWindow
.DisposeWith(disposables); .DisposeWith(disposables);
AppEvents.ShutdownRequested AppEvents.ShutdownRequested
.AsObservable() .AsObservable()
.ObserveOn(RxApp.MainThreadScheduler) .ObserveOn(RxApp.MainThreadScheduler)
.Subscribe(content => Shutdown(content)) .Subscribe(content => Shutdown(content))
.DisposeWith(disposables); .DisposeWith(disposables);
AppEvents.ShowHideWindowRequested
.AsObservable()
.ObserveOn(RxApp.MainThreadScheduler)
.Subscribe(blShow => ShowHideWindow(blShow))
.DisposeWith(disposables);
}); });
this.Title = $"{Utils.GetVersion()} - {(Utils.IsAdministrator() ? ResUI.RunAsAdmin : ResUI.NotRunAsAdmin)}"; this.Title = $"{Utils.GetVersion()} - {(Utils.IsAdministrator() ? ResUI.RunAsAdmin : ResUI.NotRunAsAdmin)}";
@ -213,6 +210,13 @@ public partial class MainWindow
case EViewAction.SubSettingWindow: case EViewAction.SubSettingWindow:
return (new SubSettingWindow().ShowDialog() ?? false); return (new SubSettingWindow().ShowDialog() ?? false);
case EViewAction.ShowHideWindow:
Application.Current?.Dispatcher.Invoke((() =>
{
ShowHideWindow((bool?)obj);
}), DispatcherPriority.Normal);
break;
case EViewAction.ScanScreenTask: case EViewAction.ScanScreenTask:
await ScanScreenTaskAsync(); await ScanScreenTaskAsync();
break; break;
@ -222,7 +226,11 @@ public partial class MainWindow
break; break;
case EViewAction.AddServerViaClipboard: case EViewAction.AddServerViaClipboard:
await AddServerViaClipboardAsync(); var clipboardData = WindowsUtils.GetClipboardData();
if (clipboardData.IsNotEmpty())
{
ViewModel?.AddServerViaClipboardAsync(clipboardData);
}
break; break;
} }
@ -275,7 +283,12 @@ public partial class MainWindow
{ {
return; return;
} }
AddServerViaClipboardAsync().ContinueWith(_ => { });
var clipboardData = WindowsUtils.GetClipboardData();
if (clipboardData.IsNotEmpty())
{
ViewModel?.AddServerViaClipboardAsync(clipboardData);
}
break; break;
@ -309,15 +322,6 @@ public partial class MainWindow
ProcUtils.ProcessStart(Utils.GetBinPath("EnableLoopback.exe")); ProcUtils.ProcessStart(Utils.GetBinPath("EnableLoopback.exe"));
} }
public async Task AddServerViaClipboardAsync()
{
var clipboardData = WindowsUtils.GetClipboardData();
if (clipboardData.IsNotEmpty() && ViewModel != null)
{
await ViewModel.AddServerViaClipboardAsync(clipboardData);
}
}
private async Task ScanScreenTaskAsync() private async Task ScanScreenTaskAsync()
{ {
ShowHideWindow(false); ShowHideWindow(false);