Files
better-genshin-impact/BetterGenshinImpact/View/Windows/ScriptRepoWindow.xaml
ShadowLemoon f7976b0bbd feat: 根据文件夹名字和内容重合度区分仓库;启动时自动更新仓库和订阅 (#2767)
* 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: 修复按钮位置
2026-02-20 15:09:17 +08:00

343 lines
19 KiB
XML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<ui:FluentWindow x:Class="BetterGenshinImpact.View.Windows.ScriptRepoWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:BetterGenshinImpact.View.Windows"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml"
xmlns:vio="http://schemas.lepo.co/wpfui/2022/xaml/violeta"
xmlns:behavior="clr-namespace:BetterGenshinImpact.View.Behavior"
Title="脚本仓库"
Width="410"
MinWidth="360"
MinHeight="50"
ResizeMode="NoResize"
Background="#202020"
ExtendsContentIntoTitleBar="True"
behavior:AutoTranslateInterceptor.EnableAutoTranslate="True"
FontFamily="{DynamicResource TextThemeFontFamily}"
SizeToContent="Height"
WindowBackdropType="Auto"
WindowStartupLocation="CenterOwner"
mc:Ignorable="d">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="48" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<!-- 标题栏 -->
<ui:TitleBar Grid.Row="0"
Title="{Binding Title}"
ShowMaximize="False"
ShowMinimize="False">
<ui:TitleBar.Icon>
<ui:ImageIcon Source="pack://application:,,,/Resources/Images/logo.png" />
</ui:TitleBar.Icon>
</ui:TitleBar>
<!-- 主内容区域 -->
<Grid Grid.Row="1" Margin="12,0,12,12">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<!-- 标签页区域 -->
<Border Grid.Row="0"
Background="{ui:ThemeResource CardBackgroundFillColorDefaultBrush}"
BorderBrush="{ui:ThemeResource CardStrokeColorDefaultBrush}"
BorderThickness="1,1,1,1"
CornerRadius="8">
<TabControl Margin="12">
<!-- Git仓库标签页 -->
<TabItem Width="110">
<TabItem.Header>
<StackPanel Orientation="Horizontal">
<ui:SymbolIcon Margin="0,0,6,0" Symbol="BranchFork24" />
<TextBlock Text="Git一键更新" />
</StackPanel>
</TabItem.Header>
<Grid Margin="0,12,0,0">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<!-- 第一行:更新渠道 -->
<Grid Grid.Row="0" Margin="0,0,0,12">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<ui:TextBlock Grid.Column="0"
Margin="0,0,8,0"
VerticalAlignment="Center"
Foreground="{ui:ThemeResource TextFillColorPrimaryBrush}"
Text="更新渠道:" />
<ComboBox Grid.Column="1"
MinWidth="160"
VerticalAlignment="Center"
DisplayMemberPath="Name"
ItemsSource="{Binding RepoChannels}"
SelectedItem="{Binding SelectedRepoChannel}"
IsTextSearchEnabled="False" />
</Grid>
<!-- 第二行脚本仓库URL -->
<Grid Grid.Row="1" Margin="0,0,0,12">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<ui:TextBlock Grid.Column="0"
Margin="0,0,8,0"
VerticalAlignment="Center"
Foreground="{ui:ThemeResource TextFillColorPrimaryBrush}"
Text="仓库地址:" />
<!-- 只读模式:显示文本 -->
<Border Grid.Column="1"
MinWidth="160"
MinHeight="32"
Background="{ui:ThemeResource ControlFillColorDefaultBrush}"
BorderBrush="{ui:ThemeResource ControlStrokeColorDefaultBrush}"
BorderThickness="1"
CornerRadius="4"
Visibility="{Binding IsRepoUrlReadOnly, Converter={StaticResource BooleanToVisibilityConverter}}">
<ScrollViewer VerticalScrollBarVisibility="Auto"
HorizontalScrollBarVisibility="Disabled"
Padding="8,6">
<ui:TextBlock Foreground="{ui:ThemeResource TextFillColorSecondaryBrush}"
Text="{Binding CurrentRepoUrl}"
TextWrapping="Wrap" />
</ScrollViewer>
</Border>
<!-- 编辑模式:可输入 -->
<TextBox Grid.Column="1"
MinWidth="160"
VerticalAlignment="Center"
Text="{Binding Config.CustomRepoUrl, UpdateSourceTrigger=PropertyChanged}"
Visibility="{Binding IsRepoUrlReadOnly, Converter={StaticResource BooleanToVisibilityRevertConverter}}" />
</Grid>
<!-- 第三行Git 用户名 -->
<Grid Grid.Row="2"
Margin="0,0,0,12"
Visibility="{Binding IsRepoUrlReadOnly, Converter={StaticResource BooleanToVisibilityRevertConverter}}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<ui:TextBlock Grid.Column="0"
Margin="0,0,8,0"
VerticalAlignment="Center"
Foreground="{ui:ThemeResource TextFillColorPrimaryBrush}"
Text="用户名称:" />
<!-- 编辑模式:可输入 -->
<TextBox Grid.Column="1"
MinWidth="160"
VerticalAlignment="Center"
Text="{Binding GitUsername, UpdateSourceTrigger=PropertyChanged}" />
</Grid>
<!-- 第四行Git Token -->
<Grid Grid.Row="3"
Margin="0,0,0,12"
Visibility="{Binding IsRepoUrlReadOnly, Converter={StaticResource BooleanToVisibilityRevertConverter}}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<ui:TextBlock Grid.Column="0"
Margin="0,0,8,0"
VerticalAlignment="Center"
Foreground="{ui:ThemeResource TextFillColorPrimaryBrush}"
Text="访问令牌:" />
<!-- 编辑模式:可输入 -->
<PasswordBox x:Name="GitTokenPasswordBox"
Grid.Column="1"
MinWidth="160"
VerticalAlignment="Center"
PasswordChanged="PasswordBox_PasswordChanged" />
</Grid>
<!-- 第五行:按钮组 -->
<Grid Grid.Row="4" Margin="0,0,0,8">
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<ui:Button Grid.Column="0"
Margin="0,0,4,0"
Command="{Binding UpdateRepoCommand}"
Content="更新仓库"
Icon="{ui:SymbolIcon CloudSync24}"
HorizontalAlignment="Stretch"
IsEnabled="{Binding IsUpdating, Converter={StaticResource InverseBooleanConverter}}" />
<ui:Button Grid.Column="1"
Margin="4,0,0,0"
Command="{Binding ResetRepoCommand}"
Content="重置仓库"
Icon="{ui:SymbolIcon ArrowReset24}"
HorizontalAlignment="Stretch"
IsEnabled="{Binding IsUpdating, Converter={StaticResource InverseBooleanConverter}}" />
</Grid>
</Grid>
</TabItem>
<!-- 在线更新标签页 -->
<!--<TabItem Width="100">
<TabItem.Header>
<StackPanel Orientation="Horizontal">
<ui:SymbolIcon Margin="0,0,6,0" Symbol="DocumentArrowDown20" />
<TextBlock Text="URL更新" />
</StackPanel>
</TabItem.Header>
<Grid Margin="0,12,0,0">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<ui:TextBlock Grid.Row="0"
Margin="0,0,0,12"
Foreground="{ui:ThemeResource TextFillColorSecondaryBrush}"
TextWrapping="Wrap"
Text="从在线地址直接下载脚本仓库压缩包,适用于网络环境较好的情况。" />
<Grid Grid.Row="1" Margin="0,0,0,12">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<ui:TextBlock Grid.Column="0"
Margin="0,0,8,0"
VerticalAlignment="Center"
Foreground="{ui:ThemeResource TextFillColorPrimaryBrush}"
Text="下载地址:" />
<TextBox Grid.Column="1"
MinWidth="160"
VerticalAlignment="Center"
Text="{Binding OnlineDownloadUrl}" />
</Grid>
<ui:Button Grid.Row="2"
Command="{Binding DownloadOnlineRepoCommand}"
Content="下载并导入"
Icon="{ui:SymbolIcon Cloud24}"
HorizontalAlignment="Left" />
</Grid>
</TabItem>-->
<!-- 手动导入标签页 -->
<TabItem Width="100">
<TabItem.Header>
<StackPanel Orientation="Horizontal">
<ui:SymbolIcon Margin="0,0,6,0" Symbol="FolderZip24" />
<TextBlock Text="手动导入" />
</StackPanel>
</TabItem.Header>
<Grid Margin="0,12,0,0">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<ui:TextBlock Grid.Row="0"
Margin="0,0,0,12"
Foreground="{ui:ThemeResource TextFillColorSecondaryBrush}"
TextWrapping="Wrap"
Text="从本地zip文件导入脚本仓库适用于离线环境或网络不稳定的情况。" />
<ui:TextBlock Grid.Row="1"
Margin="0,0,0,12"
Foreground="{ui:ThemeResource TextFillColorTertiaryBrush}"
TextWrapping="Wrap"
Text="请选择包含脚本仓库内容的zip压缩包文件进行导入。" />
<ui:TextBlock Grid.Row="2"
Margin="0,0,0,12"
Foreground="{ui:ThemeResource TextFillColorSecondaryBrush}"
TextWrapping="Wrap">
<Run Text="可以从这里获取zip" />
<Hyperlink NavigateUri="https://bettergi.com/feats/autos/srepo.html" RequestNavigate="Hyperlink_RequestNavigate">
<Run Text="脚本仓库文档" />
</Hyperlink>
</ui:TextBlock>
<ui:Button Grid.Row="3"
Command="{Binding ImportLocalScriptsRepoZipCommand}"
Content="选择zip文件导入"
Icon="{ui:SymbolIcon FolderZip24}"
HorizontalAlignment="Left" />
</Grid>
</TabItem>
</TabControl>
</Border>
<!-- 进度条区域 -->
<Grid Grid.Row="1"
Margin="0,12,0,8"
Visibility="{Binding IsUpdating, Converter={StaticResource BooleanToVisibilityConverter}}">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<ui:TextBlock Grid.Row="0"
Margin="0,0,0,4"
VerticalAlignment="Center"
Foreground="{ui:ThemeResource TextFillColorSecondaryBrush}"
Text="{Binding UpdateProgressText}" />
<ProgressBar Grid.Row="1"
IsIndeterminate="{Binding IsProgressIndeterminate}"
Maximum="100"
Value="{Binding UpdateProgressValue}" />
</Grid>
<!-- 公共按钮区域 -->
<Grid Grid.Row="2" Margin="0,4,0,0">
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<ui:Button Grid.Column="0"
Margin="0,0,4,0"
Appearance="Primary"
Command="{Binding OpenLocalScriptRepoCommand}"
Content="打开仓库"
Icon="{ui:SymbolIcon BookStar24}"
HorizontalAlignment="Stretch"
IsEnabled="{Binding IsUpdating, Converter={StaticResource InverseBooleanConverter}}" />
<ui:Button Grid.Column="1"
Margin="4,0,0,0"
Command="{Binding UpdateSubscribedScriptsCommand}"
Content="一键更新订阅"
Icon="{ui:SymbolIcon ArrowDownload24}"
HorizontalAlignment="Stretch"
IsEnabled="{Binding IsUpdating, Converter={StaticResource InverseBooleanConverter}}" />
</Grid>
</Grid>
</Grid>
</ui:FluentWindow>