| 文件 | 最后提交记录 | 最后更新时间 |
|---|---|---|
重构(仓储层): 仓储扩覆盖至全部课表域实体——时间方案/地点分组/日期规则+签名/情侣绑定/教师教室记录共 16 处调用改走仓储,provider 仅剩 init 与迁移标记两个基础设施调用直连 storage;回应评审「仓储口径名实不符」,唯一写入口承诺完整(阶段2) | 28 天前 | |
新增(天气): 天气数据模型与区间聚合逻辑(日视图课卡天气 · 第 1 步) 接入公开免费天气源 Open-Meteo(零密钥)的前置纯逻辑层,只做数据与算法, 不碰任何界面与网络。 - lib/models/weather_forecast.dart WeatherLocation(含 admin1 用于区分同名地点、经纬度判同一地点)、 HourlyWeatherPoint、WeatherForecast(升序保证 + covers/hasLapsedAt/ matchesLocation + 列式序列化)。 列式存 6 个平行数组而非逐点对象,体积约为 1/3;时间用不带 Z 的墙钟串, 避免本地/UTC 往返漂移。 - lib/domain/weather_logic.dart 20 档 WeatherCategory + WMO 码映射 + 严重度序; summarizeCourseWeather 按「与课程区间有交集的小时桶」聚合 (t > start && t < end + 1h,因为降水是前 1 小时累计;左开右开各有一条 单测钉住),代表现象按雪优先于雨、家族内取最严重; 降水概率低于 30% 不返回显示标记(「晴 · 23° · 0%」是噪音)。 纯 Dart,无 UI 依赖,符合 lib/domain 纯度守卫。 - 测试:51 条断言。含区间选取 7 个边界、雪雨同存判雪、有雪量无雪码兜底、 概率 29/30 阈值、温度全缺报返回 null、序列化往返与损坏数据降级。 验证:flutter analyze 无 issue;flutter test 51 条全绿。 | 9 天前 | |
天气设置页:数据来源置顶、灰字收窄、打开开关即定位 - 「数据来源」区块移到最前:没有城市就一条天气都取不到,它是这个功能的前置条件, 先办完它,后面那些显示开关才有意义。这是设置目录里第一块前置的来源区块,代码 注释里写清了它为什么与「来源型内容放末段」的惯例不同。 - 删掉「显示内容」区块末尾那条 77 字脚注(全目录最长,第二长的只有 26 字)。它装的 三件事里,两件本来就可推断;周视图那句改挂到「周视图课卡」行的副标题(13 字), 拨开关的人正好需要知道;图标认领规则属于内部机制且图标本身自解释,不再写。依据是 仓库的文案三戒律(副标题 ≤14 字、禁内部术语)与既有的「标签下勿多余脚注」要求。 - 打开「显示天气」开关时若还没有城市,主动定位一次,不再停在「开关亮着、卡片上 什么都没有」的状态。只在「打开 + 没城市」这个组合触发:已有城市绝不覆盖(用户 手选的城市比定位可信),关闭时不做任何事。触发点放在界面层——它要弹系统权限框和 失败提示,都需要 BuildContext;provider 继续只管状态与请求。 | 5 天前 | |
卡片玻璃独立配置 + 液态玻璃浅/深成对(同批提交) 两批必须同批:卡片这套参数直接调在新加的 toStyle(darkBoost:) 与几个新字段上, 拆开任一半都编译不过。 A. 液态玻璃浅/深成对(前一批已完成、此前未提交的工作) LiquidGlassDarkRecipe(identity/legacy/standard)+ forMode + toStyle 的 dark/link/darkBoost; 深色档三个字段 + 两个开关 + 编辑器与预览透传;顺带修掉「恢复默认对可空 tuning 字段无效」 (copyWith 对可空字段是 ?? 语义,必须走 clear 标记)。 B. 课程卡片一套自己的玻璃参数(本次) - 新增 CourseGlassTuning(八项;缺键回落到**卡片**默认,不是全局那份的 0.70 —— 这是它 不复用 LiquidGlassTuning 的头号理由),解析走 courseGlassStyleFor → 仍经唯一入口 toStyle, 形状/深浅配方/染色 alpha 都从那出,架构守卫仍绿; - course_card_glass.frag 接上 u_dispersion(与全局那份逐字同源的三采样分支), CourseGlassStyle 加 dispersion 并同步 ==/hashCode(漏了就是「拖色散不重绘」); - 卡片单独烤一张预糊位图:cache 发布槽改 Map ≤2、scope 加 cardBlurSigma 与第二个 inherited、 AlignedFill 加显式 source;resolveHomePreblurSigma 刻意不动(改了会连带改摘要替身卡的磨砂); - 课程卡片设置页新增「高级材质」一节:八根滑杆,折射强度/作用带宽度/边缘陡缓/染色强度 带建议点位(miuix 的 showKeyPoints/keyPoints,由 HyperosSlider 透传;有档位时上游不磁吸, 故只做「标记 + 划过变色 + 经过触感」); - 不放「外观编辑」材质面板的算术理由:面板内容上限约 334px(393×852),八行滑杆 592px。 默认观感逐位不变(八项出厂值 = 改动前行为);深色下卡片开始吃同一份配方(边光 ×0.6、 色散 ×0.7、染色 ×0.85),回滚开关是 darkGlassBoostEnabled。 已知三条红与本次无关、未修:dependency_guards_test(pubspec 的 fork 依赖)、 _debug_material_sheet_test(未入库的临时调试件)、wallpaper_position_picker_glass_test (75e63f2e 新增 LiquidGlassTransitionRepaint 后计数断言未同步)。 | 6 天前 | |
材质面板改成「通用 / 课程卡片」两页,卡片调参搬回面板 用户口径(2026-09-22):材质弹窗改结构,做成左右切换的内部页面 —— 第一个「通用」、 第二个「课程卡片」,要能滑;第二页带上卡片自己那八根旋钮。 * 面板正文改成「标题 + 两格内联分段」一行 + 横向 PageView 两页: 通用 = 总闸(玻璃模式)/ 首页顶栏玻璃 / 液态预设与八根旋钮 / 子页顶栏风格 / 各表面当前材质只读总览;课程卡片 = 卡片外观三档 + 卡片自己的八根旋钮 (卡片档为液态时出现)。面板高度因此固定占满半屏(此前是随内容长、最多半屏)。 * 八根滑杆只有一份实现: _liquidSliderTiles 改名 _glassSliderTiles,浅色 / 深色 / 卡片三档共用;卡片档沿用它在课程卡片设置页那套参数(4 根建议点位、染色 25 档 以保证出厂 0.32 落在格点上),写回经新加的 CourseGlassTuning.fromLiquidGlassTuning。 * 总闸会盖过卡片页(模糊总开关关掉 → 卡片一律按实体渲染),所以第二页在该情形多一行 说明(新文案 courseCardMaterialMasterOffHint,6 语种)。不加提示就是「选了液态、 画面不动」。 * **移除用户可见功能(注明)**:课程卡片设置页不再有那八根旋钮 —— 选了卡片液态也不在 那页展开;该页「卡片外观」选择行旁留了指向新位置的注释。这是用户 2026-09-22 明确 拍板的「搬走,不留第二份入口」。 * 测试:面板里第一个 Scrollable 变成那层横向翻页,三个测试文件改为按页 key (material-page-general / material-page-course-card)指名取内容滚动视图,文案 计数断言同步;新增两条回归钉(横向滑过去真的落在第二页;第二页八根旋钮写 courseCardGlassTuning 且全局那份保持 null)。 * 全量 flutter test:2568 通过 / 4 跳过 / 3 红 —— 三条红都是本次改动之前就在红的 (fork 依赖守卫、未入库的临时调试件、壁纸位置页的计数断言),与本改动无关; flutter analyze 全项目干净;跑完无孤儿 flutter_tester。 | 5 天前 | |
fix(glass): 边光改「一圈均匀 + 按边界曲率加权」;模糊出界黑边落成扫描守卫 真机两条观感问题的根因与修法(同一批,跨多个表面): - **边光方向性**: glass_surface_refraction.frag 与 course_card_glass.frag 原先的边缘高光带方向(u_light_dir),长直边与圆角在同一圈上亮度不匀。 改为**一圈均匀、按边界曲率加权**(卡片那支「只落在转角上」)。roundedBoxSDF 顺带把中间量 q 交出去,避免边光与 SDF 各算一遍。 - **模糊出界的透明黑**:ImageFilter.blur 不给 tileMode 时默认 decal,模糊 结果会在离边约 3σ 的带里淡成透明黑 —— 凡是「模糊后的边可见」的表面都会读出 一条黑边(宽度随模糊量走、模糊调到 0 就消失,这是它的指纹)。真机已两次 实测(弹窗顶边、星期栏底边),第二次是另一个表面又漏同一处。 修法:liquid_glass_surface / hyperos_collapsible_top_app_bar 等处补 TileMode.clamp。 - 新增 test/architecture/blur_tile_mode_guard_test.dart:扫描 lib/ 下每一处 ImageFilter.blur 必须显式给 tileMode。这条规则原先只写在笔记里,于是 第二天在另一个表面上又踩了一次 —— 落成扫描测试后新增模糊忘了给就直接红。 - 其余:液态玻璃调参、弹窗/底栏/代理层的材质分派对齐、首页背景与预模糊壁纸、 课程卡玻璃、若干设置页入口与 QR 传输页的材质口径统一。 - timetable_provider.dart:新增 @visibleForTesting 的 seedHolidayDataForTesting(+10,只赋值 + 通知,无业务逻辑),供假期课 过滤类 UI 断言注入数据;dependency_guards_test.dart 的行数棘轮按本文件 既有约定同步基线到 4499 并注明理由。 | 7 天前 | |
修复(设置·壁纸行): 文件名按两种分隔符切,不再只看当前系统的分隔符 CI(Ubuntu)上唯一那条红:appearance_editor_test.dart「弹层正文跟着草稿走」断言 find.text('wall.png') 读到 0 个,本地 Windows 绿。根因是这行用的是 path.split(Platform.pathSeparator).last Platform.pathSeparator 是**运行平台**的分隔符,不是**这条路径**的分隔符。测试喂的是 Windows 形状的 C:\fake\wall.png,在 Linux 上按 / 切不开,整条路径被当成文件名显示。 不只是测试的毛病:本仓有 android / ios / linux / macos / windows 五个目标,设置又能 经 WebDAV 跨设备同步 —— 一台机器上存下的壁纸路径,到另一台的壁纸行里就显示成整条 路径。单机同平台使用不触发,所以一直没暴露。 改成 path.split(RegExp(r'[\/]')).last:两种分隔符都切,语义收成「这一行显示的就是 文件名」,与路径来自哪个平台无关。没有改测试里的假路径 —— 那样 CI 也能绿,但等于把 「路径只可能是本机形状」这个错误假设固化进测试,跨设备同步那条路照样是坏的。 验证:全量 flutter test → 2600 通过 / 4 跳过 / 1 失败(唯一那条是不进仓库的本机临时 量测用例);appearance_editor_test.dart 18 例全绿; flutter analyze --no-pub --fatal-infos 该文件 0 issue。笔记已补(外观编辑页第 26 节)。 | 5 天前 | |
修复(日历同步): 清空与写入合并成一次批处理(失败不再丢已同步日程);权限申请改排队扇出,修连点后 Future 永挂 三个病根各自独立,都在「同步到系统日历」这条链路上: 1) 旧版先 resolver.delete 清空、成功后再另开一批 applyBatch 插入。insert 失败时清空已经提交且无回滚,用户之前同步好的日程被清没。改为 buildSyncOps 先构造完整批次(首条恒为清空 + N 条合法插入),同一次 applyBatch 提交 —— ContentProvider 批处理是事务,中途失败整批回滚。 批次抽成纯数据 SyncOp 列表,落库前才转 ContentProviderOperation, 使「清空与写入必须同批」这条规则能在 JVM 单测里断言。 2) 权限申请只有单个 pendingPermissionResult 槽位,连点两次按钮第二次会 覆盖第一次的 Result,Dart 侧第一个 Future 永挂。改为 PermissionRequestQueue 排队 + 单弹窗扇出:首个等待者触发系统弹窗,后来的只排队,complete 一次 把全部等待者按同一结果收束。 3) activity == null 之外补判 isFinishing / isDestroyed(销毁中的 Activity 照样 requestPermissions,回调可能永远不来);新增 onHostDestroyed() 由 MainActivity.onDestroy() 调用,把还没等到结果的等待者按未授权收束。 测试:新增 android/app/src/test/kotlin/.../CalendarSyncLogicTest.kt(8 例纯 逻辑单测,无需设备);Dart 侧补 1 例「连点两次都要 await 到结果」回归钉。 验证:flutter analyze 3 个改动文件 0 issue;calendar_sync_service_test.dart 与 liquid_glass_surface_test.dart 共 31 例全绿; gradlew :app:compileDevDebugUnitTestKotlin 编译通过。 | 5 天前 | |
修复(CI): 过中文硬编码审计的棘轮卡口 CI 红在「CJK hardcode audit」而不是测试上:那份清单记录每个源码文件里「没走多语言 资源的占位中文」的行数,只许减不许增,这次 5 个文件超了。分两类处理: 4 行其实是**行尾中文注释**(审计只跳整行注释,行尾注释照算,属它的误伤)——挪成 独立的整行注释即可,语义零变化: · lib/screens/timetable_screen.dart(「内嵌页表态只看主题」「56 正圆」) · lib/ui/hyperos/soft_glass/soft_glass_tab_bar.dart(两条 return 上的说明) 挪完这两处的计数归零,把清单里 timetable_screen 那条(1)一并删掉 —— 留着会让 将来单行行尾注释溜过去,删掉才是把棘轮收紧。 剩下 8 行是**诊断/日志文案**(出不了图的原因、着色器加载失败、坐标换算提示、 ErrorDescription 等),都不是界面文案、不该走 l10n,按本仓既有惯例登记进清单: · lib/ui/hyperos/hyperos_proxies.dart:1 · lib/ui/hyperos/preview_bake_boundary.dart:6 · lib/widgets/glass_shader_program.dart:1 (清单里本就有 71 个文件、1078 行同类存量,隔壁 soft_glass_surface:7 等都在。) 验证:本地跑该审计脚本 → 「OK: 71 files, 1078 lines (same as baseline)」exit 0; 两个被改文件 flutter analyze 0 issue;相关 3 个底栏测试文件共 7 例全绿。 | 5 天前 | |
日视图日期卡的墨色改判「卡面亮度」:浅色主题下发白/字浅的根因 用户报(2026-09-22):「日视图日期卡片的字体颜色适配好像没做好」,真机症状是浅色主题下 卡面发白、字也是浅色,糊在一起。 根因:上一轮把摘要卡改成跟课程卡同材质之后,判字色用的仍是**裸壁纸那条带的亮度** —— 而卡面上还压着一层自有底色(浅色主题下纯白,染色强度高斯 0.42 / 液态 0.32)。壁纸偏暗 → 翻白字,卡面却已被那层白底冲成中灰:白字对比度只剩 1.5~2.8:1(正文要 4.5:1)。 同屏课程卡是黑字(它的自动墨色会把卡色与壁纸混合),于是"一样材质、两种字色"。 * 新增 contentCardInkOverWallpaper(home_page_background.dart):判据亮度先按 cardGlassSurfaceLuminance 混成**卡面亮度**(卡自己的底色 × 染色强度 + 壁纸 × 余量), 黑白分界点从顶栏那套 0.45 换成 cardGlassInkFlipLuminance = 0.20(黑白对比度相等的 那一点)。其余(用户手挑的字色照给、对比度不够只推明度、亮度未采到回落主题色)沿用 homePageOverWallpaperInk。 * 新增 CourseSurface.washAlpha(context, style):把「这档卡面压多少自有底色在壁纸上」 交给画它的那个类回答(实体 1 / 高斯 frostedFillAlpha / 液态走卡片自己那套调参的 tintAlpha,深色下还吃深色配方),调用方不另写一份,避免与渲染层漂。 * **没有照抄课程卡那条式子**(卡色与壁纸 0.5/0.5 + 0.45 分界):议程卡的填充是彩色课程 色(0.5 权重近似成立),摘要卡的填充是主题背景(深色下近黑),照抄会在深色主题 + 亮 壁纸时判白字压在 0.58~0.68 × 壁纸亮度的卡面上,对比度跌到 1.8:1。课程卡观感本次不动。 * 测试:day_view_summary_material_test.dart 新增一个组,含用户报的那组输入(必须深墨、 > 4.5:1;同组走旧口径判白字 < 3:1 的对照)、**全区间扫描**(壁纸亮度 0→1 每 0.01 × 两档染色 × 两种主题底色 = 404 组,每组 ≥ 4.1:1)与「染色强度与渲染层同源」。 * 定向六文件 73 通过 / 3 跳过 / 0 红;全量 2591 通过 / 4 跳过 / 3 红(仍是改动前就在红的 三条:fork 依赖守卫、未入库的临时调试件、壁纸位置页计数断言);analyze 干净; 跑完无孤儿 flutter_tester。 | 5 天前 | |
整理(壁纸页玻璃): 撤掉按钮层那层重复的转场重绘驱动,测试改钉「每颗玻璃自带驱动」 起因是全量测试里 wallpaper_position_picker_glass_test.dart 那条红的:断言「驱动 节点只能有一个」,实际 5 个。查下来不是渲染坏了 —— 9614a6b6 让 LiquidGlassSurface 自己默认套 LiquidGlassTransitionRepaint(见其 build),本页按钮外面那层与本页四颗 玻璃各自带的那层完全重复,节点数从 1 变 5(外层 1 + 每颗各 1)。 按新设计收:撤掉 _buildOverlayLayer 里那层包装(机制本体仍在每块玻璃上生效,行为 不变),理由写进方法注释,避免下次照着「这里要罩一层」再补回来。 测试口径随之改:驱动沉进组件后树形反转了(玻璃是父、驱动是子),原来的「外面有一个 驱动、四颗都在它子树里」不再成立。改为断言「四颗玻璃各自都带一层驱动」,**刻意不钉 总数**——数量随页面玻璃数走,口径不该跟着变。(第一版改法用 find.ancestor 找外层 驱动,一颗都找不到,正是被这个反转顶回来的。) 验证:该文件 5 例全绿;全量 2600 通过 / 4 跳过 / 1 失败(唯一那条是 .gitignore 排除的 本机临时量测用例 _debug_material_sheet_test.dart,不进仓库、不影响 CI); flutter analyze 两个改动文件 0 issue。 | 5 天前 | |
修复(调试浮层·性能): 悬浮球无限脉冲动画让性能版静止 120fps 重绘、205% CPU 现象:打开性能版(perfProfile / .profile)放着不动,机身持续发烫。 真机实测(Redmi 25079RPDCC,同机同时段): - 性能版静止:6 秒烧 10.24 秒 CPU(≈205%),SurfaceView 持续 120.00 fps - 正式版静止:1.02 秒(≈17%),1~5 fps - 关掉浮层后:0.07 秒(≈1.2%),<1 fps 根因:flutter_blackbox 的悬浮球(_DraggableFloatingButton)在 initState 里挂了 AnimationController(1500ms)..repeat(reverse: true) 的无限脉冲动画(上游 blackbox_overlay.dart:955-961),只要浮层挂载就每帧请求新帧;而浮层在非 release 构建里默认可见(_visible = true,prefs 无该键时走默认),于是静止也满速重绘。 release 构建因 blackbox_host.dart 首行 kReleaseMode 短路,从不构造浮层。 改动: - blackbox_adapters.dart:trigger floatingButton() -> none()。上游 overlay:221 的 trigger is FloatingButtonTrigger 分支因此不再构造悬浮球,出帧源消除。 - blackbox_overlay_preferences.dart:_visible 默认 true -> false(含 load 兜底值)。 - blackbox_host.dart:新增 openBlackBoxPanel(),按需打开面板(浮层关着时先启用、 等两帧让 overlay 注册好回调再 BlackBox.open(),否则 open 是静默 no-op)。 - timetable_settings_screen.dart:开发者选项新增「打开调试面板」入口。 l10n 新增 debugUiOverlayOpenPanelTitle(6 语言,untranslated 为空)。 - test/ui/debug/blackbox_host_test.dart:补「默认必须隐藏」回归守卫。 验证:flutter analyze lib test 0 issue;test/ui/debug + timetable_settings_screen_test 12 passed;真机复测——浮层关 0.1%、浮层强制开 0.25%(旧代码同状态 205%)、 稳态连续 6 轮 0.2~1.2%。诊断报告见 docs/perf-flavor-overheat-diagnosis-2026-09-13.md。 | 14 天前 | |
fix(glass): 边光改「一圈均匀 + 按边界曲率加权」;模糊出界黑边落成扫描守卫 真机两条观感问题的根因与修法(同一批,跨多个表面): - **边光方向性**: glass_surface_refraction.frag 与 course_card_glass.frag 原先的边缘高光带方向(u_light_dir),长直边与圆角在同一圈上亮度不匀。 改为**一圈均匀、按边界曲率加权**(卡片那支「只落在转角上」)。roundedBoxSDF 顺带把中间量 q 交出去,避免边光与 SDF 各算一遍。 - **模糊出界的透明黑**:ImageFilter.blur 不给 tileMode 时默认 decal,模糊 结果会在离边约 3σ 的带里淡成透明黑 —— 凡是「模糊后的边可见」的表面都会读出 一条黑边(宽度随模糊量走、模糊调到 0 就消失,这是它的指纹)。真机已两次 实测(弹窗顶边、星期栏底边),第二次是另一个表面又漏同一处。 修法:liquid_glass_surface / hyperos_collapsible_top_app_bar 等处补 TileMode.clamp。 - 新增 test/architecture/blur_tile_mode_guard_test.dart:扫描 lib/ 下每一处 ImageFilter.blur 必须显式给 tileMode。这条规则原先只写在笔记里,于是 第二天在另一个表面上又踩了一次 —— 落成扫描测试后新增模糊忘了给就直接红。 - 其余:液态玻璃调参、弹窗/底栏/代理层的材质分派对齐、首页背景与预模糊壁纸、 课程卡玻璃、若干设置页入口与 QR 传输页的材质口径统一。 - timetable_provider.dart:新增 @visibleForTesting 的 seedHolidayDataForTesting(+10,只赋值 + 通知,无业务逻辑),供假期课 过滤类 UI 断言注入数据;dependency_guards_test.dart 的行数棘轮按本文件 既有约定同步基线到 4499 并注明理由。 | 7 天前 |