- 重构版主提示词(14 parts,面向 ClassHelper 灵动岛重构) - ClassIsland 全量规格提示词(20 parts,含分卷与逐章版本) - 投喂指南、分卷、逐节文件 - 调研记录、一致性基线、生成与质检脚本
33 KiB
3. ClassIsland 灵动岛行为基准(重构对照规格)
本节是行为基准,不是像素规范。实现者(ChatGPT)在 ClassHelper 现有仓库内重构灵动岛时,必须让「fixed 默认风格(ClassIsland 信息行)」与「custom 常驻模式」在行为语义上与 ClassIsland 主界面(MainWindow / MainWindowLine / 组件系统 / 提醒系统)对齐;fixed 的 winisland 兼容风格只保留原胶囊交互即可,不要求对齐 ClassIsland。具体颜色、间距、圆角、阴影、字号、动画曲线上限等像素值一律以第 6 章(tokens)、第 7 章(结构与组件)、第 10 章(动画)为准,本节只给出「必须实现什么行为、判定顺序、默认值与边界」。凡本节与 ClassIsland 源码冲突,以源码行为为准;凡与 ClassHelper 既有业务规则冲突,以第 8 章的裁决表为准(ClassHelper 业务优先、ClassIsland 视觉优先)。
3.0.1 与 ClassHelper 三种运行形态的映射(口径,必须一致)
| ClassHelper 形态 | 目标语义 | 说明 |
|---|---|---|
fixed + 默认风格 classisland |
ClassIsland 风格信息行 | 默认 1 行 = 日期 + 课程表;行高 40、圆角 8、背景不透明度 0.5、底部 3px 进度条;消息到来时在同一行内展开 ClassIsland 风格气泡(遮罩阶段 + 正文阶段),暂存/紧急/叫人/已读/去重规则沿用 ClassHelper |
fixed + 风格 winisland |
原「胶囊 + 详情卡」形态 | 老用户升级默认保持 winisland;只做必要的动画/修 bug,不按 ClassIsland 规格重做几何与气泡 |
custom |
常驻多行 | 保留 schemes/rows/nodes/expandedRows/编辑器数据模型,按 ClassIsland 的行/组件/编辑/隐藏/动画规格重构渲染与交互 |
风格枚举落盘字段以 parts-r/05 为准(本节统一写作 appearance.family = 'classisland' | 'winisland',对应配置键 islandAppearance.style);新安装默认 classisland,升级用户默认 winisland。下文凡写「fixed」而未特别说明,均指默认风格 classisland 的信息行。
证据写法:repos/ClassIsland/... 指本工作区内的 ClassIsland 源码;packages/... 指 ClassHelper 源码。未在源码中确认的写【推断】。
3.1 主界面行(行为模型)
必须实现的模型:主界面是一个多行容器,每行(MainWindowLine)包含「背景层 + 内容层(组件集合) + 提醒层(遮罩/正文) + 进度条」。行是提醒的宿主,也是编辑的最小单位。
- 行高固定 40,且同一行内所有组件共享该高度;组件区左右内边距 12、最小内容宽 20(
repos/ClassIsland/ClassIsland/Controls/MainWindowLine.axaml:16;repos/ClassIsland/ClassIsland/XamlThemes/FluentTheme/Styles.axaml:110)。 - 行数无硬上限,但默认只有 1 行;行间距默认 5(
repos/ClassIsland/ClassIsland/Models/Settings.cs:219,范围 0–150、步进 5)。 - 必须存在且只存在一行「主行」(MainLine):删除到只剩 1 行时不得再删,必须提示「至少需要保留 1 个主界面行。」(
repos/ClassIsland/ClassIsland/Views/EditModeView.axaml:428文案,MainWindow.axaml.cs的删除守卫)。 - 行模板三分支(必须按条件选,不得混用,
repos/ClassIsland/ClassIsland/XamlThemes/FluentTheme/Styles.axaml:275-278):- Full:
IsNotificationEnabled = true,含遮罩/正文/进度条; - Min:
IsNotificationEnabled = false,只有背景与内容; - 分体(Separated):
IsIslandSeperated=true或行级IslandSeparationMode=2,整行背景改为每个顶级组件各自胶囊。
- Full:
- 行的可见性(必须逐条实现,
repos/ClassIsland/ClassIsland/Controls/MainWindowLine.axaml:29-49):
visible = ( (!IsAllComponentsHid || IsOverlayOpen) && (HideOnRule ? IsVisible : true) ) || IsEditMode
IsAllComponentsHid:该行所有组件都被隐藏时整行消失,不能留一条空胶囊;IsOverlayOpen:该行正在播提醒时必须可见(即使组件全隐藏);HideOnRule:该行命中隐藏规则集时隐藏;规则集变化要实时重算(订阅规则状态更新);- 编辑模式下永远可见。
- 行级不透明度默认 1.0(范围 0.1–1、步进 0.05),只作用于行内容;背景不透明度是另一个独立设置(默认 0.5),只作用于背景层,文字必须始终 100% 不透明(
repos/ClassIsland/ClassIsland/Models/Settings.cs:64,183-184)。 - 鼠标淡出(必须实现):
IsMouseInFadingEnabled(默认 true)与IsMouseInFadingReversed(默认 false)决定「指针不在行内时行变淡到 0.05」,判定用行的屏幕矩形(含 DPI 与缩放),编辑模式不淡出(repos/ClassIsland/ClassIsland/Controls/MainWindowLine.cs:503-509,619-637)。 - 行背景宽度 = 内容实际宽度,不是窗口宽度;内容宽度变化必须平滑跟随(Fluent 300ms / Classic 550ms),且不得触发窗口尺寸变化(
repos/ClassIsland/ClassIsland/Controls/MainWindowLine.cs:614-617;动画细节见第 10 章)。 - 行的提醒宿主能力:
AcceptsNotificationRequests = IsNotificationEnabled && !IsAllComponentsHid && !_isOverlayOpen && !_isUnloading——只有同时满足这些条件的行才能接收提醒;多行时由提醒分发规则决定落到哪一行(repos/ClassIsland/ClassIsland/Controls/MainWindowLine.cs:814)。 - 行级设置(必须保留在编辑器中可改):不透明度、是否允许显示提醒、隐藏规则、圆角/间距(继承全局或覆盖)、附加设置(见第 7 章)。
3.2 组件系统(11 类 + 容器)
必须实现 ClassIsland 的 11 种内置组件与 4 种容器(repos/ClassIsland/ClassIsland/Controls/Components/),并保留 ClassHelper 现有的同名组件作为承载:
| 组件 | 职责(行为) | 关键默认值 |
|---|---|---|
日期 DateComponent |
显示「今天」或自定义格式日期;支持农历/自定义模板(模板语法按组件设置) | 显示今天 |
时钟 ClockComponent |
显示当前时间;支持 12/24 小时、秒、自定义格式 | 24 小时制、显示秒 |
倒计时 CountDownComponent |
目标时间倒计时;目标可固定日期或「按课表倒数至上课/下课/放学」 | 见 3.7 |
课程表 ScheduleComponent |
今日时间点/当前课程/下一节,见 3.7 | 见 3.7 设置表 |
天气简报 WeatherComponent |
天气图标 + 温度 + 文本;多种主信息模式 | 见 3.10 |
文本 TextComponent |
静态文本,支持模板变量与滚动 | 见组件设置 |
滚动容器 RollingComponent |
单行内容超宽时循环滚动 | 见组件设置 |
轮播容器 SlideComponent |
多个子组件按间隔轮播 | 见组件设置 |
分组容器 GroupComponent |
子组件横向成组,统一间距 | 见组件设置 |
堆叠容器 StackComponent |
子组件纵向堆叠 | 见组件设置 |
分割线 SeparatorComponent |
竖线分隔,2px 宽 25px 高(视觉细节归第 7 章) | — |
必须实现的组件通用语义:
- 组件宿主间距:行内相邻组件水平间距 12(每个组件
Margin="6 0");容器组件内部用Margin="-6 0"抵消,避免嵌套累积(repos/ClassIsland/ClassIsland/MainWindow.axaml:396)。 - 组件可见性:组件自身有
IsVisible;行内「全部组件都不可见」→ 整行IsAllComponentsHid(见 3.1)。 - 组件级隐藏规则(
custom模式必须对齐):按in-class(上课中)、no-message(无消息)、no-class(无课/放学后)三个条件隐藏;ClassHelper 现有advanced.hideRules的三值语义与之一一对应,必须保留。 - 组件宽高:
advanced.align/width/maxWidth必须生效;stretch为默认,剩余空间按 flex 分配。 - 组件的附加设置:附加设置可挂在科目/时间点/课表/时间表(ClassIsland 语义,见第 7 章),本重构只保留 ClassHelper 已有的「课程控件附加设置」语义,不引入 ClassIsland 本地档案。
- 编辑态:所有组件必须可被点击选中、可拖动排序、可跨行移动;容器组件展开子项供选择(第 9 章编辑器规范)。
- 空数据兜底:任何组件在无数据时必须渲染占位(不得空白、不得抛错),占位文案与场景见第 7 章。
3.3 编辑模式(行为语义)
必须实现「编辑模式」作为岛的唯一配置入口,行为如下(repos/ClassIsland/ClassIsland/MainWindow.axaml.cs:510-528,1391-1403):
- 进入条件:菜单「编辑主界面…」或 URI
classisland://app/edit;进入前必须通过权限校验(ClassHelper 侧对应「已登录班级设备」判断)。 - 进入步骤(按序):置编辑标志 → 激活窗口 → 挂载编辑视图 → 同步特效窗口的编辑态(编辑期间不播强提醒特效)→ 更新窗口层级 → 编辑模式下窗口必须接收鼠标。
- 编辑画布:画布覆盖整个屏幕;岛内容在画布内按停靠位置排布,并预留底部操作栏空间(操作栏高度 64 的语义见第 7/9 章);编辑模式内容整体垂直居中。
- 编辑态可见性:所有行、所有组件(含被隐藏规则隐藏的)都必须可见可选中;隐藏规则命中时以半透明/斜纹提示,而不是直接消失。
- 底部操作栏(行为):重置视图、外观抽屉、添加组件抽屉、组件配置方案、完成;「完成」退出并保存。
- 两级抽屉:主抽屉(外观/添加组件/配置方案)与次抽屉(组件设置);抽屉打开时挂载「逐项入场」动画;拖拽组件时主抽屉自动临时收起,结束后恢复。
- 退出:关闭抽屉 → 清编辑标志 → 清教程提示 → 保存组件配置(保存必须幂等、原子:写临时文件再替换);退出后恢复逐像素透明与点击穿透。
- 编辑期间:不得创建额外桌面窗口;不得因编辑导致提醒被丢弃(提醒进队列,退出后按规则补播);强提醒特效丢弃但提醒本体照常。
- 配置方案:支持多套组件配置方案(ClassHelper 现有
schemes),方案切换即时生效并持久化;方案 JSON 导入导出走本机配置,不上服务端。
3.4 隐藏与显示规则(完整判定)
必须实现两档 hideMode(默认 0,repos/ClassIsland/ClassIsland/Models/Settings.cs:185;repos/ClassIsland/ClassIsland/MainWindow.axaml:150-163):
- 0 基本:三个独立开关,全部默认
false:HideOnClass:当前时间状态为「上课」时隐藏;HideOnMaxWindow:前台窗口最大化时隐藏;HideOnFullscreen:前台窗口全屏时隐藏。
- 1 高级:用规则集
HideRules求值(规则集/逻辑见第 8 章的规则语义;ClassHelper 侧只保留独立开关 + 上课状态条件,不引入完整规则集)。
检测数据源与频率:
- 全屏/最大化状态在每个主计时器 tick 检测,基准屏幕必须是「岛所在屏幕」(
repos/ClassIsland/ClassIsland/MainWindow.axaml.cs:451-456)。 - 排除进程名单
ExcludedFullscreenWindow默认["explorer"]:这些进程在前台时不算全屏/最大化(repos/ClassIsland/ClassIsland/Models/Settings.cs:56-59)。 - 强制显示(覆盖隐藏):正在播放提醒或处于编辑模式时,即使命中隐藏条件也必须显示,并临时置顶(见 3.9 的置顶锁语义)。
- 手动隐藏:
IsMainWindowVisible(默认 true)为用户手动开关;手动隐藏时同时不接受新提醒(与 3.1 第 9 条一致)。 - 全部隐藏:所有行都隐藏时,可见内容
opacity:0,窗口包围盒不变、窗口不销毁,保证提醒到来能立刻显示(repos/ClassIsland/ClassIsland/MainWindow.axaml:135-141)。 - ClassHelper 映射要求:
custom模式的「常驻」不能被HideOnClass直接隐藏——上课时只允许按hideRules:in-class隐藏指定组件;fixed+classisland信息行按 ClassIsland 默认(HideOnClass=false)上课也保持可见,只是「普通消息暂存、紧急/叫人例外」;不得回到「上课即整岛隐藏」;fixed+winisland兼容形态保留 ClassHelper 原规则(上课时普通消息暂存并隐藏岛体,紧急与叫人例外,见 3.9 与第 8 章)。
3.5 多显示器、停靠与点击穿透
- 6 个停靠位置:顶/底 × 左/中/右(
0/1/2贴工作区上边、3/4/5贴下边;左/中/右分别为贴左/居中/贴右),窗口始终横跨整屏,岛在窗口内形变(repos/ClassIsland/ClassIsland/Models/Settings.cs:48)。 - 偏移:
WindowDockingOffsetX/Y必须生效;顶部停靠时正值向下偏移不得被屏幕边缘裁掉(偏移吞进安全区)。 - 多显示器:
WindowDockingMonitorIndex选择目标屏;可选「跟随鼠标所在屏」(ClassHelper 现有followCursorDisplay保留)。 - DPI:所有几何与命中必须按「物理像素 × 缩放」换算,4K@150% 与 1080p@100% 下不得出现 1px 白边、黑边、圆角锯齿;圆角为 0 时是直角,为最大值时左右边缘为半圆。
- 点击穿透:非编辑模式下,岛默认鼠标穿透(点击落到桌面应用);只有指针真正在岛体上时才接收鼠标;编辑模式下必须接收(
repos/ClassIsland/ClassIsland/MainWindow.axaml.cs:839;ClassHelperpackages/desktop-client/src/main/island.ts:2000-2080的命中轮询必须保留)。 - 置顶锁:提醒播放期间临时置顶,多提醒时以「锁计数」方式管理——只有最后一个锁释放才还原层级,避免闪烁(
repos/ClassIsland/ClassIsland/MainWindow.axaml.cs:1056-1092)。
3.6 时间状态机与跨天(课程计算的唯一事实源)
- 主计时器周期 50ms,优先级 Render;每 tick 顺序:
PreMainTimerTicked→ 计算 →PostMainTimerTicked(repos/ClassIsland/ClassIsland/Services/LessonsService.cs:39-45,373-388)。ClassHelper 映射为主进程单一 1s/50ms 混合节拍(秒级 UI 用 1s,跨点判定用 50ms【推断:可降到 200ms,见 3.13 性能非功能】)。 - 时间状态枚举:
None / OnClass / PrepareOnClass(预留) / Breaking / AfterSchool(repos/ClassIsland/ClassIsland.Shared/Enums/TimeState.cs:6-27)。 - 每 tick 计算顺序(必须逐条实现):
- 清理过期临时课表/临时层/临时课表群;
- 若「加载课表」关闭 → 当前课表为空;
- 选当天课表(预定 > 临时 > 常规,详见 parts/06 §6.2);
now = 当前本地时间;- 当前时间点 = 有效时间点中第一个
TimeType∈{0,1}且StartTime ≤ now ≤ EndTime; - 上课 →
CurrentState=OnClass并映射科目;课间 →CurrentState=Breaking,CurrentSubject=课间科目(名称=课间名); - 下一节 = 第一个
TimeType=0 && EndTime ≥ now;下一个课间 = 第一个TimeType=1 && EndTime ≥ now; - 剩余时间:上课时算「距下课」,否则算「距上课」;下限钳 0;
- 下一节与下一课间都不存在 →
AfterSchool; - 统一回写(未算出用默认值);状态变化时才发事件,顺序固定「先
CurrentTimeStateChanged,再按新状态发OnClass/OnBreakingTime/OnAfterSchool」。
- 有效时间点的双向裁剪:禁用一节早课 → 其前所有时间点不显示;禁用一节晚课 → 其后所有时间点不显示(
repos/ClassIsland/ClassIsland.Shared/Models/Profile/ClassPlan.cs:54-98)。ClassHelper 侧映射为「ScheduleDto投影 + 当前时间点/下一节,由服务端解析结果决定」,不得在客户端重写轮换规则。 - 跨天:每次 tick 检测日期变化;跨天必须重新取当天课表、清除「今天」的已提醒标记、重置课程提醒状态机(
LessonReminderTracker的dayKey变化),不得沿用昨天的「已提醒」状态。 - 时间突变(手动改系统时间、NTP 校正、睡眠唤醒):下一次 tick 必须按新时间重新判定状态;不得补发错过的提醒,也不得因时间回退而重复发出同一提醒(用「状态变化」而非「时间比较」触发)。
3.7 课程表组件的行为(重点)
课程表组件是「一行多条课程」的核心,ClassHelper 的 schedule 组件必须按下列行为实现(视觉像素见第 7 章):
3.7.1 显示哪些时间点(必须逐条判定,repos/ClassIsland/ClassIsland/Controls/Components/ScheduleComponent.axaml.cs:243-251)
对当天每个时间点:
TimeType ∈ {2 分割线, 3 行动}不作为课程项显示(分割线由专门的竖线控件渲染;行动不显示);HideFinishedClass=true且EndTime < now→ 不显示;IsHideDefault=true且不是当前选中项 → 不显示;TimeType==1(课间)且不是当前选中项 → 不显示;ShowCurrentLessonOnlyOnClass=true且当前选中项是上课类型且该项不是当前项 → 不显示。
映射到 ClassHelper(custom 模式的 schedule 组件):display:'today' 必须实现「只当前项展开、其余折叠」的 ClassIsland 语义:
- 上课点折叠只显示课程名;当前时间点展开显示「课程名 + 起止时间」;
- 课间与
isHideDefault的上课点折叠时完全隐藏,轮到它们成为当前项时才出现; - 分割线
DIVIDER渲染为一条竖线;ACTION完全不显示(packages/shared/src/class-plan.ts:4,70-87;packages/desktop-client/src/island/ComponentNode.vue:48-80); - 无时间点数据时回退按
ScheduleDto条目显示课程(docs/app/island.md:69); - 倒计时/徽标只在「当前时间点临近结束」时出现,不得常驻。
3.7.2 三种课程呈现
必须实现三种课程项(repos/ClassIsland/ClassIsland.Core/Controls/LessonsControls/):
- 展开型:科目名(强调字号)+ 附加信息 + 进度条;左右留白按「课程表文本间距」缩放(默认 1,范围 0.2–1,左右各 16×间距);
- 最小型:只显示科目首字(
Subject.Initial),用于IsHideDefault时间点或「上课时仅显示当前课程」; - 分割线:2px 竖线、高 25、次要色、透明度 0.8。
已结束课程淡化:FadeCompletedClasses 默认 true,透明度 0.6,过渡 150ms(CubicEaseInOut);HighlightChangedClass 默认 false,换课课程高亮(强调色块)。
3.7.3 附加信息与倒计时(必须实现 6 种 ExtraInfoType)
ShowExtraInfoOnTimePoint=true 时,当前课程可显示(repos/ClassIsland/ClassIsland/Controls/Components/LessonControlExpanded.axaml:85-171):
| 值 | 显示 | 格式 |
|---|---|---|
| 0 | 起止时间 | hh:mm-hh:mm |
| 1 | 已过时间 | -mm:ss |
| 2 | 剩余时间 | -mm:ss |
| 3 | 进度百分比 | N% |
| 4 | 模糊倒计时 | -<1min(按 CountdownSeconds 向上取整) |
| 5 | 精确倒计时 | -mm:ss |
当前课程剩余时间药丸:IsCountdownEnabled=true 时,当前时间点剩余 ≤ CountdownSeconds(默认 60)才出现;精确模式 -mm:ss,非精确模式 <<数值(IsNonExactCountdownEnabled=false,LessonControlExpanded.axaml:173-214)。
课程进度条:贴底、Maximum=1、值为课程进度、高度 3px(视觉细节归第 7 章);进度更新必须按「比例插值」而非每帧重算布局。
3.7.4 空状态与明天课表
- 空占位(默认显示,
ShowPlaceholderOnEmptyClassPlan=true):- 今天没有课表 →
"今天没有课程。"; - 今日课程全部结束且
HideFinishedClass=true→"今日课程已全部结束。"; - 垂直居中、正文色;占位与课程列表互斥。
- 今天没有课表 →
- 明天课表
TomorrowScheduleShowMode默认1:0不显示、1放学后显示、2总是显示、3今天无可显示课程时显示;显示时左侧出现「明天」药丸、主列表隐藏。 AfterSchool判定 = 当前时间状态为放学后或今天没有课表。
3.7.5 课程表组件设置默认值(必须照抄)
| 字段 | 默认 | 说明 |
|---|---|---|
ShowExtraInfoOnTimePoint |
true |
显示附加信息 |
ExtraInfoType |
0 |
0–5 |
IsCountdownEnabled |
true |
结束倒计时药丸 |
CountdownSeconds |
60 |
阈值(秒) |
IsNonExactCountdownEnabled |
false |
模糊倒计时 |
ScheduleSpacing |
1 |
0.2–1 |
ShowCurrentLessonOnlyOnClass |
false |
上课仅显示当前课程 |
HideFinishedClass |
false |
不显示已结束课程 |
FadeCompletedClasses |
true |
淡化已上课程 |
HighlightChangedClass |
false |
标记换课 |
ShowPlaceholderOnEmptyClassPlan |
true |
空态占位 |
PlaceholderTextNoClass |
"今天没有课程。" |
文案 |
PlaceholderTextAllClassEnded |
"今日课程已全部结束。" |
文案 |
TomorrowScheduleShowMode |
1 |
0–3 |
(证据:repos/ClassIsland/ClassIsland/Models/ComponentSettings/LessonControlSettings.cs:8-23;repos/ClassIsland/ClassIsland/Models/Settings.cs:103-109,208-209,221。)
3.8 提醒队列与优先级(行为)
ClassIsland 的提醒是统一管线,必须实现以下行为:
- 一切提醒都进同一管线:上下课、放学、天气、集控、行动触发的提醒共用队列与消费者;不得各写一套弹窗。
- 两层 UI:遮罩(Mask,短文案,第一阶段)+ 正文(Overlay,详细内容,第二阶段);无正文时只播遮罩(
repos/ClassIsland/ClassIsland.Core/Models/Notification/NotificationRequest.cs:40-63)。 - 队列与优先级:
- 提供方优先级:
NotificationProvidersPriority数组下标越小越先播;设置页可拖动排序。 - 同提供方内先入队先播(FIFO)。
- ClassIsland 源码的
IsPriorityOverride比较器存在取反异常(repos/ClassIsland/ClassIsland.Shared/Models/Notification/NotificationPriority.cs:47-50);本轮目标语义按第 8 章裁决:三级排序键(提供方下标 → 通知等级 Emergency>High>Normal>Low → 入队序),不照抄异常行为。
- 提供方优先级:
- 去重:同一 request 对象只入队一次;出队用「已弹出集合」避免链式头节点重复;天气预警按
Detail会话内去重;ClassHelper 侧另有「同 id 通知/叫人双播合并」规则(见第 8 章),两者不冲突。 - 链式提醒:数组请求串成链,任一子请求取消即取消全部;准备上课 + 上课是典型链(
repos/ClassIsland/ClassIsland/Services/NotificationHostService.cs:205-254)。 - 消费者:按优先级排序,只有
AcceptsNotificationRequests && QueuedNotificationCount<=0才推送;无消费者时退回队列;播放完主动拉取后续(NotificationHostService.cs:337-419)。 - 播放状态机:
None → Queued → Playing →(Paused/Cancelled/Completed);取消/完成分别触发对应令牌回调;被中断但未被取消的提醒必须重新入队(NotificationHostService.cs:488-522)。 - 取消与清理:
CancelAllNotifications清空队列 + 取消所有正在播放的请求;用户入口为主界面右键菜单「清除全部提醒」,仅在「有提醒正在播放」时可见(repos/ClassIsland/ClassIsland/MainWindow.axaml:86-94);不实现独立「清除提醒浮动按钮窗口」(源码#if false遗留)。
3.9 通知两层 UI(气泡 + 强提醒)
3.9.1 气泡(行内)行为
- 遮罩阶段:背景切换为强调色 + 斜切遮罩扫入 + 遮罩文字入场;此阶段不显示详情。
- 遮罩结束:有正文则切正文(背景恢复、正文淡入、底部进度条显示剩余时间);无正文则直接收起。
- 正文阶段:内容 + 底部进度条(
Maximum=1、Value=剩余进度、值过渡 50ms 线性);显示时长由内容Duration或EndTime决定。 - 结束时:正文淡出 → 遮罩退出 → 行恢复原状;队列里还有提醒则继续播下一条。
- 提醒期间行的可见性:强制可见(覆盖隐藏规则),并置顶;提醒结束释放置顶锁。
- 关键动画参数(语义;完整表见第 10 章):斜切遮罩 5 区段、区段 360ms、错峰 120ms、开
QuarticEaseOut/关QuadraticEaseIn;遮罩文字delay 260ms、淡入 250ms、缩放 1.1→1.0、750ms,曲线(0.25,1,0.5,1);退出文字 200ms、缩放 1.0→1.1、曲线(0.5,0,0.75,0);正文淡入淡出 200ms、SineEaseIn。Classic 主题是另一套(上滑/下压)语义,必须两套都保留。 - 音效与 TTS:ClassIsland 支持提醒音效与语音(默认关闭语音、音效音量 1.0);本轮重构不实现音效/TTS(ClassHelper 无音频通道,见 3.13),只保留视觉提醒。
3.9.2 强提醒(Topmost 全屏特效)行为
- 触发:提醒开始且生效设置开启「强调特效」、主界面可见、行未全部隐藏、本次遮罩尚未播过声音。
- 表现:从行中心向全屏扩散的涟漪(默认强调色),扩散 600ms + 淡出 600ms,750ms 后移除元素;特效窗口为独立透明置顶窗口,逐屏覆盖主界面所在屏幕,按
NotificationEffectRenderingScale(默认 1.0)缩放。 - 生命周期:特效元素集合为空即隐藏窗口,不销毁;非
OSShutdown/ApplicationShutdown时禁止关闭窗口;编辑模式下丢弃新特效。 - 必须支持多屏:每个显示器一个特效窗口,屏幕/DPI 变化时重算位置与尺寸。
- ClassHelper 映射:
custom/fixed共用同一套特效窗口;动画速度倍率缩放 600/750ms;animations=false时不播特效只播气泡。
3.10 天气展示(行为)
- 数据频率:天气服务每 5 分钟刷新一次,启动立即刷新一次;刷新成功才置「已刷新」标志,所有依赖天气的提醒/规则先判该标志(
repos/ClassIsland/ClassIsland/Services/WeatherService.cs:41-44,69-71,386-389)。 - 缓存:最近一次天气持久化在设置中,重启先展示旧数据并标注更新时间;刷新失败保留旧数据,不清空。
- 组件展示:天气组件有多种主信息模式(图标 + 温度 + 文本;默认展示当前天气+温度);无数据时显示占位。
- 提醒:气象预警与天气预报的提醒在「上课 / 课间」事件时触发;预警按
Detail会话内去重、显示时长按文本长度钳制 10–90 秒;预报正文 15 秒;预警要求数据已刷新。 - 本轮范围:ClassHelper 已有 Open-Meteo 天气简报(15 分钟缓存、断网标「缓存」、无官方气象预警)。重构后必须保留 ClassHelper 数据源与行为,ClassIsland 的「气象预警/三天预报/逐小时预报提醒」不实现(见第 8 章冲突裁决)。
3.11 主题语义(Fluent vs Classic 的差异)
必须保留两套「风格」的概念(ClassHelper islandAppearance.style 默认 classisland,回退 winisland),差异只体现在行为参数上:
| 维度 | Fluent(默认目标) | Classic(可选回退) |
|---|---|---|
| 行宽过渡 | 300ms、(0.65,0,0.35,1) |
550ms、(0,1,0.5,1.1)(带过冲) |
| 遮罩入场 | 斜切 5 区段扫入 + 文字延迟 260ms | 整层上滑/下压(Y -50→0,200ms QuadraticEaseIn) |
| 遮罩退场 | 文字淡出 200ms + 缩放 | 下移 0→50、200ms QuadraticEaseOut、延迟 100ms |
| 行列表面 | 中性填充 + 1px 描边 + 阴影 0 4 8 2 #48000000 |
类似,但强调色/描边更强 |
| 分体 | 每组件独立胶囊(min-width 40、padding 0 16) | 同语义,参数略异 |
| 主题色来源 | 系统强调色/自定义 | 同 |
硬约束:背景不透明度只作用于背景层;文字始终不透明;投影必须常驻声明、只改参数(禁止在开合瞬间增删 filter);两套主题共用同一行为状态机,只切换视觉参数。
3.12 动画语义总则(实现时必须遵守)
- 进场慢、退场快:进场 200–300ms,退场 100–150ms;提醒遮罩文字淡入 250ms、淡出 200ms,属于「进场慢退场快」的允许例外(遮罩退场本身另有 100–200ms 的层退出)。
- 延迟表达因果:先扫入(0–360ms)、再文字(+260ms)、再投影(+600ms);不得所有元素同时启动。
- 错峰封顶:列表入场每项 25–35ms,超过 10 项必须封顶;不得线性累加到 1 秒以上。
- 可打断:进/出必须成对、可反向,反向时新动画直接覆盖旧动画(不排队);不得用 JS 计时器模拟状态机。
- 动画不改业务:动画只表达状态,不得在动画结束回调里发请求或用动画时长当业务计时。
- 最终几何一致:动画结束后元素几何必须与「无动画直跳终态」逐像素一致。
- 动画级别:
AnimationLevel0/1/2(默认 1);级别 0 禁用动画但主界面提醒动画不在此列(设置项描述明确);同时响应系统「减少动态效果」(视为级别 0 + 时长 1ms,加载指示器放慢不停)。 - 性能禁忌:不对包含文字的容器做
width/margin过渡(用绝对定位背景层或clip-path/scaleX);卡片投影用box-shadow不用filter: drop-shadow;透明窗口禁用setBackgroundMaterial()。
3.13 本轮不实现的 ClassIsland 能力(必须写进实现说明,不得遗漏标注)
以下能力在 ClassIsland 基准里存在,但本轮重构明确不实现,实现者不得自行扩展、也不得因缺失判为缺陷:
- 自动化系统(触发器/行动/规则集/时间点行动):不实现;岛内不出现自动化入口。
- 插件系统与插件市场:不实现;不引入
.cipx、不加载第三方 DLL/模块。 - 主题市场/主题包/壁纸取色:不实现(壁纸取色在 ClassIsland 也已是 P2 停用状态);只做岛内两套风格(
classisland/winisland)。 - 集控/管理端(ManagementServer、策略、审计、授权级别):不实现;ClassHelper 用服务端权限体系替代。
- Excel 导入/导出、档案导入导出、CSES 互转:不实现(属 ClassIsland 本地档案能力);ClassHelper 继续用服务端课表/YAML 导入。
- 自动更新器、启动闪屏、OOBE、欢迎向导、教程中心、崩溃恢复窗口、作者/致谢窗口:不实现(属其它 part/非岛范围)。
- 提醒音效与 TTS(系统 TTS / Edge TTS):不实现;本轮只做视觉提醒。若未来需要,作为独立扩展项,默认关闭。
- ClassIsland 的「即将下课」遮罩:不实现——课程临近下课的提示统一走 ClassHelper 的「课程名右侧蓝色秒数徽标」(见第 8 章裁决)。
- 本地档案/Profile/TimeLayout/CSES 体系:不实现;数据继续用 ClassHelper 服务端解析结果(
ScheduleDto/IslandTimePointDto)。 - 通知音效音量、静音时段、语音源切换:不实现(ClassIsland 有,ClassHelper 无对应通道)。
3.14 验收标准(行为级)
实现者必须逐条自查,全部通过才算完成本节:
- 多行场景:1→5→1 行增删后,行可见性与「主行」约束正确;只剩 1 行时删除被拒绝且提示「至少需要保留 1 个主界面行。」。
- 行可见性表达式三态:组件全隐藏时整行消失;提醒期间强制可见;编辑模式下隐藏行也可见可选。
- 隐藏规则:
hideMode=0三个开关各自生效,explorer前台时不算全屏;提醒/编辑时覆盖隐藏;手动隐藏后不再接收新提醒;全部隐藏时内容透明度为 0 但窗口不销毁。 - 时间状态机:构造「上课→课间→放学」一天,状态与事件顺序正确(状态改变事件先于具体事件);禁用一节早课/晚课后,时间点的双向裁剪与「今天没有课程」占位一致。
- 课程表组件:6 种附加信息、倒计时药丸阈值 60 秒、已结束课程淡化 0.6、明天课表 4 种模式、无课表/全部结束两种占位文案全部正确。
- 提醒:两条提醒先后入队,第一条播完自动播第二条;提醒期间行强制可见并置顶,结束后释放;右键「清除全部提醒」仅在有提醒时出现并立即清空。
- 强提醒:开启特效时从岛中心扩散涟漪,600ms 扩散 + 600ms 淡出、750ms 后消失;编辑模式下不播;多屏时覆盖岛所在屏。
- 主题:Fluent 与 Classic 两套的遮罩入场/退场行为不同(斜切 vs 上下滑),行宽过渡 300ms vs 550ms;切换主题不改变任何业务状态。
- 动画:
AnimationLevel=0时除岛提醒外无动画;系统「减少动态效果」下时长压到 1ms 且加载指示器不停;动画结束后几何与直跳终态一致。 - 非目标确认:界面上不存在自动化、插件、主题市场、集控、Excel 导入、音效/TTS 入口;代码中不存在对应依赖。
- 形态映射:新安装默认
family='classisland'的信息行(日期+课程表、行高 40、底部 3px 进度条),升级用户默认family='winisland'的胶囊形态;custom仍走 schemes/rows/nodes;三种形态切换不丢消息、不重建第二个岛窗口。