mirror of
https://github.com/babalae/better-genshin-impact.git
synced 2026-05-17 09:26:50 +08:00
* feat: 实现启动时自动更新已订阅脚本及多仓库分离存储
- ScriptConfig: 新增 AutoUpdateSubscribedScripts 配置项
- ScriptRepoUpdater: 动态 CenterRepoPath, 按仓库URL分离存储
- 内容重合度检测(Jaccard系数)判断仓库异同
- URL→文件夹名持久化映射(repo_folder_mapping.json)
- repo_updated.json 存放于各自仓库文件夹内
- AutoUpdateSubscribedScripts 启动时自动更新订阅脚本
- 静默同步仓库、渠道URL解析、检出更新脚本
- RepoWebBridge: 使用动态路径, 辅助方法改为 internal
- MainWindowViewModel: 启动时调用自动更新
* feat: 基于内容重合度的导入zip仓库
* perf: 合并默认仓库url映射
* perf: 清理兼容字段
* perf: 添加线程锁以避免并发调用
* fix: 缓存FolderMapping、修复重合度异常返回值、目录扫描异常隔离、移除未使用变量
* perf: 优化更新流程
* perf: 内存缓存添加锁
* fix: 修复更新状态逻辑,确保克隆失败时不标记为已更新
* perf: 文件夹映射先写磁盘再写缓存
* refactor: 简化生成唯一文件夹名称的方法,移除不必要的参数
* fix: ResetRepo加写锁并清理URL映射条目
* perf: 优化重合度算法
* docs: 更新注释
* fix: 仅重置实际更新成功的脚本的 hasUpdate 标记
* feat: 手动一键更新按钮
* feat: 订阅路径迁移至独立文件存储并简化更新逻辑
- 订阅数据从 config.json 迁移到 User/subscriptions/{repo}.json 独立文件
- 添加 ReaderWriterLockSlim 保护订阅文件并发读写
- 使用 System.Text.Json + ConfigService.JsonOptions 序列化
- 新增 RepoWebBridge.GetSubscribedScriptPaths() 桥接方法
- 启动时自动从旧 config.json 迁移订阅数据到独立文件
- 合并手动/自动更新为 UpdateAllSubscribedScriptsCore 共用核心
- 移除 hasUpdate 检查,直接全量更新所有订阅脚本
- 移除冗余 logPrefix 参数
* refactor: 简化启动时自动更新调用
- 移除 Task.Run + try-catch 包装,异常处理已内置于方法中
- 直接使用 fire-and-forget 异步调用
* fix: 订阅目录命名改为 PascalCase (Subscriptions)
* refactor: 移除死代码和冗余中间层方法
* fix: ReadSubscriptionFile 异常时记录日志避免订阅数据静默丢失
* fix: 进度条改为Indeterminate模式、异常日志补全、订阅去重、迁移批量写入、锁注释
* refactor: 提取 ReadFolderMappingFromDisk 消除映射方法嵌套 try
* fix: 补全静态方法异常日志、WriteSubscriptionFile异常保护、ManualUpdate注释
* fix: ManualUpdateSubscribedScripts 加 try-catch 兜底并提示用户重置仓库
* fix: Dialog打开时检测后台自动更新状态,自动禁用按钮并显示进度提示
- ScriptRepoUpdater 新增 IsAutoUpdating 标志和 AutoUpdateStateChanged 事件
- ScriptRepoWindow 订阅事件,自动更新期间显示进度条、禁用所有操作按钮并 Toast 提示
- 更新仓库/重置仓库按钮也加上 IsEnabled 绑定 IsUpdating
* fix: 将自动更新调用包裹在 Task.Run 中避免 UI 线程阻塞
AutoUpdateSubscribedScripts 的 await 后续会被 WPF SynchronizationContext
调度回 UI 线程,导致大量 Git checkout 和文件 IO 操作阻塞界面。
用 Task.Run 确保整个流程在线程池执行。
* fix: 进度条分离 IsProgressIndeterminate 属性,按操作类型正确切换确定/不确定模式
* refactor: 消除 pathing 展开重复逻辑、用布尔字段替换字符串比较追踪状态来源、补全锁注释、统一日志方式
* fix: ExpandTopLevelPaths 泛化展开所有 PathMapper 顶层 key 防止误删用户目录,迁移移入锁内
* fix: 命令行启动配置组/一条龙前先等待自动更新订阅脚本完成
* feat: 添加命令行启动时是否先自动更新选项
* fix: 修复按钮位置
520 lines
18 KiB
C#
520 lines
18 KiB
C#
using BetterGenshinImpact.Core.Config;
|
||
using BetterGenshinImpact.Core.Recognition.OCR;
|
||
using BetterGenshinImpact.Core.Script;
|
||
using BetterGenshinImpact.GameTask;
|
||
using BetterGenshinImpact.GameTask.UseRedeemCode;
|
||
using BetterGenshinImpact.Helpers;
|
||
using BetterGenshinImpact.Helpers.Ui;
|
||
using BetterGenshinImpact.Model;
|
||
using BetterGenshinImpact.Service.Interface;
|
||
using BetterGenshinImpact.View;
|
||
using BetterGenshinImpact.View.Pages;
|
||
using BetterGenshinImpact.View.Windows;
|
||
using BetterGenshinImpact.ViewModel.Pages;
|
||
using CommunityToolkit.Mvvm.ComponentModel;
|
||
using CommunityToolkit.Mvvm.Input;
|
||
using DeviceId;
|
||
using Fischless.GameCapture.BitBlt;
|
||
using Microsoft.Extensions.Logging;
|
||
using OpenCvSharp;
|
||
using System;
|
||
using System.Collections.Generic;
|
||
using System.ComponentModel;
|
||
using System.Diagnostics;
|
||
using System.Diagnostics.CodeAnalysis;
|
||
using System.IO;
|
||
using System.Linq;
|
||
using System.Net.Http;
|
||
using System.Net.Http.Json;
|
||
using System.Threading.Tasks;
|
||
using System.Windows;
|
||
using System.Windows.Media;
|
||
using BetterGenshinImpact.Helpers.Http;
|
||
using BetterGenshinImpact.ViewModel.Windows;
|
||
using Wpf.Ui;
|
||
using Wpf.Ui.Controls;
|
||
|
||
using BetterGenshinImpact.Platform.Wine;
|
||
|
||
namespace BetterGenshinImpact.ViewModel;
|
||
|
||
public partial class MainWindowViewModel : ObservableObject, IViewModel
|
||
{
|
||
private readonly ILogger<MainWindowViewModel> _logger;
|
||
private readonly IConfigService _configService;
|
||
private readonly INavigationService _navigationService;
|
||
public string Title => $"BetterGI · 更好的原神 · {Global.Version}{(RuntimeHelper.IsDebug ? " · Dev" : string.Empty)}";
|
||
|
||
[ObservableProperty] private bool _isVisible = true;
|
||
|
||
[ObservableProperty] private WindowState _windowState = WindowState.Normal;
|
||
|
||
[ObservableProperty] private WindowBackdropType _currentBackdropType = WindowBackdropType.Auto;
|
||
|
||
[ObservableProperty] private bool _isWin11Later = OsVersionHelper.IsWindows11_OrGreater;
|
||
|
||
[ObservableProperty] private Brush _redeemCodeButtonForeground = Brushes.White;
|
||
|
||
private string? _redeemCodeUpdateNewVersion;
|
||
|
||
private bool _firstActivated = true;
|
||
|
||
public AllConfig Config { get; set; }
|
||
|
||
public MainWindowViewModel(INavigationService navigationService, IConfigService configService)
|
||
{
|
||
_navigationService = navigationService;
|
||
_configService = configService;
|
||
Config = _configService.Get();
|
||
_logger = App.GetLogger<MainWindowViewModel>();
|
||
}
|
||
|
||
[RelayCommand]
|
||
private async Task OnActivated()
|
||
{
|
||
// 首次激活时不处理
|
||
if (_firstActivated)
|
||
{
|
||
_firstActivated = false;
|
||
return;
|
||
}
|
||
|
||
// 激活时候获取剪切板内容 用于脚本导入、兑换码自动兑换等
|
||
try
|
||
{
|
||
if (Clipboard.ContainsText())
|
||
{
|
||
string clipboardText = Clipboard.GetText();
|
||
|
||
if (string.IsNullOrEmpty(clipboardText)
|
||
|| clipboardText.Length > 1000)
|
||
{
|
||
return;
|
||
}
|
||
|
||
|
||
// 1. 导入脚本
|
||
await ScriptRepoUpdater.Instance.ImportScriptFromClipboard(clipboardText);
|
||
// 2. 自动兑换码
|
||
await RedeemCodeManager.ImportFromClipboard(clipboardText);
|
||
}
|
||
}
|
||
catch
|
||
{
|
||
// 忽略异常,可能是因为没有权限访问剪切板
|
||
}
|
||
}
|
||
|
||
[RelayCommand]
|
||
private void OnHide()
|
||
{
|
||
IsVisible = false;
|
||
}
|
||
|
||
[RelayCommand]
|
||
private void OnSwitchBackdrop()
|
||
{
|
||
// Windows11_22523以下版本支持基本深浅主题切换,以上版本额外还支持Mica/Acrylic主题切换
|
||
if (!OsVersionHelper.IsWindows11_22523_OrGreater)
|
||
{
|
||
Config.CommonConfig.CurrentThemeType = Config.CommonConfig.CurrentThemeType switch
|
||
{
|
||
ThemeType.DarkNone => ThemeType.LightNone,
|
||
ThemeType.LightNone => ThemeType.DarkNone,
|
||
_ => ThemeType.DarkNone
|
||
};
|
||
}
|
||
else
|
||
{
|
||
Config.CommonConfig.CurrentThemeType = Config.CommonConfig.CurrentThemeType switch
|
||
{
|
||
ThemeType.DarkMica => ThemeType.DarkAcrylic,
|
||
ThemeType.DarkAcrylic => ThemeType.LightMica,
|
||
ThemeType.LightMica => ThemeType.LightAcrylic,
|
||
ThemeType.LightAcrylic => ThemeType.DarkMica,
|
||
_ => ThemeType.DarkMica
|
||
};
|
||
}
|
||
|
||
ApplyTheme(Config.CommonConfig.CurrentThemeType);
|
||
_configService.Save();
|
||
}
|
||
|
||
private void ApplyTheme(ThemeType themeType)
|
||
{
|
||
var originalThemeType = themeType;
|
||
|
||
// 根据主题类型设置应用程序主题(深色/浅色)和背景效果类型(Mica/Acrylic/None)
|
||
if (!OsVersionHelper.IsWindows11_22523_OrGreater)
|
||
{
|
||
// 22523以下版本只支持深浅色切换,修正背景材质为纯色
|
||
if (themeType == ThemeType.DarkMica || themeType == ThemeType.DarkAcrylic)
|
||
{
|
||
themeType = ThemeType.DarkNone;
|
||
}
|
||
else if (themeType == ThemeType.LightMica || themeType == ThemeType.LightAcrylic)
|
||
{
|
||
themeType = ThemeType.LightNone;
|
||
}
|
||
}
|
||
|
||
// 如果主题类型被修正,更新配置并保存
|
||
if (themeType != originalThemeType)
|
||
{
|
||
Config.CommonConfig.CurrentThemeType = themeType;
|
||
_configService.Save();
|
||
_logger.LogInformation($"主题类型已从 {originalThemeType} 修正为 {themeType},因为当前系统不支持该主题效果");
|
||
}
|
||
|
||
if (WinePlatformAddon.IsRunningOnWine)
|
||
{
|
||
// Wine 平台下不应用主题
|
||
_logger.LogInformation("检测到运行在 Wine 平台,跳过主题应用");
|
||
return;
|
||
}
|
||
|
||
switch (themeType)
|
||
{
|
||
case ThemeType.DarkNone:
|
||
Wpf.Ui.Appearance.ApplicationThemeManager.Apply(Wpf.Ui.Appearance.ApplicationTheme.Dark);
|
||
CurrentBackdropType = WindowBackdropType.None;
|
||
break;
|
||
case ThemeType.DarkMica:
|
||
Wpf.Ui.Appearance.ApplicationThemeManager.Apply(Wpf.Ui.Appearance.ApplicationTheme.Dark);
|
||
CurrentBackdropType = WindowBackdropType.Mica;
|
||
break;
|
||
case ThemeType.DarkAcrylic:
|
||
Wpf.Ui.Appearance.ApplicationThemeManager.Apply(Wpf.Ui.Appearance.ApplicationTheme.Dark);
|
||
CurrentBackdropType = WindowBackdropType.Acrylic;
|
||
break;
|
||
case ThemeType.LightNone:
|
||
Wpf.Ui.Appearance.ApplicationThemeManager.Apply(Wpf.Ui.Appearance.ApplicationTheme.Light);
|
||
CurrentBackdropType = WindowBackdropType.None;
|
||
break;
|
||
case ThemeType.LightMica:
|
||
Wpf.Ui.Appearance.ApplicationThemeManager.Apply(Wpf.Ui.Appearance.ApplicationTheme.Light);
|
||
CurrentBackdropType = WindowBackdropType.Mica;
|
||
break;
|
||
case ThemeType.LightAcrylic:
|
||
Wpf.Ui.Appearance.ApplicationThemeManager.Apply(Wpf.Ui.Appearance.ApplicationTheme.Light);
|
||
CurrentBackdropType = WindowBackdropType.Acrylic;
|
||
break;
|
||
}
|
||
|
||
// 立即应用主题到当前窗口
|
||
if (Application.Current.MainWindow != null)
|
||
{
|
||
WindowHelper.ApplyThemeToWindow(Application.Current.MainWindow, themeType);
|
||
}
|
||
|
||
// 根据当前主题更新兑换码按钮的默认前景色(若无更新高亮)
|
||
if (_redeemCodeUpdateNewVersion == null)
|
||
{
|
||
UpdateRedeemCodeButtonDefaultForeground();
|
||
}
|
||
}
|
||
|
||
[RelayCommand]
|
||
private void OnClosing(CancelEventArgs e)
|
||
{
|
||
if (Config.CommonConfig.ExitToTray)
|
||
{
|
||
e.Cancel = true;
|
||
OnHide();
|
||
}
|
||
}
|
||
|
||
[RelayCommand]
|
||
private void OnOpenFeed()
|
||
{
|
||
if (_redeemCodeUpdateNewVersion != null)
|
||
{
|
||
Config.CommonConfig.RedeemCodeFeedsUpdateVersion = _redeemCodeUpdateNewVersion;
|
||
// 重置为主题默认前景色,避免浅色主题下显示为白色
|
||
UpdateRedeemCodeButtonDefaultForeground();
|
||
_redeemCodeUpdateNewVersion = null;
|
||
}
|
||
|
||
var feedWindow = new FeedWindow(new FeedWindowViewModel());
|
||
feedWindow.Show();
|
||
}
|
||
|
||
[RelayCommand]
|
||
private async Task OnLoaded()
|
||
{
|
||
|
||
// 应用上次保存的主题
|
||
ApplyTheme(Config.CommonConfig.CurrentThemeType);
|
||
|
||
|
||
// 预热OCR
|
||
await OcrPreheating();
|
||
|
||
if (Environment.GetCommandLineArgs().Length > 1)
|
||
{
|
||
return;
|
||
}
|
||
|
||
// 自动处理目录配置
|
||
await Patch1();
|
||
|
||
// 删除多余特征点
|
||
Patch2();
|
||
|
||
// 启动时关闭布局编辑模式
|
||
if (Config.MaskWindowConfig.OverlayLayoutEditEnabled)
|
||
{
|
||
Config.MaskWindowConfig.OverlayLayoutEditEnabled = false;
|
||
}
|
||
|
||
// 首次运行
|
||
if (Config.CommonConfig.IsFirstRun)
|
||
{
|
||
// 自动初始化键位绑定
|
||
// InitKeyBinding();
|
||
Config.AutoFightConfig.TeamNames = ""; // 此配置以后无用
|
||
Config.CommonConfig.IsFirstRun = false;
|
||
}
|
||
|
||
// 版本是否运行过
|
||
if (Config.CommonConfig.RunForVersion != Global.Version)
|
||
{
|
||
ModifyFolderSecurity();
|
||
Config.CommonConfig.RunForVersion = Global.Version;
|
||
}
|
||
|
||
OnceRun();
|
||
|
||
// 检查更新
|
||
await App.GetService<IUpdateService>()!.CheckUpdateAsync(new UpdateOption());
|
||
|
||
// 检查兑换码更新
|
||
await CheckRedeemCodeFeedsUpdateAsync();
|
||
|
||
// Win11下 BitBlt截图方式不可用,需要关闭窗口优化功能
|
||
if (OsVersionHelper.IsWindows11_OrGreater && TaskContext.Instance().Config.AutoFixWin11BitBlt)
|
||
{
|
||
BitBltRegistryHelper.SetDirectXUserGlobalSettings();
|
||
}
|
||
|
||
// 更新仓库
|
||
// ScriptRepoUpdater.Instance.AutoUpdate();
|
||
|
||
// 自动更新已订阅的脚本 会先更新仓库
|
||
// 使用 Task.Run 确保整个流程在线程池执行,避免 WPF SynchronizationContext
|
||
// 将 await 后续调度回 UI 线程导致大量 IO/Git 操作阻塞界面
|
||
_ = Task.Run(() => ScriptRepoUpdater.Instance.AutoUpdateSubscribedScripts());
|
||
|
||
// 清理临时目录
|
||
TempManager.CleanUp();
|
||
}
|
||
|
||
|
||
private void ModifyFolderSecurity()
|
||
{
|
||
// 检查程序是否位于C盘
|
||
if (Global.StartUpPath.StartsWith(@"C:", StringComparison.OrdinalIgnoreCase))
|
||
{
|
||
// 修改文件夹权限
|
||
SecurityControlHelper.AllowFullFolderSecurity(Global.StartUpPath);
|
||
}
|
||
}
|
||
|
||
/*
|
||
private void InitKeyBinding()
|
||
{
|
||
try
|
||
{
|
||
var kbVm = App.GetService<KeyBindingsSettingsPageViewModel>();
|
||
if (kbVm != null)
|
||
{
|
||
kbVm.FetchFromRegistryCommand.Execute(null);
|
||
}
|
||
}
|
||
catch (Exception e)
|
||
{
|
||
_logger.LogError("首次运行自动初始化按键绑定异常:" + e.Source + "\r\n--" + Environment.NewLine + e.StackTrace + "\r\n---" + Environment.NewLine + e.Message);
|
||
|
||
await ThemedMessageBox.ErrorAsync("读取原神键位并设置键位绑定数据时发生异常:" + e.Message + ",后续可以手动设置");
|
||
}
|
||
}
|
||
*/
|
||
|
||
/**
|
||
* 不同的安装目录处理
|
||
* 可能当前目录下存在 BetterGI 的文件,需要移动到新的目录
|
||
*/
|
||
private async Task Patch1()
|
||
{
|
||
var embeddedPath = Global.Absolute("BetterGI");
|
||
var embeddedUserPath = Global.Absolute("BetterGI/User");
|
||
var exePath = Global.Absolute("BetterGI/BetterGI.exe");
|
||
if (Directory.Exists(embeddedPath)
|
||
&& File.Exists(exePath)
|
||
&& Directory.Exists(embeddedUserPath)
|
||
)
|
||
{
|
||
var fileVersionInfo = FileVersionInfo.GetVersionInfo(exePath);
|
||
// 低版本才需要迁移
|
||
if (fileVersionInfo.FileVersion != null && !Global.IsNewVersion(fileVersionInfo.FileVersion))
|
||
{
|
||
var res = await ThemedMessageBox.ShowAsync("检测到旧的 BetterGI 配置,是否迁移配置并清理旧目录?", "BetterGI",
|
||
System.Windows.MessageBoxButton.YesNo, ThemedMessageBox.MessageBoxIcon.Question);
|
||
if (res == System.Windows.MessageBoxResult.Yes)
|
||
{
|
||
// 迁移配置,拷贝整个目录并覆盖
|
||
DirectoryHelper.CopyDirectory(embeddedUserPath, Global.Absolute("User"));
|
||
// 删除旧目录
|
||
DirectoryHelper.DeleteReadOnlyDirectory(embeddedPath);
|
||
await ThemedMessageBox.InformationAsync("迁移配置成功, 软件将自动退出,请手动重新启动 BetterGI!");
|
||
Application.Current.Shutdown();
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 0.45版本开始
|
||
* 地图特征的存储格式变化
|
||
*/
|
||
private void Patch2()
|
||
{
|
||
List<string> files =
|
||
[
|
||
Global.Absolute(@"Assets\Map\mainMap256Block_SIFT.kp"),
|
||
Global.Absolute(@"Assets\Map\mainMap256Block_SIFT.mat"),
|
||
Global.Absolute(@"Assets\Map\mainMap2048Block_SIFT.kp"),
|
||
Global.Absolute(@"Assets\Map\mainMap2048Block_SIFT.mat"),
|
||
Global.Absolute(@"Assets\Map\Teyvat\map_info.json"),
|
||
];
|
||
|
||
// 循环删除
|
||
foreach (var file in files.Where(File.Exists))
|
||
{
|
||
File.Delete(file);
|
||
}
|
||
}
|
||
|
||
private async Task OcrPreheating()
|
||
{
|
||
try
|
||
{
|
||
await Task.Run(async () =>
|
||
{
|
||
try
|
||
{
|
||
// 现在OCR创建的时候会自己读设置了
|
||
// string gameCultureInfoName = TaskContext.Instance().Config.OtherConfig.GameCultureInfoName;
|
||
// await OcrFactory.ChangeCulture(gameCultureInfoName);
|
||
var s = OcrFactory.Paddle.Ocr(new Mat(Global.Absolute(@"Assets\Model\PaddleOCR\test_pp_ocr.png")));
|
||
Debug.WriteLine("PaddleOcr预热结果:" + s);
|
||
}
|
||
catch (Exception e)
|
||
{
|
||
Console.WriteLine(e);
|
||
_logger.LogError("PaddleOcr预热异常,解决方案:【https://bettergi.com/faq.html】\r\n" + e.Source + "\r\n--" +
|
||
Environment.NewLine + e.StackTrace + "\r\n---" + Environment.NewLine + e.Message);
|
||
var innerException = e.InnerException;
|
||
if (innerException != null)
|
||
{
|
||
_logger.LogError("PaddleOcr预热内部异常,解决方案:【https://bettergi.com/faq.html】\r\n" +
|
||
innerException.Source + "\r\n--" + Environment.NewLine +
|
||
innerException.StackTrace + "\r\n---" + Environment.NewLine +
|
||
innerException.Message);
|
||
throw innerException;
|
||
}
|
||
else
|
||
{
|
||
throw;
|
||
}
|
||
}
|
||
});
|
||
}
|
||
catch (Exception e)
|
||
{
|
||
ThemedMessageBox.Warning("PaddleOcr预热失败,解决方案:【https://bettergi.com/faq.html】 \r\n" + e.Source + "\r\n--" +
|
||
Environment.NewLine + e.StackTrace + "\r\n---" + Environment.NewLine + e.Message);
|
||
Process.Start(
|
||
new ProcessStartInfo(
|
||
"https://bettergi.com/faq.html#%E2%9D%93%E6%8F%90%E7%A4%BA-paddleocr%E9%A2%84%E7%83%AD%E5%A4%B1%E8%B4%A5-%E5%BA%94%E8%AF%A5%E5%A6%82%E4%BD%95%E8%A7%A3%E5%86%B3")
|
||
{ UseShellExecute = true });
|
||
}
|
||
}
|
||
|
||
private void OnceRun()
|
||
{
|
||
string deviceId = DeviceIdHelper.DeviceId;
|
||
if (string.IsNullOrWhiteSpace(deviceId))
|
||
{
|
||
deviceId = "default"; // 如果获取设备ID失败,使用默认值
|
||
}
|
||
|
||
// 每个设备只运行一次 | 在Wine上会崩溃
|
||
if (!Config.CommonConfig.OnceHadRunDeviceIdList.Contains(deviceId) && !WinePlatformAddon.IsRunningOnWine)
|
||
{
|
||
WelcomeDialog prompt = new WelcomeDialog
|
||
{
|
||
Owner = Application.Current.MainWindow
|
||
};
|
||
prompt.ShowDialog();
|
||
prompt.Focus();
|
||
|
||
Config.CommonConfig.OnceHadRunDeviceIdList.Add(deviceId);
|
||
_configService.Save();
|
||
}
|
||
}
|
||
|
||
private async Task CheckRedeemCodeFeedsUpdateAsync()
|
||
{
|
||
try
|
||
{
|
||
var request = new HttpRequestMessage(HttpMethod.Get, "https://cnb.cool/bettergi/genshin-redeem-code/-/git/raw/main/update_time.txt");
|
||
var response = await HttpClientFactory.GetCommonSendClient().SendAsync(request);
|
||
response.EnsureSuccessStatusCode();
|
||
var txt = await response.Content.ReadAsStringAsync();
|
||
|
||
|
||
if (!string.IsNullOrEmpty(txt))
|
||
{
|
||
if (long.TryParse(txt, out long v2)
|
||
&& long.TryParse(Config.CommonConfig.RedeemCodeFeedsUpdateVersion, out long v1))
|
||
{
|
||
if (v2 > v1)
|
||
{
|
||
RedeemCodeButtonForeground = new SolidColorBrush((Color)ColorConverter.ConvertFromString("#1E9BFA"));
|
||
_redeemCodeUpdateNewVersion = txt;
|
||
}
|
||
}
|
||
}
|
||
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
_logger.LogDebug(ex, $"获取兑换码是否存在更新失败");
|
||
}
|
||
}
|
||
|
||
// 更新兑换码按钮在当前主题下的默认前景色
|
||
private void UpdateRedeemCodeButtonDefaultForeground()
|
||
{
|
||
try
|
||
{
|
||
var brush = Application.Current.TryFindResource("TextFillColorPrimaryBrush") as Brush;
|
||
if (brush != null)
|
||
{
|
||
RedeemCodeButtonForeground = brush;
|
||
return;
|
||
}
|
||
}
|
||
catch
|
||
{
|
||
// 忽略资源查找异常,走回退逻辑
|
||
}
|
||
|
||
// 回退:根据当前主题类型使用黑/白色
|
||
var isLightTheme = Config.CommonConfig.CurrentThemeType == ThemeType.LightNone
|
||
|| Config.CommonConfig.CurrentThemeType == ThemeType.LightMica
|
||
|| Config.CommonConfig.CurrentThemeType == ThemeType.LightAcrylic;
|
||
RedeemCodeButtonForeground = isLightTheme ? Brushes.Black : Brushes.White;
|
||
}
|
||
} |