-
Notifications
You must be signed in to change notification settings - Fork 8
Edit Table
TL;DR:编辑单张课表的属性(名称/学期开始日期/总周数/节次时间表),以及「所有课表」列表页的新建、复制、切换、删除动线。给想了解多课表机制的用户和贡献者。
一张课表对应 Room 表 time_tables 中的一行,实体是 TimeTableEntity。编辑屏直接操作的四个字段:
| 字段 | 含义 | 默认值 |
|---|---|---|
name |
课表名称 | — |
startDate |
学期开始日期,yyyy-MM-dd
|
— |
maxWeek |
学期总周数 | 20 |
timeJson |
每节课的上下课时间 JSON | TimeTableUtils.DEFAULT_TIME_JSON |
完整的实体定义见 app/src/main/java/com/lingion/sleepy/data/entity/TimeTableEntity.kt:13。另有 nodesPerDay(默认 12,TimeTableEntity.kt:24)、smartConfigJson(v1.0.16 自动模式配置,空串表示走手动模式,TimeTableEntity.kt:41)、createdAt(列表页展示导入时间,TimeTableEntity.kt:43)。
入口在「我的」页的「所有课表」项(app/src/main/java/com/lingion/sleepy/ui/screen/mine/MineScreen.kt:115),经 MainActivity 以覆盖层方式打开(app/src/main/java/com/lingion/sleepy/MainActivity.kt:300)。tableId == null 时编辑当前表,否则按 id 查找(app/src/main/java/com/lingion/sleepy/ui/screen/mine/EditTableScreen.kt:90);查不到显示「课表数据未找到」(EditTableScreen.kt:98)。
-
课表名称:单行输入,保存时空名称回落到原名(
EditTableScreen.kt:288)。 -
学期开始日期:手输加日历图标,弹出原生 DatePicker,与导入确认弹窗同款组件(
EditTableScreen.kt:184)。 -
总周数:只允许输入数字,
onValueChange里filter { it.isDigit() }(EditTableScreen.kt:193);解析失败保存时取 20(EditTableScreen.kt:273)。
折叠面板,标题下方显示「N 节课 · 点击展开/收起」(EditTableScreen.kt:228)。展开后是 TimeSlotEditor,支持手动逐行编辑和基于 SmartPeriodConfig 的自动模式两条路径(EditTableScreen.kt:249)。保存时把行重建为 timeJson 写回(EditTableScreen.kt:291)。
点「保存课表设置」先跑三条校验,任一不过就显示「日期需为 yyyy-MM-dd,时间需为 HH:mm 且开始早于结束」(EditTableScreen.kt:274-279)。通过后做两件事:
-
DateUtils.normalizeStartDate(startDate)把日期归一到所在周的周一再写库(EditTableScreen.kt:289,归一逻辑在app/src/main/java/com/lingion/sleepy/util/DateUtils.kt:60)。 - 走
updateTableRemappingCourses而非普通更新:如果timeJson变了,课程节次按绝对时间自适应新表。ownTime 课用timeToNode直接定位,普通课用remapCourseNodes重排,否则 16 节改成 12 节后课程会停在已不存在的 13-16 节(app/src/main/java/com/lingion/sleepy/data/repository/ScheduleRepository.kt:98)。
「删除课表」按钮只在 pendingNewTableId == null 时显示——新建还没保存的表,退出即丢弃,没有删除入口(EditTableScreen.kt:312)。点击后弹确认框:表里有课时文案是「确定要删除课表「%1$s」吗?共 %2$d 门课程将一并删除,此操作不可撤销。」,空表则是「确定要删除课表「%1$s」吗?此操作不可撤销。」,课程数量明示给用户(EditTableScreen.kt:337-343)。
最后一张表也允许删,删完由主界面真空态接管(EditTableScreen.kt:310-311 的设计注释)。删除时仓库层先收集该表全部课程 id,级联删除后对这些 id 显式取消课程级课前闹钟,避免孤儿闹钟继续响(ScheduleRepository.kt:123)。
覆盖层入口同上(MainActivity.kt:288)。列表按 createdAt 倒序排,最新建的/最新导入的排最前(app/src/main/java/com/lingion/sleepy/data/dao/TimeTableDao.kt:37)。
每行对比 table.id == state.selectedTableId 判断是否当前表(app/src/main/java/com/lingion/sleepy/ui/screen/mine/AllTablesScreen.kt:84)。当前行:
- 背景用
primaryContainer,左侧是CheckCircle对勾图标;非当前行是surfaceContainer加一个实心方块(AllTablesScreen.kt:89,AllTablesScreen.kt:100)。 - 副标题显示「当前课表 · 第 N 周」;非当前行显示「开始日期: yyyy-MM-dd」(
AllTablesScreen.kt:131)。 - 每行还显示导入时间,格式
yyyy-MM-dd HH:mm:ss,前缀「导入于」(AllTablesScreen.kt:136)。
点非当前行就切换:viewModel.selectTable(table.id),选中态就地高亮,页面留在原地,靠返回键离开(AllTablesScreen.kt:90)。切表会同步数据库 isDefault,让桌面组件跟随 App 当前选中的表(app/src/main/java/com/lingion/sleepy/ui/screen/schedule/ScheduleViewModel.kt:119)。
-
复制图标:调
duplicateTable,全量复制表配置和课程;新副本命名沿用导入路径的去重规则(原名追加「2」「3」…),groupId整组映射到新 UUID 保证副本内课程仍可整组编辑;副本不接管默认表也不切选中;建表加插课包在一个撤回批次里,撤回一次整步回退(ScheduleViewModel.kt:141)。 -
设置图标:进入该表的
EditTableScreen(AllTablesScreen.kt:158)。
列表底部是「新建课表」按钮(AllTablesScreen.kt:169)。点下后 MainActivity 先调 createEmptyTable(commitSelection = false)——插入一张空表但不动选中——然后直接带着 pendingNewTableId 跳进编辑屏(MainActivity.kt:290-296)。空表的初始值:名称按「默认 N」去重取号,startDate 自动填上周周一,isDefault 只在全库无表时为 true(ScheduleViewModel.kt:171)。
这条动线是一个「暂存-确认」流程:
-
点保存:正常走
onSaved,暂存表转正。 -
点返回:触发
onDiscardPending,调discardNewTable删掉这张从未保存的表,选中回退到之前的默认表或剩余第一张(ScheduleViewModel.kt:227,MainActivity.kt:302-306)。
核心计算在 DateUtils.currentWeek(app/src/main/java/com/lingion/sleepy/util/DateUtils.kt:35):
val start = mondayOf(LocalDate.parse(startDate, dateFormat))
val days = ChronoUnit.DAYS.between(start, today)
maxOf(1, (days / 7).toInt() + 1)三条规则:
-
起点归一到周一。应用约定
startDate必须是周一(day=1 对应周一),但用户手填或历史数据可能是任意日期,mondayOf用previousOrSame(MONDAY)把它拉回所在周的周一(DateUtils.kt:56)。不归一会出现「startDate 填周二,日期偏移一整周」的错位。 - 7 天一周向上取整。从归一起点到今天隔了几天,除以 7 加 1,得到 1-based 周次。开学第一天所在周就是第 1 周。
-
下限钳制到 1。学期开始前
currentWeek返回 1;学期结束后,semesterStatus按maxWeek判定AFTER_END,周次可浏览但不落在学期内(DateUtils.kt:20)。
反方向换算也有:由「第几周 + 星期几」推具体日期用 dateOfWeek,同样以归一后的周一为基准加 (week-1) 周加 (dayOfWeek-1) 天(DateUtils.kt:68)。
保存编辑屏时 normalizeStartDate 已把日期落到周一,所以库里的 startDate 日常就是周一;归一逻辑是为历史数据留的保险。
Sleepy Wiki
入门
界面与视图
课程管理
导入导出
小组件与提醒
数据与设置
项目
社区