Improve CheckUpdateModel

This commit is contained in:
2dust 2026-05-18 17:32:07 +08:00
parent 460a674ebc
commit f7206f3405
14 changed files with 113 additions and 38 deletions

View file

@ -48,6 +48,13 @@ public sealed class AppManager
} }
} }
public Dictionary<ECoreType, string> LastCheckUpdateResults { get; set; } = new();
public void SetLastCheckUpdateResult(ECoreType coreType, string result)
{
LastCheckUpdateResults[coreType] = result;
}
#endregion Property #endregion Property
#region App #region App

View file

@ -3,8 +3,10 @@ namespace ServiceLib.Models.Dto;
public class CheckUpdateModel : ReactiveObject public class CheckUpdateModel : ReactiveObject
{ {
public bool? IsSelected { get; set; } public bool? IsSelected { get; set; }
public string? CoreType { get; set; } public ECoreType? CoreType { get; set; }
[Reactive] public string? Remarks { get; set; } [Reactive] public string? Remarks { get; set; }
public string? FileName { get; set; } public string? FileName { get; set; }
public bool? IsFinished { get; set; } public bool? IsFinished { get; set; }
public bool IsGeoFile { get; set; }
public string CoreTypeForStorage => IsGeoFile ? "GeoFiles" : (CoreType?.ToString() ?? "");
} }

View file

@ -2058,6 +2058,15 @@ namespace ServiceLib.Resx {
} }
} }
/// <summary>
/// 查找类似 Not Support 的本地化字符串。
/// </summary>
public static string MsgNotSupport {
get {
return ResourceManager.GetString("MsgNotSupport", resourceCulture);
}
}
/// <summary> /// <summary>
/// 查找类似 Not support protocol &apos;{0}&apos; 的本地化字符串。 /// 查找类似 Not support protocol &apos;{0}&apos; 的本地化字符串。
/// </summary> /// </summary>

View file

@ -1737,4 +1737,7 @@ The "Get Certificate" action may fail if a self-signed certificate is used or if
<data name="menuCheckOnly" xml:space="preserve"> <data name="menuCheckOnly" xml:space="preserve">
<value>Only Check</value> <value>Only Check</value>
</data> </data>
<data name="MsgNotSupport" xml:space="preserve">
<value>Not Support</value>
</data>
</root> </root>

View file

@ -1734,4 +1734,7 @@ The "Get Certificate" action may fail if a self-signed certificate is used or if
<data name="menuCheckOnly" xml:space="preserve"> <data name="menuCheckOnly" xml:space="preserve">
<value>Only Check</value> <value>Only Check</value>
</data> </data>
<data name="MsgNotSupport" xml:space="preserve">
<value>Not Support</value>
</data>
</root> </root>

View file

@ -1737,4 +1737,7 @@ The "Get Certificate" action may fail if a self-signed certificate is used or if
<data name="menuCheckOnly" xml:space="preserve"> <data name="menuCheckOnly" xml:space="preserve">
<value>Only Check</value> <value>Only Check</value>
</data> </data>
<data name="MsgNotSupport" xml:space="preserve">
<value>Not Support</value>
</data>
</root> </root>

View file

@ -1737,4 +1737,7 @@ The "Get Certificate" action may fail if a self-signed certificate is used or if
<data name="menuCheckOnly" xml:space="preserve"> <data name="menuCheckOnly" xml:space="preserve">
<value>Only Check</value> <value>Only Check</value>
</data> </data>
<data name="MsgNotSupport" xml:space="preserve">
<value>Not Support</value>
</data>
</root> </root>

View file

@ -1737,4 +1737,7 @@
<data name="menuCheckOnly" xml:space="preserve"> <data name="menuCheckOnly" xml:space="preserve">
<value>Only Check</value> <value>Only Check</value>
</data> </data>
<data name="MsgNotSupport" xml:space="preserve">
<value>Not Support</value>
</data>
</root> </root>

View file

@ -1734,4 +1734,7 @@
<data name="menuCheckOnly" xml:space="preserve"> <data name="menuCheckOnly" xml:space="preserve">
<value>仅检查</value> <value>仅检查</value>
</data> </data>
<data name="MsgNotSupport" xml:space="preserve">
<value>不支持</value>
</data>
</root> </root>

View file

@ -1734,4 +1734,7 @@
<data name="menuCheckOnly" xml:space="preserve"> <data name="menuCheckOnly" xml:space="preserve">
<value>僅檢查</value> <value>僅檢查</value>
</data> </data>
<data name="MsgNotSupport" xml:space="preserve">
<value>不支援</value>
</data>
</root> </root>

View file

@ -104,7 +104,7 @@ public class UpdateService(Config config, Func<bool, string, Task> updateFunc)
{ {
if (!CoreInfoManager.Instance.IsCheckUpdateSupported(type)) if (!CoreInfoManager.Instance.IsCheckUpdateSupported(type))
{ {
return new UpdateResult(false, "Not Support"); return new UpdateResult(false, ResUI.MsgNotSupport);
} }
var downloadHandle = new DownloadService(); var downloadHandle = new DownloadService();
@ -120,7 +120,13 @@ public class UpdateService(Config config, Func<bool, string, Task> updateFunc)
var result = await CheckHasUpdateOnly(type, preRelease); var result = await CheckHasUpdateOnly(type, preRelease);
if (result.Success && result.Version != null) if (result.Success && result.Version != null)
{ {
msgs.Add(string.Format(ResUI.MsgCheckUpdateHasNewVersion, type, result.Version)); var msg = string.Format(ResUI.MsgCheckUpdateHasNewVersion, type, result.Version);
msgs.Add(msg);
AppManager.Instance.SetLastCheckUpdateResult(type, msg);
}
else
{
AppManager.Instance.SetLastCheckUpdateResult(type, result.Msg);
} }
} }
return msgs; return msgs;

View file

@ -3,7 +3,7 @@ namespace ServiceLib.ViewModels;
public class CheckUpdateViewModel : MyReactiveObject public class CheckUpdateViewModel : MyReactiveObject
{ {
private const string _geo = "GeoFiles"; private const string _geo = "GeoFiles";
private readonly string _v2rayN = ECoreType.v2rayN.ToString(); private readonly ECoreType _v2rayN = ECoreType.v2rayN;
private List<CheckUpdateModel> _lstUpdated = []; private List<CheckUpdateModel> _lstUpdated = [];
private static readonly string _tag = "CheckUpdateViewModel"; private static readonly string _tag = "CheckUpdateViewModel";
@ -47,13 +47,13 @@ public class CheckUpdateViewModel : MyReactiveObject
foreach (var type in CoreInfoManager.Instance.GetCheckUpdateCoreTypes()) foreach (var type in CoreInfoManager.Instance.GetCheckUpdateCoreTypes())
{ {
CheckUpdateModels.Add(GetCheckUpdateModel(type.ToString())); CheckUpdateModels.Add(GetCheckUpdateModel(type));
} }
CheckUpdateModels.Add(GetCheckUpdateModel(_geo)); CheckUpdateModels.Add(GetGeoFileCheckUpdateModel());
} }
private CheckUpdateModel GetCheckUpdateModel(string coreType) private CheckUpdateModel GetCheckUpdateModel(ECoreType coreType)
{ {
if (coreType == _v2rayN && Utils.IsPackagedInstall()) if (coreType == _v2rayN && Utils.IsPackagedInstall())
{ {
@ -61,21 +61,38 @@ public class CheckUpdateViewModel : MyReactiveObject
{ {
IsSelected = false, IsSelected = false,
CoreType = coreType, CoreType = coreType,
Remarks = ResUI.menuCheckUpdate + " (Not Support)", IsGeoFile = false,
Remarks = ResUI.menuCheckUpdate + $" ({ResUI.MsgNotSupport})",
}; };
} }
AppManager.Instance.LastCheckUpdateResults.TryGetValue(coreType, out var lastResult);
return new() return new()
{ {
IsSelected = _config.CheckUpdateItem.SelectedCoreTypes?.Contains(coreType) ?? true, IsSelected = _config.CheckUpdateItem.SelectedCoreTypes?.Contains(coreType.ToString()) ?? true,
CoreType = coreType, CoreType = coreType,
IsGeoFile = false,
Remarks = lastResult ?? ResUI.menuCheckUpdate,
};
}
private CheckUpdateModel GetGeoFileCheckUpdateModel()
{
return new()
{
IsSelected = _config.CheckUpdateItem.SelectedCoreTypes?.Contains(_geo) ?? true,
CoreType = null,
IsGeoFile = true,
Remarks = ResUI.menuCheckUpdate, Remarks = ResUI.menuCheckUpdate,
}; };
} }
private async Task SaveSelectedCoreTypes() private async Task SaveSelectedCoreTypes()
{ {
_config.CheckUpdateItem.SelectedCoreTypes = CheckUpdateModels.Where(t => t.IsSelected == true).Select(t => t.CoreType ?? "").ToList(); _config.CheckUpdateItem.SelectedCoreTypes = CheckUpdateModels
.Where(t => t.IsSelected == true)
.Select(t => t.CoreTypeForStorage)
.ToList();
await ConfigHandler.SaveConfig(_config); await ConfigHandler.SaveConfig(_config);
} }
@ -102,23 +119,24 @@ public class CheckUpdateViewModel : MyReactiveObject
} }
await UpdateView(item.CoreType, "..."); await UpdateView(item.CoreType, "...");
if (item.CoreType == _geo)
if (item.IsGeoFile || item.CoreType == null)
{ {
await UpdateView(item.CoreType, ResUI.menuCheckOnly + " (Not Support)"); await UpdateView(item.CoreType, ResUI.menuCheckOnly + $" ({ResUI.MsgNotSupport})");
continue; continue;
} }
if (!Enum.TryParse<ECoreType>(item.CoreType, out var type)) if (item.CoreType == null)
{ {
await UpdateView(item.CoreType, "Not Support"); await UpdateView(item.CoreType, ResUI.MsgNotSupport);
continue; continue;
} }
var updateService = new UpdateService(_config, async (success, msg) => await Task.CompletedTask); var updateService = new UpdateService(_config, async (success, msg) => await Task.CompletedTask);
var result = await updateService.CheckHasUpdateOnly(type, EnableCheckPreReleaseUpdate); var result = await updateService.CheckHasUpdateOnly(item.CoreType.Value, EnableCheckPreReleaseUpdate);
if (result.Success && result.Version != null) if (result.Success && result.Version != null)
{ {
await UpdateView(item.CoreType, string.Format(ResUI.MsgCheckUpdateHasNewVersion, type, result.Version)); await UpdateView(item.CoreType, string.Format(ResUI.MsgCheckUpdateHasNewVersion, item.CoreType, result.Version));
} }
else else
{ {
@ -130,8 +148,14 @@ public class CheckUpdateViewModel : MyReactiveObject
private async Task CheckUpdateTask() private async Task CheckUpdateTask()
{ {
_lstUpdated.Clear(); _lstUpdated.Clear();
_lstUpdated = CheckUpdateModels.Where(x => x.IsSelected == true) _lstUpdated = CheckUpdateModels
.Select(x => new CheckUpdateModel() { CoreType = x.CoreType }).ToList(); .Where(x => x.IsSelected == true)
.Select(x => new CheckUpdateModel()
{
CoreType = x.CoreType,
IsGeoFile = x.IsGeoFile
})
.ToList();
await SaveSelectedCoreTypes(); await SaveSelectedCoreTypes();
for (var k = CheckUpdateModels.Count - 1; k >= 0; k--) for (var k = CheckUpdateModels.Count - 1; k >= 0; k--)
@ -143,7 +167,8 @@ public class CheckUpdateViewModel : MyReactiveObject
} }
await UpdateView(item.CoreType, "..."); await UpdateView(item.CoreType, "...");
if (item.CoreType == _geo)
if (item.IsGeoFile)
{ {
await CheckUpdateGeo(); await CheckUpdateGeo();
} }
@ -151,16 +176,16 @@ public class CheckUpdateViewModel : MyReactiveObject
{ {
if (Utils.IsPackagedInstall()) if (Utils.IsPackagedInstall())
{ {
await UpdateView(_v2rayN, "Not Support"); await UpdateView(_v2rayN, ResUI.MsgNotSupport);
continue; continue;
} }
await CheckUpdateN(EnableCheckPreReleaseUpdate); await CheckUpdateN(EnableCheckPreReleaseUpdate);
} }
else if (item.CoreType == ECoreType.Xray.ToString()) else if (item.CoreType == ECoreType.Xray)
{ {
await CheckUpdateCore(item, EnableCheckPreReleaseUpdate); await CheckUpdateCore(item, EnableCheckPreReleaseUpdate);
} }
else else if (item.CoreType.HasValue)
{ {
await CheckUpdateCore(item, false); await CheckUpdateCore(item, false);
} }
@ -169,7 +194,7 @@ public class CheckUpdateViewModel : MyReactiveObject
await UpdateFinished(); await UpdateFinished();
} }
private void UpdatedPlusPlus(string coreType, string fileName) private void UpdatedPlusPlus(ECoreType? coreType, string fileName)
{ {
var item = _lstUpdated.FirstOrDefault(x => x.CoreType == coreType); var item = _lstUpdated.FirstOrDefault(x => x.CoreType == coreType);
if (item == null) if (item == null)
@ -187,14 +212,14 @@ public class CheckUpdateViewModel : MyReactiveObject
{ {
async Task _updateUI(bool success, string msg) async Task _updateUI(bool success, string msg)
{ {
await UpdateView(_geo, msg); await UpdateView(null, msg);
if (success) if (success)
{ {
UpdatedPlusPlus(_geo, ""); UpdatedPlusPlus(null, "");
} }
} }
await new UpdateService(_config, _updateUI).UpdateGeoFileAll() await new UpdateService(_config, _updateUI).UpdateGeoFileAll()
.ContinueWith(t => UpdatedPlusPlus(_geo, "")); .ContinueWith(t => UpdatedPlusPlus(null, ""));
} }
private async Task CheckUpdateN(bool preRelease) private async Task CheckUpdateN(bool preRelease)
@ -220,13 +245,15 @@ public class CheckUpdateViewModel : MyReactiveObject
if (success) if (success)
{ {
await UpdateView(model.CoreType, ResUI.MsgUpdateV2rayCoreSuccessfullyMore); await UpdateView(model.CoreType, ResUI.MsgUpdateV2rayCoreSuccessfullyMore);
UpdatedPlusPlus(model.CoreType, msg); UpdatedPlusPlus(model.CoreType, msg);
} }
} }
var type = (ECoreType)Enum.Parse(typeof(ECoreType), model.CoreType);
await new UpdateService(_config, _updateUI).CheckUpdateCore(type, preRelease) if (model.CoreType.HasValue)
.ContinueWith(t => UpdatedPlusPlus(model.CoreType, "")); {
await new UpdateService(_config, _updateUI).CheckUpdateCore(model.CoreType.Value, preRelease)
.ContinueWith(t => UpdatedPlusPlus(model.CoreType, ""));
}
} }
private async Task UpdateFinished() private async Task UpdateFinished()
@ -302,7 +329,7 @@ public class CheckUpdateViewModel : MyReactiveObject
{ {
foreach (var item in _lstUpdated) foreach (var item in _lstUpdated)
{ {
if (item.FileName.IsNullOrEmpty()) if (item.FileName.IsNullOrEmpty() || item.IsGeoFile)
{ {
continue; continue;
} }
@ -312,7 +339,9 @@ public class CheckUpdateViewModel : MyReactiveObject
{ {
continue; continue;
} }
var toPath = Utils.GetBinPath("", item.CoreType);
var coreTypeStr = item.CoreType?.ToString() ?? "";
var toPath = Utils.GetBinPath("", coreTypeStr);
if (fileName.Contains(".tar.gz")) if (fileName.Contains(".tar.gz"))
{ {
@ -329,7 +358,7 @@ public class CheckUpdateViewModel : MyReactiveObject
} }
else if (fileName.Contains(".gz")) else if (fileName.Contains(".gz"))
{ {
FileUtils.DecompressFile(fileName, toPath, item.CoreType); FileUtils.DecompressFile(fileName, toPath, coreTypeStr);
} }
else else
{ {
@ -341,7 +370,7 @@ public class CheckUpdateViewModel : MyReactiveObject
var filesList = new DirectoryInfo(toPath).GetFiles().Select(u => u.FullName).ToList(); var filesList = new DirectoryInfo(toPath).GetFiles().Select(u => u.FullName).ToList();
foreach (var file in filesList) foreach (var file in filesList)
{ {
await Utils.SetLinuxChmod(Path.Combine(toPath, item.CoreType.ToLower())); await Utils.SetLinuxChmod(Path.Combine(toPath, coreTypeStr.ToLower()));
} }
} }
@ -354,11 +383,12 @@ public class CheckUpdateViewModel : MyReactiveObject
} }
} }
private async Task UpdateView(string coreType, string msg) private async Task UpdateView(ECoreType? coreType, string msg)
{ {
var item = new CheckUpdateModel() var item = new CheckUpdateModel()
{ {
CoreType = coreType, CoreType = coreType,
IsGeoFile = coreType == null,
Remarks = msg, Remarks = msg,
}; };
@ -372,7 +402,7 @@ public class CheckUpdateViewModel : MyReactiveObject
public async Task UpdateViewResult(CheckUpdateModel model) public async Task UpdateViewResult(CheckUpdateModel model)
{ {
var found = CheckUpdateModels.FirstOrDefault(t => t.CoreType == model.CoreType); var found = CheckUpdateModels.FirstOrDefault(t => t.CoreType == model.CoreType && t.IsGeoFile == model.IsGeoFile);
if (found == null) if (found == null)
{ {
return; return;

View file

@ -76,7 +76,7 @@
Grid.Column="1" Grid.Column="1"
HorizontalAlignment="Left" HorizontalAlignment="Left"
VerticalAlignment="Center" VerticalAlignment="Center"
Text="{Binding CoreType}" /> Text="{Binding CoreTypeForStorage}" />
<TextBlock <TextBlock
Grid.Column="2" Grid.Column="2"
HorizontalAlignment="Left" HorizontalAlignment="Left"

View file

@ -84,7 +84,7 @@
<TextBlock <TextBlock
Grid.Column="1" Grid.Column="1"
Style="{StaticResource ListItemTitle}" Style="{StaticResource ListItemTitle}"
Text="{Binding CoreType}" /> Text="{Binding CoreTypeForStorage}" />
<TextBlock <TextBlock
Grid.Column="2" Grid.Column="2"
Style="{StaticResource ListItemSubTitle}" Style="{StaticResource ListItemSubTitle}"