From 40b8524ffd0d8c601ca25218696b4232599a74d3 Mon Sep 17 00:00:00 2001 From: Oliver Wong Date: Mon, 8 Jun 2026 13:40:27 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E6=89=AB=E6=8F=8F=E6=97=B6=E7=95=8C?= =?UTF-8?q?=E9=9D=A2=E4=BC=9A=E5=9B=A0=E4=B8=BA=E6=96=87=E4=BB=B6=E5=90=8D?= =?UTF-8?q?=E4=B8=8D=E5=90=8C=E8=80=8C=E6=8A=96=E5=8A=A8=E7=9A=84=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- AGENTS.md | 16 +++++------ src/GUI/Converters/ValueConverters.cs | 39 +++++++++++++++++++++++++++ src/GUI/Views/MainWindow.axaml | 6 ++--- src/GUI/Views/ScanProgressView.axaml | 12 ++++++--- src/Resonance.sln.DotSettings.user | 2 ++ 5 files changed, 59 insertions(+), 16 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index d6cc679..64cb29d 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,5 +1,10 @@ # AGENTS.md +## AI 行为准则 + +- **称呼规范**:始终称呼用户为「思谦」或「王思谦」。 +- **信息缺失处理**:遇到任何不确定、拿不准或信息缺失的情况,不要自行推测。先收集整理好问题,停下来向思谦确认后再继续。 + ## Build & Test ```bash @@ -26,23 +31,14 @@ dotnet run --project src/GUI # Launch the Avalonia de ## Known Issues / Gotchas - - 扫描时如果报错,报错信息可能会填满整个窗口,导致Overlay无法关闭。 - 读取时如果报错,没有任何警告,会静默报错。需要有一个界面右下方的toast,或是发送系统通知告知用户遇到了错误。 -- 扫描界面的宽度会因为文件名而发生变化。固定为窗口宽度的50%。如果文件名超过这个宽度则省略中间的字符,仅保留开头以及最后10个字符。 - **升级 Avalonia 版本时,必须同步更新所有次级包引用。** 仅修改主包 `Avalonia` 的 Version 不会自动更新 `Avalonia.Desktop`、`Avalonia.Themes.Fluent`、`Avalonia.Fonts.Inter` 等次级包。必须手动逐个修改,然后执行 `dotnet clean && dotnet restore`。否则运行时的原生库(如 `libAvaloniaNative.dylib`)会混用新旧版本,导致 macOS 上的 `StorageProvider` 文件/文件夹选择对话框在回调时 SIGSEGV 崩溃。 - 相关 Avalonia issues: [#21102](https://github.com/AvaloniaUI/Avalonia/issues/21102), [#21150](https://github.com/AvaloniaUI/Avalonia/issues/21150), [#21313](https://github.com/AvaloniaUI/Avalonia/issues/21313),修复 PR: [#21104](https://github.com/AvaloniaUI/Avalonia/pull/21104)。 - **Tests create temp files/directories** under `Path.GetTempPath()` and clean them up via `IDisposable`. Don't rely on a real audio directory for tests. - **`AudioMetadataReader` tests** use real WAV files from `data/source/` (not in git). When files are absent, tests silently return early (`if (wavFiles.Length == 0) return;`) — they pass without actually running assertions, not `Skip.If`. Running `dotnet test` will report 12 passes regardless of whether the fixture files exist. - **`.atl.txt` fixture files** are generated by `AtlFieldExtractor`. If the WAV files or the ATL library version change, re-run the extractor to regenerate them before running metadata tests. - -## Data / Test Fixtures - -- **`data/source/`** 包含有版权保护的 WAV 音频文件,**不会提交到 git**。按厂商分子目录:`Boom/`、`Wow Sound/`、`The Odessy/`、`Sound Idea/`。 - - 每个 WAV 旁有对应的 `.atl.txt` 文件(由 `AtlFieldExtractor` 生成),记录了 ATL 库解析出的完整元数据,供测试断言参考。 - - Boom 目录下的文件元数据最丰富(标准标签 + iXML 自定义字段 + BWF bext 字段 + 嵌入封面);Sound Idea 目录下的文件元数据最少(仅基础技术参数,无任何附加字段)。 -- **`AudioMetadataReader` 测试**使用 `data/source/Boom/` 和 `Sound Idea/` 中的 WAV 文件。文件不在 git 仓库中,测试通过 `if (wavFiles.Length == 0) return;` 静默返回(测试仍然 pass,但未执行实际断言)。 -- **路径解析**:测试运行时从 `bin/Debug/net10.0/` 启动,需向上回溯 6 级到达仓库根目录,再拼接 `data/source/`。 +- 需要一个UI设计。现在的界面属实有点丑陋了。 ## Conventions diff --git a/src/GUI/Converters/ValueConverters.cs b/src/GUI/Converters/ValueConverters.cs index b255c5e..1e3b729 100644 --- a/src/GUI/Converters/ValueConverters.cs +++ b/src/GUI/Converters/ValueConverters.cs @@ -100,6 +100,43 @@ public class InverseBoolConverter : IValueConverter } } +public class HalfDoubleConverter : IValueConverter +{ + public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture) + { + if (value is double d && !double.IsNaN(d) && !double.IsInfinity(d)) + return d / 2.0; + return 400.0; + } + + public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture) + => throw new NotSupportedException(); +} + +public class MiddleTruncateConverter : IValueConverter +{ + private const int KeepTail = 10; + + public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture) + { + if (value is not string text || string.IsNullOrEmpty(text)) return value; + + int maxLength = 60; + if (parameter != null && int.TryParse(parameter.ToString(), NumberStyles.Integer, CultureInfo.InvariantCulture, out int parsed)) + maxLength = parsed; + + if (text.Length <= maxLength) return text; + + int head = maxLength - KeepTail - 3; + if (head <= 0) return text[..maxLength]; + + return string.Concat(text.AsSpan(0, head), "...", text.AsSpan(text.Length - KeepTail, KeepTail)); + } + + public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture) + => throw new NotSupportedException(); +} + public static class ValueConverters { public static readonly IValueConverter DurationFormat = new DurationFormatConverter(); @@ -109,4 +146,6 @@ public static class ValueConverters public static readonly IValueConverter DurationToSliderMax = new DurationToSliderMaxConverter(); public static readonly IValueConverter PositionFormat = new PositionFormatConverter(); public static readonly IValueConverter InverseBool = new InverseBoolConverter(); + public static readonly IValueConverter HalfDouble = new HalfDoubleConverter(); + public static readonly IValueConverter MiddleTruncate = new MiddleTruncateConverter(); } diff --git a/src/GUI/Views/MainWindow.axaml b/src/GUI/Views/MainWindow.axaml index a1862be..4b4d7fe 100644 --- a/src/GUI/Views/MainWindow.axaml +++ b/src/GUI/Views/MainWindow.axaml @@ -16,15 +16,15 @@ - + -