Files
TPSchedule/mobile/lib/features/timetable/timetable_page.dart
T

181 lines
6.0 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import 'package:flutter/material.dart';
import '../../app/app_controller.dart';
import '../../app/app_theme.dart';
import '../../domain/schedule_engine.dart';
import 'week_grid.dart';
class TimetablePage extends StatefulWidget {
const TimetablePage({super.key, required this.controller});
final AppController controller;
@override
State<TimetablePage> createState() => _TimetablePageState();
}
class _TimetablePageState extends State<TimetablePage> {
int? _week;
bool? _wasDemo;
@override
Widget build(BuildContext context) {
final c = widget.controller, term = c.visibleSettings.semester;
final today = ScheduleEngine.schoolDate(c.clock());
if (_wasDemo != c.isDemo) {
_week = null;
_wasDemo = c.isDemo;
}
final current = term == null
? 1
: (ScheduleEngine.weekNumber(term, today) ?? 1);
final week = (_week ?? current).clamp(1, term?.totalWeeks ?? 1);
final monday = term == null
? today.subtract(Duration(days: today.weekday - 1))
: term.firstMonday.add(Duration(days: (week - 1) * 7));
final sunday = monday.add(const Duration(days: 6));
return ListView(
key: const PageStorageKey('timetable-scroll'),
padding: EdgeInsets.fromLTRB(
8,
10,
8,
140 + MediaQuery.paddingOf(context).bottom,
),
children: [
const Padding(
padding: EdgeInsets.symmetric(horizontal: 14),
child: Text(
'RSchedule',
style: TextStyle(fontSize: 22, fontWeight: FontWeight.w700),
),
),
const SizedBox(height: 10),
SurfaceCard(
padding: const EdgeInsets.symmetric(horizontal: 4, vertical: 0),
child: Row(
children: [
IconButton(
onPressed: term != null && week > 1
? () => setState(() => _week = week - 1)
: null,
icon: const Icon(Icons.chevron_left_rounded),
),
Expanded(
child: Column(
children: [
Text(
term == null ? '本周' : '第 $week 周',
style: const TextStyle(
fontSize: 17,
fontWeight: FontWeight.w700,
),
),
const SizedBox(height: 4),
Text(
'${monday.month}.${monday.day.toString().padLeft(2, '0')} – ${sunday.month}.${sunday.day.toString().padLeft(2, '0')}',
style: TextStyle(
fontSize: 12,
color: ink.withValues(alpha: 0.5),
),
),
],
),
),
IconButton(
onPressed: term != null && week < term.totalWeeks
? () => setState(() => _week = week + 1)
: null,
icon: const Icon(Icons.chevron_right_rounded),
),
TextButton(
onPressed: () => setState(() => _week = null),
child: const Text('本周'),
),
],
),
),
const SizedBox(height: 4),
if (c.isDemo)
Padding(
padding: const EdgeInsets.only(bottom: 12),
child: Wrap(
crossAxisAlignment: WrapCrossAlignment.center,
spacing: 8,
children: [
Container(
padding: const EdgeInsets.symmetric(
horizontal: 12,
vertical: 7,
),
decoration: BoxDecoration(
color: const Color(0xFFE2EEFF),
borderRadius: BorderRadius.circular(10),
),
child: const Text(
'示例课表',
style: TextStyle(
fontSize: 11,
color: Color(0xFF356AA8),
fontWeight: FontWeight.w600,
),
),
),
const Text(
'不会生成提醒或日历事件',
style: TextStyle(fontSize: 10, color: Color(0xFF8193AB)),
),
TextButton(onPressed: c.leaveDemo, child: const Text('退出示例')),
],
),
),
if (term != null) ...[
WeekGrid(
events: ScheduleEngine.occurrences(
c.visibleCourses,
term,
).where((e) => e.week == week).toList(),
monday: monday,
today: today,
settings: c.visibleSettings,
),
const SizedBox(height: 12),
Text(
'点击课程查看完整信息',
textAlign: TextAlign.center,
style: TextStyle(fontSize: 11, color: ink.withValues(alpha: 0.35)),
),
] else ...[
const SizedBox(height: 38),
const Icon(
Icons.calendar_month_outlined,
size: 66,
color: Color(0xFFB7CDF0),
),
const SizedBox(height: 22),
const Text(
'让课表,陪你开启每一天',
textAlign: TextAlign.center,
style: TextStyle(fontSize: 18, fontWeight: FontWeight.w600),
),
const SizedBox(height: 12),
Text(
'在「个人设置」设置学期并导入课程,\n或先看看示例课表。',
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 13,
height: 1.8,
color: ink.withValues(alpha: 0.5),
),
),
const SizedBox(height: 25),
Center(
child: FilledButton.icon(
onPressed: c.showDemo,
icon: const Icon(Icons.auto_awesome_outlined, size: 18),
label: const Text('体验示例课表'),
),
),
],
],
);
}
}