From f85326cf0e32fd6a98f75fbf197d6920429b4b6b Mon Sep 17 00:00:00 2001 From: 2dust <31833384+2dust@users.noreply.github.com> Date: Sat, 3 Oct 2026 14:58:45 +0800 Subject: [PATCH] Add per-core prerelease update selection Replaces the global prerelease toggle with per-core prerelease options in both WPF and Avalonia update views, and persists selections via `CheckPreReleaseCoreTypes` in config. Update checks now resolve prerelease mode per selected core (including auto-check flow), and the sing-box max-version lock is removed to allow newer versions. --- v2rayN/ServiceLib/Manager/CoreInfoManager.cs | 2 +- v2rayN/ServiceLib/Manager/TaskManager.cs | 2 +- .../ServiceLib/Models/Configs/ConfigItems.cs | 2 +- .../ServiceLib/Models/Dto/CheckUpdateModel.cs | 2 + v2rayN/ServiceLib/Services/UpdateService.cs | 3 +- .../ViewModels/CheckUpdateViewModel.cs | 37 +++++++---------- .../Views/CheckUpdateView.axaml | 36 ++++++++++------- .../Views/CheckUpdateView.axaml.cs | 1 - v2rayN/v2rayN/Views/CheckUpdateView.xaml | 40 ++++++++++++------- v2rayN/v2rayN/Views/CheckUpdateView.xaml.cs | 1 - 10 files changed, 70 insertions(+), 56 deletions(-) diff --git a/v2rayN/ServiceLib/Manager/CoreInfoManager.cs b/v2rayN/ServiceLib/Manager/CoreInfoManager.cs index de5875e5..2e9f3423 100644 --- a/v2rayN/ServiceLib/Manager/CoreInfoManager.cs +++ b/v2rayN/ServiceLib/Manager/CoreInfoManager.cs @@ -229,7 +229,7 @@ public sealed class CoreInfoManager DownloadUrlLinuxLoong64 = urlSingbox + "/download/{0}/sing-box-{1}-linux-loong64.tar.gz", DownloadUrlOSX64 = urlSingbox + "/download/{0}/sing-box-{1}-darwin-amd64.tar.gz", DownloadUrlOSXArm64 = urlSingbox + "/download/{0}/sing-box-{1}-darwin-arm64.tar.gz", - LockedMaxVersion = new SemanticVersion(1, 14, int.MaxValue), + //LockedMaxVersion = new SemanticVersion(1, 14, int.MaxValue), Match = "sing-box", VersionArg = "version", }, diff --git a/v2rayN/ServiceLib/Manager/TaskManager.cs b/v2rayN/ServiceLib/Manager/TaskManager.cs index dbec401a..cb400f2a 100644 --- a/v2rayN/ServiceLib/Manager/TaskManager.cs +++ b/v2rayN/ServiceLib/Manager/TaskManager.cs @@ -134,7 +134,7 @@ public class TaskManager var updateService = new UpdateService(_config, async (success, msg) => await Task.CompletedTask); - var msgs = await updateService.CheckHasUpdateOnlyAll(_config.CheckUpdateItem.CheckPreReleaseUpdate, _config.CheckUpdateItem.UpdateViaProxy); + var msgs = await updateService.CheckHasUpdateOnlyAll(_config.CheckUpdateItem.UpdateViaProxy); foreach (var msg in msgs) { await _updateFunc?.Invoke(false, msg); diff --git a/v2rayN/ServiceLib/Models/Configs/ConfigItems.cs b/v2rayN/ServiceLib/Models/Configs/ConfigItems.cs index 4931dd23..4219b66e 100644 --- a/v2rayN/ServiceLib/Models/Configs/ConfigItems.cs +++ b/v2rayN/ServiceLib/Models/Configs/ConfigItems.cs @@ -242,9 +242,9 @@ public class WebDavItem [Serializable] public class CheckUpdateItem { - public bool CheckPreReleaseUpdate { get; set; } public bool UpdateViaProxy { get; set; } = true; public List? SelectedCoreTypes { get; set; } + public List? CheckPreReleaseCoreTypes { get; set; } } [Serializable] diff --git a/v2rayN/ServiceLib/Models/Dto/CheckUpdateModel.cs b/v2rayN/ServiceLib/Models/Dto/CheckUpdateModel.cs index 3fba51fc..a231ccf3 100644 --- a/v2rayN/ServiceLib/Models/Dto/CheckUpdateModel.cs +++ b/v2rayN/ServiceLib/Models/Dto/CheckUpdateModel.cs @@ -3,6 +3,8 @@ namespace ServiceLib.Models.Dto; public partial class CheckUpdateModel : ReactiveObject { public bool? IsSelected { get; set; } + public bool IsCheckPreRelease { get; set; } + public bool ShowCheckPreRelease { get; set; } public ECoreType? CoreType { get; set; } [Reactive] public partial string? Remarks { get; set; } public string? FileName { get; set; } diff --git a/v2rayN/ServiceLib/Services/UpdateService.cs b/v2rayN/ServiceLib/Services/UpdateService.cs index a1180f4f..3eee6c76 100644 --- a/v2rayN/ServiceLib/Services/UpdateService.cs +++ b/v2rayN/ServiceLib/Services/UpdateService.cs @@ -111,7 +111,7 @@ public partial class UpdateService(Config config, Func updat return await CheckUpdateAsync(downloadHandle, type, checkPreRelease, blProxy, cancellationToken); } - public async Task> CheckHasUpdateOnlyAll(bool preRelease, bool blProxy = true, CancellationToken cancellationToken = default) + public async Task> CheckHasUpdateOnlyAll(bool blProxy = true, CancellationToken cancellationToken = default) { var msgs = new List(); foreach (var type in CoreInfoManager.Instance.GetCheckUpdateCoreTypes()) @@ -121,6 +121,7 @@ public partial class UpdateService(Config config, Func updat continue; } + var preRelease = _config.CheckUpdateItem.CheckPreReleaseCoreTypes?.Contains(type.ToString()) ?? false; var result = await CheckHasUpdateOnly(type, preRelease, blProxy, cancellationToken); if (result.Success && result.Version != null) { diff --git a/v2rayN/ServiceLib/ViewModels/CheckUpdateViewModel.cs b/v2rayN/ServiceLib/ViewModels/CheckUpdateViewModel.cs index 18d1cb75..9c588268 100644 --- a/v2rayN/ServiceLib/ViewModels/CheckUpdateViewModel.cs +++ b/v2rayN/ServiceLib/ViewModels/CheckUpdateViewModel.cs @@ -12,7 +12,7 @@ public partial class CheckUpdateViewModel : MyReactiveObject public BulkObservableCollection CheckUpdateModels { get; } = []; public ReactiveCommand CheckUpdateCmd { get; } public ReactiveCommand CheckOnlyCmd { get; } - [Reactive] public partial bool EnableCheckPreReleaseUpdate { get; set; } + [Reactive] public partial bool EnableUpdateViaProxy { get; set; } public CheckUpdateViewModel() @@ -33,12 +33,8 @@ public partial class CheckUpdateViewModel : MyReactiveObject _ = UpdateView(_v2rayN, ex.Message); }); - EnableCheckPreReleaseUpdate = _config.CheckUpdateItem.CheckPreReleaseUpdate; EnableUpdateViaProxy = _config.CheckUpdateItem.UpdateViaProxy; - this.WhenAnyValue(x => x.EnableCheckPreReleaseUpdate) - .SubscribeAsync(async _ => await OnCheckPreReleaseUpdateChanged()); - this.WhenAnyValue(x => x.EnableUpdateViaProxy) .Subscribe(c => _ = OnUpdateViaProxyChanged()); @@ -73,6 +69,8 @@ public partial class CheckUpdateViewModel : MyReactiveObject return new() { IsSelected = false, + IsCheckPreRelease = false, + ShowCheckPreRelease = false, CoreType = coreType, IsGeoFile = false, Remarks = ResUI.menuCheckUpdate + $" ({ResUI.MsgNotSupport})", @@ -83,6 +81,8 @@ public partial class CheckUpdateViewModel : MyReactiveObject return new() { IsSelected = _config.CheckUpdateItem.SelectedCoreTypes?.Contains(coreType.ToString()) ?? true, + IsCheckPreRelease = _config.CheckUpdateItem.CheckPreReleaseCoreTypes?.Contains(coreType.ToString()) ?? false, + ShowCheckPreRelease = CoreInfoManager.Instance.GetCheckPreRelease(coreType, true), CoreType = coreType, IsGeoFile = false, Remarks = lastResult ?? ResUI.menuCheckUpdate, @@ -94,22 +94,14 @@ public partial class CheckUpdateViewModel : MyReactiveObject return new() { IsSelected = _config.CheckUpdateItem.SelectedCoreTypes?.Contains(_geo) ?? true, + IsCheckPreRelease = false, + ShowCheckPreRelease = false, CoreType = null, IsGeoFile = true, Remarks = ResUI.menuCheckUpdate, }; } - private async Task OnCheckPreReleaseUpdateChanged() - { - if (_config.CheckUpdateItem.CheckPreReleaseUpdate == EnableCheckPreReleaseUpdate) - { - return; - } - _config.CheckUpdateItem.CheckPreReleaseUpdate = EnableCheckPreReleaseUpdate; - await SaveSelectedCoreTypes(); - } - private async Task OnUpdateViaProxyChanged() { if (_config.CheckUpdateItem.UpdateViaProxy == EnableUpdateViaProxy) @@ -127,6 +119,11 @@ public partial class CheckUpdateViewModel : MyReactiveObject .Select(t => t.CoreTypeForStorage) .ToList(); + _config.CheckUpdateItem.CheckPreReleaseCoreTypes = + CheckUpdateModels.Where(t => t.IsCheckPreRelease == true) + .Select(t => t.CoreTypeForStorage) + .ToList(); + await ConfigHandler.SaveConfig(_config); } @@ -167,7 +164,7 @@ public partial class CheckUpdateViewModel : MyReactiveObject } var updateService = new UpdateService(_config, async (success, msg) => await Task.CompletedTask); - var result = await updateService.CheckHasUpdateOnly(item.CoreType.Value, EnableCheckPreReleaseUpdate, EnableUpdateViaProxy); + var result = await updateService.CheckHasUpdateOnly(item.CoreType.Value, item.IsCheckPreRelease, EnableUpdateViaProxy); if (result.Success && result.Version != null) { await UpdateView(item.CoreType, string.Format(ResUI.MsgCheckUpdateHasNewVersion, item.CoreType, result.Version)); @@ -213,15 +210,11 @@ public partial class CheckUpdateViewModel : MyReactiveObject await UpdateView(_v2rayN, ResUI.MsgNotSupport); continue; } - await CheckUpdateN(EnableCheckPreReleaseUpdate); - } - else if (item.CoreType is ECoreType.Xray or ECoreType.sing_box) - { - await CheckUpdateCore(item, EnableCheckPreReleaseUpdate); + await CheckUpdateN(item.IsCheckPreRelease); } else if (item.CoreType.HasValue) { - await CheckUpdateCore(item, false); + await CheckUpdateCore(item, item.IsCheckPreRelease); } } diff --git a/v2rayN/v2rayN.Desktop/Views/CheckUpdateView.axaml b/v2rayN/v2rayN.Desktop/Views/CheckUpdateView.axaml index 6e2909b3..a5638982 100644 --- a/v2rayN/v2rayN.Desktop/Views/CheckUpdateView.axaml +++ b/v2rayN/v2rayN.Desktop/Views/CheckUpdateView.axaml @@ -35,16 +35,6 @@ Margin="{StaticResource Margin4}" HorizontalAlignment="Left" /> - - -