diff --git a/docs/ui-design.md b/docs/ui-design.md index a31f1d5..c6f92a2 100644 --- a/docs/ui-design.md +++ b/docs/ui-design.md @@ -116,6 +116,7 @@ Android 端保存这些设置,在应用关闭后刷新时读取当前系统颜 其他日期为 1px 淡色实线,直接位于卡片上方。当天课程的圆角作为蒙版,线在卡片内按 同色系强调色叠加:浅色模式加深、深色模式提亮,与已上时段的填充保持清楚对比, 保留文字明暗;圆角外自然露出原色。 +课程块空间不足时优先保留完整地点;课程名只使用剩余空间,并在必要时省略。 进度填充与时间线共享同一中心坐标;卡片的 2px 内缩只限制填充范围。 时间线始终按节次位置移动,课间停在节次边界,不在课程开始或结束时切换绘制方式。 课程结束后恢复普通底色;课表时段外,独立时间线仍停在下一次早课起点。 diff --git a/lib/schedule/ui/course_tile.dart b/lib/schedule/ui/course_tile.dart index 4f926c0..b94edb6 100644 --- a/lib/schedule/ui/course_tile.dart +++ b/lib/schedule/ui/course_tile.dart @@ -75,10 +75,15 @@ class CourseTile extends StatelessWidget { final narrow = constraints.maxWidth < 100; final fontSize = narrow ? 12.0 : 14.0; final media = MediaQuery.of(context); - final compact = constraints.maxHeight < + final compact = + constraints.maxHeight < 40 * media.textScaler.scale(1); - final horizontalPadding = compact ? 1.0 : (narrow ? 3.0 : 10.0); - final verticalPadding = compact ? 0.0 : (narrow ? 4.0 : 6.0); + final horizontalPadding = compact + ? 1.0 + : (narrow ? 3.0 : 10.0); + final verticalPadding = compact + ? 0.0 + : (narrow ? 4.0 : 6.0); final spacing = narrow ? 3.0 : 4.0; final width = constraints.maxWidth - horizontalPadding * 2; @@ -135,29 +140,22 @@ class CourseTile extends StatelessWidget { if (title.height + (roomLines > 0 ? room.height + spacing : 0) > available) { - title.maxLines = 1; - title.layout(maxWidth: width); - room.maxLines = 1; - room.layout(maxWidth: width); - final reserveRoom = - roomLines > 0 && - title.height + room.height + spacing <= available; - titleLines = _fittingLines( - title, - width, - available - (reserveRoom ? room.height + spacing : 0), - ); - roomLines = reserveRoom - ? _fittingLines( - room, - width, - available - title.height - spacing, - ) - : 0; + // Keep the location intact; the title uses leftover space. + if (roomLines > 0) { + roomLines = _fittingLines(room, width, available); + final titleSpace = available - room.height - spacing; + titleLines = titleSpace > 0 + ? _fittingLines(title, width, titleSpace) + : 0; + } else { + titleLines = _fittingLines(title, width, available); + } } title.dispose(); room.dispose(); - if (titleLines <= 0) return const SizedBox.shrink(); + if (titleLines <= 0 && roomLines <= 0) { + return const SizedBox.shrink(); + } return Padding( padding: EdgeInsets.symmetric( horizontal: horizontalPadding, @@ -166,18 +164,20 @@ class CourseTile extends StatelessWidget { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Flexible( - child: Text( - course.name, - textAlign: TextAlign.start, - softWrap: true, - maxLines: titleLines, - overflow: TextOverflow.ellipsis, - style: titleStyle, + if (titleLines > 0) + Flexible( + child: Text( + course.name, + textAlign: TextAlign.start, + softWrap: true, + maxLines: titleLines, + overflow: TextOverflow.ellipsis, + style: titleStyle, + ), ), - ), - if (roomLines > 0) ...[ + if (titleLines > 0 && roomLines > 0) SizedBox(height: spacing), + if (roomLines > 0) Text( course.room, textAlign: TextAlign.start, @@ -186,7 +186,6 @@ class CourseTile extends StatelessWidget { overflow: TextOverflow.ellipsis, style: roomStyle, ), - ], ], ), ); diff --git a/test/course_tile_test.dart b/test/course_tile_test.dart index d2a6a47..54ef0eb 100644 --- a/test/course_tile_test.dart +++ b/test/course_tile_test.dart @@ -170,15 +170,18 @@ void main() { expect(tester.takeException(), isNull); }); - testWidgets('Short cards ellipsize without overflowing', (tester) async { + testWidgets('Short cards keep the full room before the course name', ( + tester, + ) async { await showCard(tester, width: 52, height: 48); - final title = tester.renderObject(find.text(course.name)); - expect(title.didExceedMaxLines, isTrue); + final room = tester.renderObject(find.text(course.room)); + expect(room.didExceedMaxLines, isFalse); final card = tester.getRect(find.byType(CourseTile)); expect( tester.getRect(find.text(course.room)).bottom, - lessThanOrEqualTo(card.bottom - 6), + lessThanOrEqualTo(card.bottom), ); + expect(find.text(course.name), findsNothing); expect(tester.takeException(), isNull); });