improve:用户体验分级

This commit is contained in:
2025-07-26 16:22:55 +08:00
parent 58c399dcbe
commit a66037f886
3 changed files with 119 additions and 31 deletions
+77 -7
View File
@@ -20,7 +20,7 @@ namespace Ink_Canvas.Helpers
{
// 定义超时时间为10秒
private static readonly TimeSpan RequestTimeout = TimeSpan.FromSeconds(10);
private static string updatesFolderPath = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "AutoUpdate");
private static readonly string updatesFolderPath = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "AutoUpdate");
private static string statusFilePath = null;
// 线路组结构体(包含版本、下载、日志地址)
@@ -395,6 +395,47 @@ namespace Ink_Canvas.Helpers
}
}
// 通过GitHub API获取指定版本的Release信息
private static async Task<(string version, string downloadUrl, string releaseNotes, DateTime? releaseTime)> GetGithubReleaseByVersion(string targetVersion, UpdateChannel channel)
{
try
{
string apiUrl = channel == UpdateChannel.Beta
? "https://api.github.com/repos/InkCanvasForClass/community-beta/releases"
: "https://api.github.com/repos/InkCanvasForClass/community/releases";
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Add("User-Agent", "ICC-CE Auto Updater");
var response = await client.GetStringAsync(apiUrl);
var releases = JArray.Parse(response);
foreach (var release in releases)
{
string version = release["tag_name"]?.ToString();
if (version == targetVersion || version == $"v{targetVersion}" || version == $"V{targetVersion}")
{
string releaseNotes = release["body"]?.ToString();
string downloadUrl = release["assets"]?.First?["browser_download_url"]?.ToString();
// 解析发布时间
DateTime? releaseTime = null;
if (release["published_at"] != null && DateTime.TryParse(release["published_at"].ToString(), out DateTime parsedTime))
{
releaseTime = parsedTime;
}
return (version, downloadUrl, releaseNotes, releaseTime);
}
}
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"AutoUpdate | GitHub Releases API 获取版本 {targetVersion} 失败: {ex.Message}", LogHelper.LogType.Warning);
}
return (null, null, null, null);
}
// 通过GitHub API获取最新Release信息
private static async Task<(string version, string downloadUrl, string releaseNotes, DateTime? releaseTime)> GetLatestGithubRelease(UpdateChannel channel)
{
@@ -454,17 +495,23 @@ namespace Ink_Canvas.Helpers
if (remote > local || alwaysGetRemote)
{
LogHelper.WriteLogToFile($"AutoUpdate | 通过GitHub Releases API发现新版本: {apiVersion}");
// 检查是否应该根据用户优先级推送更新(版本修复功能不受限制)
if (!isVersionFix)
{
DateTime releaseTime = apiReleaseTime ?? DateTime.Now;
bool shouldPush = DeviceIdentifier.ShouldPushUpdate(apiVersion, releaseTime, true); // 明确标记为自动更新
// 尝试获取当前版本的发布时间
DateTime? currentVersionReleaseTime = await GetVersionReleaseTime(localVersion, channel);
bool shouldPush = DeviceIdentifier.ShouldPushUpdate(apiVersion, releaseTime, true, currentVersionReleaseTime); // 明确标记为自动更新
if (!shouldPush)
{
var priority = DeviceIdentifier.GetUpdatePriority();
var daysSinceRelease = (DateTime.Now - releaseTime).TotalDays;
LogHelper.WriteLogToFile($"AutoUpdate | 根据用户优先级({priority}),暂不推送更新 {apiVersion},发布时间: {releaseTime:yyyy-MM-dd HH:mm:ss},已过 {daysSinceRelease:F1} 天");
var daysBetweenVersions = currentVersionReleaseTime.HasValue
? (releaseTime - currentVersionReleaseTime.Value).TotalDays
: (DateTime.Now - releaseTime).TotalDays;
LogHelper.WriteLogToFile($"AutoUpdate | 根据用户优先级({priority}),暂不推送更新 {apiVersion},版本间隔: {daysBetweenVersions:F1} 天");
var group = (await GetAvailableLineGroupsOrdered(channel)).FirstOrDefault();
return (null, group, apiReleaseNotes); // 返回null表示不推送
}
@@ -506,11 +553,14 @@ namespace Ink_Canvas.Helpers
if (remote > local || alwaysGetRemote)
{
LogHelper.WriteLogToFile($"AutoUpdate | 发现新版本或强制获取: {remoteVersion}");
// 检查是否应该根据用户优先级推送更新(版本修复功能不受限制)
if (!isVersionFix)
{
bool shouldPush = DeviceIdentifier.ShouldPushUpdate(remoteVersion, DateTime.Now, true); // 明确标记为自动更新
// 尝试获取当前版本的发布时间
DateTime? currentVersionReleaseTime = await GetVersionReleaseTime(localVersion, channel);
bool shouldPush = DeviceIdentifier.ShouldPushUpdate(remoteVersion, DateTime.Now, true, currentVersionReleaseTime); // 明确标记为自动更新
if (!shouldPush)
{
var priority = DeviceIdentifier.GetUpdatePriority();
@@ -1501,6 +1551,26 @@ namespace Ink_Canvas.Helpers
}
}
/// <summary>
/// 获取指定版本的发布时间
/// </summary>
/// <param name="version">版本号</param>
/// <param name="channel">更新通道</param>
/// <returns>版本发布时间,如果获取失败则返回null</returns>
public static async Task<DateTime?> GetVersionReleaseTime(string version, UpdateChannel channel = UpdateChannel.Release)
{
try
{
var (_, _, _, releaseTime) = await GetGithubReleaseByVersion(version, channel);
return releaseTime;
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"AutoUpdate | 获取版本 {version} 发布时间失败: {ex.Message}", LogHelper.LogType.Warning);
return null;
}
}
/// <summary>
/// 启动手动指定版本的多线路多线程下载并自动安装(用于历史版本回滚等场景)
/// </summary>
+40 -22
View File
@@ -1747,10 +1747,11 @@ namespace Ink_Canvas.Helpers
/// 根据优先级决定是否应该推送更新(仅适用于自动更新,版本修复功能不受影响)
/// </summary>
/// <param name="updateVersion">更新版本号</param>
/// <param name="releaseTime">发布时间</param>
/// <param name="releaseTime">新版本发布时间</param>
/// <param name="isAutoUpdate">是否为自动更新检查(默认true,false表示版本修复)</param>
/// <param name="currentVersionReleaseTime">当前版本发布时间</param>
/// <returns>是否应该推送更新</returns>
public static bool ShouldPushUpdate(string updateVersion, DateTime releaseTime, bool isAutoUpdate = true)
public static bool ShouldPushUpdate(string updateVersion, DateTime releaseTime, bool isAutoUpdate = true, DateTime? currentVersionReleaseTime = null)
{
try
{
@@ -1769,17 +1770,27 @@ namespace Ink_Canvas.Helpers
var frequency = GetUsageFrequency();
var stats = LoadUsageStats();
// 计算发布时间到现在的天数
var daysSinceRelease = (DateTime.Now - releaseTime).TotalDays;
// 计算版本间的时间差
double daysBetweenVersions;
if (currentVersionReleaseTime.HasValue)
{
// 使用当前版本发布时间与新版本发布时间的差异
daysBetweenVersions = (releaseTime - currentVersionReleaseTime.Value).TotalDays;
}
else
{
// 如果没有当前版本发布时间,回退到使用新版本发布时间到现在的天数
daysBetweenVersions = (DateTime.Now - releaseTime).TotalDays;
}
// 计算最近活跃度(最后一次使用距今的天数)
var daysSinceLastUse = (DateTime.Now - stats.LastLaunchTime).TotalDays;
// 综合判断逻辑(仅适用于自动更新)
var shouldPush = ShouldPushUpdateComprehensive(priority, frequency, daysSinceRelease, daysSinceLastUse, stats, updateType);
var shouldPush = ShouldPushUpdateComprehensive(priority, frequency, daysBetweenVersions, daysSinceLastUse, stats, updateType);
LogHelper.WriteLogToFile($"DeviceIdentifier | 自动更新推送判断 - 版本: {updateVersion}, 类型: {updateType}, " +
$"优先级: {priority}, 频率: {frequency}, 发布天数: {daysSinceRelease:F1}, " +
$"优先级: {priority}, 频率: {frequency}, 版本间隔: {daysBetweenVersions:F1}, " +
$"最后使用: {daysSinceLastUse:F1}天前, 结果: {shouldPush}");
return shouldPush;
@@ -1844,8 +1855,15 @@ namespace Ink_Canvas.Helpers
/// <summary>
/// 综合时间和使用频率的自动更新推送判断逻辑(不影响版本修复)
/// </summary>
/// <param name="priority">用户更新优先级</param>
/// <param name="frequency">用户使用频率</param>
/// <param name="daysBetweenVersions">当前版本与新版本之间的天数差异</param>
/// <param name="daysSinceLastUse">距离最后使用的天数</param>
/// <param name="stats">使用统计数据</param>
/// <param name="updateType">更新类型</param>
/// <returns>是否应该推送更新</returns>
private static bool ShouldPushUpdateComprehensive(UpdatePriority priority, UsageFrequency frequency,
double daysSinceRelease, double daysSinceLastUse, UsageStats stats, UpdateType updateType)
double daysBetweenVersions, double daysSinceLastUse, UsageStats stats, UpdateType updateType)
{
// 考虑用户的总体使用模式
var isHeavyUser = stats.TotalUsageMinutes > 3000; // 超过50小时的重度用户
@@ -1860,12 +1878,12 @@ namespace Ink_Canvas.Helpers
// 热修复和重要更新优先推送
if (updateType == UpdateType.Hotfix)
{
return daysSinceRelease >= 1; // 热修复1天后推送
return daysBetweenVersions >= 1; // 热修复版本间隔1天后推送
}
// 但如果是重度用户,仍然要适当推送
var baseDelay = isHeavyUser ? 7 : 14;
return daysSinceRelease >= (baseDelay / urgencyMultiplier);
return daysBetweenVersions >= (baseDelay / urgencyMultiplier);
}
// 如果用户最近很活跃(3天内使用过)
@@ -1880,19 +1898,19 @@ namespace Ink_Canvas.Helpers
// 结合使用频率和优先级判断
if (frequency == UsageFrequency.High || isHeavyUser)
{
return daysSinceRelease >= Math.Max(0, 1 / urgencyMultiplier); // 高频用户优先推送
return daysBetweenVersions >= Math.Max(0, 1 / urgencyMultiplier); // 高频用户优先推送
}
switch (priority)
{
case UpdatePriority.High:
return daysSinceRelease >= Math.Max(0, 1 / urgencyMultiplier);
return daysBetweenVersions >= Math.Max(0, 1 / urgencyMultiplier);
case UpdatePriority.Medium:
return daysSinceRelease >= Math.Max(1, 2 / urgencyMultiplier);
return daysBetweenVersions >= Math.Max(1, 2 / urgencyMultiplier);
case UpdatePriority.Low:
return daysSinceRelease >= Math.Max(2, 3 / urgencyMultiplier);
return daysBetweenVersions >= Math.Max(2, 3 / urgencyMultiplier);
}
}
@@ -1902,25 +1920,25 @@ namespace Ink_Canvas.Helpers
// 热修复优先推送
if (updateType == UpdateType.Hotfix)
{
return daysSinceRelease >= 1;
return daysBetweenVersions >= 1;
}
// 频繁用户优先推送
if (isFrequentUser && frequency == UsageFrequency.High)
{
return daysSinceRelease >= Math.Max(1, 2 / urgencyMultiplier);
return daysBetweenVersions >= Math.Max(1, 2 / urgencyMultiplier);
}
switch (priority)
{
case UpdatePriority.High:
return daysSinceRelease >= Math.Max(1, 2 / urgencyMultiplier);
return daysBetweenVersions >= Math.Max(1, 2 / urgencyMultiplier);
case UpdatePriority.Medium:
return daysSinceRelease >= Math.Max(2, 4 / urgencyMultiplier);
return daysBetweenVersions >= Math.Max(2, 4 / urgencyMultiplier);
case UpdatePriority.Low:
return daysSinceRelease >= Math.Max(4, 7 / urgencyMultiplier);
return daysBetweenVersions >= Math.Max(4, 7 / urgencyMultiplier);
}
}
@@ -1931,16 +1949,16 @@ namespace Ink_Canvas.Helpers
switch (priority)
{
case UpdatePriority.High:
return daysSinceRelease >= Math.Max(2, 3 * delayMultiplier / urgencyMultiplier);
return daysBetweenVersions >= Math.Max(2, 3 * delayMultiplier / urgencyMultiplier);
case UpdatePriority.Medium:
return daysSinceRelease >= Math.Max(4, 7 * delayMultiplier / urgencyMultiplier);
return daysBetweenVersions >= Math.Max(4, 7 * delayMultiplier / urgencyMultiplier);
case UpdatePriority.Low:
return daysSinceRelease >= Math.Max(7, 14 * delayMultiplier / urgencyMultiplier);
return daysBetweenVersions >= Math.Max(7, 14 * delayMultiplier / urgencyMultiplier);
default:
return daysSinceRelease >= 7;
return daysBetweenVersions >= 7;
}
}
+2 -2
View File
@@ -49,5 +49,5 @@ using System.Windows;
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.7.2.1")]
[assembly: AssemblyFileVersion("1.7.2.1")]
[assembly: AssemblyVersion("1.7.1.14")]
[assembly: AssemblyFileVersion("1.7.1.14")]