forked from firka/student-legacy
246 lines
6.6 KiB
Dart
246 lines
6.6 KiB
Dart
// ignore_for_file: avoid_print, use_build_context_synchronously
|
|
|
|
import 'dart:async';
|
|
import 'dart:developer';
|
|
import 'dart:math' as math;
|
|
import 'package:refilc_kreta_api/providers/homework_provider.dart';
|
|
import 'package:refilc_kreta_api/providers/timetable_provider.dart';
|
|
import 'package:refilc_kreta_api/models/lesson.dart';
|
|
import 'package:refilc_kreta_api/models/week.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:flutter/widgets.dart';
|
|
import 'package:provider/provider.dart';
|
|
|
|
enum LoadType { initial, offline, loading, online }
|
|
|
|
class TimetableController extends ChangeNotifier {
|
|
late Week currentWeek;
|
|
int currentWeekId = -1;
|
|
late int previousWeekId;
|
|
List<List<Lesson>>? days;
|
|
LoadType loadType = LoadType.initial;
|
|
|
|
TimetableController() {
|
|
current();
|
|
}
|
|
|
|
static int getWeekId(Week week) =>
|
|
(week.start.difference(getSchoolYearStart()).inDays /
|
|
DateTime.daysPerWeek)
|
|
.ceil();
|
|
|
|
static DateTime getSchoolYearStart() {
|
|
DateTime now = DateTime.now();
|
|
DateTime nowStart = _getYearStart(now.year);
|
|
|
|
if (nowStart.isBefore(now)) {
|
|
return nowStart;
|
|
} else {
|
|
return _getYearStart(now.year - 1);
|
|
}
|
|
}
|
|
|
|
static DateTime _getYearStart(int year) {
|
|
var s1 = DateTime(year, DateTime.september, 1);
|
|
if (s1.weekday == 6) {
|
|
s1.add(const Duration(days: 2));
|
|
} else if (s1.weekday == 7) {
|
|
s1.add(const Duration(days: 1));
|
|
}
|
|
return s1;
|
|
}
|
|
|
|
// Jump shortcuts
|
|
Future<void> next(BuildContext context) =>
|
|
jump(Week.fromId(currentWeekId + 1), context: context);
|
|
Future<void> previous(BuildContext context) =>
|
|
jump(Week.fromId(currentWeekId - 1), context: context);
|
|
void current() {
|
|
Week week = Week.current();
|
|
int id = getWeekId(week);
|
|
|
|
if (id > 51) id = 51;
|
|
if (id < 0) id = 0;
|
|
|
|
_setWeek(Week.fromId(id));
|
|
}
|
|
|
|
Future<void> jump(Week week,
|
|
{required BuildContext context,
|
|
bool initial = false,
|
|
bool skip = false,
|
|
bool loader = true}) async {
|
|
if (_setWeek(week)) return;
|
|
|
|
loadType = LoadType.initial;
|
|
|
|
if (loader) {
|
|
days = null;
|
|
|
|
// Don't start loading on init
|
|
if (!initial) notifyListeners();
|
|
}
|
|
|
|
days = _sortDays(week, context: context);
|
|
|
|
if (week != currentWeek) return;
|
|
|
|
loadType = LoadType.loading;
|
|
|
|
notifyListeners();
|
|
|
|
try {
|
|
await _fetchWeek(week, context: context).timeout(
|
|
const Duration(seconds: 5),
|
|
onTimeout: (() => throw "timeout"));
|
|
loadType = LoadType.online;
|
|
} catch (error, stack) {
|
|
print("ERROR: TimetableController.jump: $error\n$stack");
|
|
loadType = LoadType.offline;
|
|
}
|
|
|
|
if (week != currentWeek) return;
|
|
|
|
days = _sortDays(week, context: context);
|
|
|
|
if (week != currentWeek) return;
|
|
|
|
// Jump to next week on weekends
|
|
if (skip &&
|
|
(days?.length ?? 0) > 0 &&
|
|
days!.last.last.end.isBefore(DateTime.now())) {
|
|
return next(context);
|
|
}
|
|
|
|
notifyListeners();
|
|
}
|
|
|
|
bool _setWeek(Week week) {
|
|
int id = getWeekId(week);
|
|
if (id > 51) return true; // Max 52.
|
|
if (id < 0) return true; // Min 1.
|
|
|
|
// Set week start to Sept. 1 of first week
|
|
if (!_differentDate(week.start, Week.fromId(0).start)) {
|
|
week.start = TimetableController.getSchoolYearStart();
|
|
}
|
|
|
|
currentWeek = week;
|
|
previousWeekId = currentWeekId;
|
|
currentWeekId = id;
|
|
return false;
|
|
}
|
|
|
|
Future<void> _fetchWeek(Week week, {required BuildContext context}) async {
|
|
await Future.wait([
|
|
context.read<TimetableProvider>().fetch(week: week),
|
|
context.read<HomeworkProvider>().fetch(from: week.start, db: false),
|
|
]);
|
|
}
|
|
|
|
List<List<Lesson>> _sortDays(Week week, {required BuildContext context}) {
|
|
List<List<Lesson>> days = [];
|
|
|
|
try {
|
|
final timetableProvider = context.read<TimetableProvider>();
|
|
|
|
List<Lesson> lessons = timetableProvider.getWeek(week) ?? [];
|
|
|
|
if (lessons.isNotEmpty) {
|
|
days.add([]);
|
|
lessons.sort((a, b) => a.date.compareTo(b.date));
|
|
for (var lesson in lessons) {
|
|
if (days.last.isNotEmpty &&
|
|
_differentDate(lesson.date, days.last.last.date)) {
|
|
days.add([]);
|
|
}
|
|
days.last.add(lesson);
|
|
}
|
|
|
|
for (int i = 0; i < days.length; i++) {
|
|
List<Lesson> day0 = List.castFrom(days[i]);
|
|
|
|
List<int> lessonIndexes = _getIndexes(day0);
|
|
int minIndex = 0, maxIndex = 0;
|
|
|
|
if (lessonIndexes.isNotEmpty) {
|
|
minIndex = lessonIndexes.reduce(math.min);
|
|
maxIndex = lessonIndexes.reduce(math.max);
|
|
}
|
|
|
|
List<Lesson> day = [];
|
|
|
|
if (lessonIndexes.isNotEmpty) {
|
|
// Fill missing indexes with empty spaces
|
|
for (var i in List<int>.generate(
|
|
maxIndex - minIndex + 1, (int i) => minIndex + i)) {
|
|
List<Lesson> indexLessons = _getLessonsByIndex(day0, i);
|
|
|
|
// Empty lesson
|
|
if (indexLessons.isEmpty) {
|
|
// Get start date by previous lesson
|
|
List<Lesson> prevLesson = _getLessonsByIndex(day, i - 1);
|
|
try {
|
|
DateTime startDate =
|
|
prevLesson.last.start.add(const Duration(seconds: 1));
|
|
indexLessons.add(Lesson.fromJson({
|
|
'isEmpty': true,
|
|
'Oraszam': i,
|
|
'KezdetIdopont': startDate.toIso8601String()
|
|
}));
|
|
// ignore: empty_catches
|
|
} catch (e) {}
|
|
}
|
|
|
|
day.addAll(indexLessons);
|
|
}
|
|
}
|
|
|
|
// Additional lessons
|
|
day.addAll(day0.where((l) =>
|
|
int.tryParse(l.lessonIndex) == null && l.subject.id != ''));
|
|
|
|
day.sort((a, b) => a.start.compareTo(b.start));
|
|
|
|
// Special Dates
|
|
for (var l in day0) {
|
|
l.subject.id == '' ? day.insert(0, l) : null;
|
|
}
|
|
|
|
days[i] = day;
|
|
}
|
|
}
|
|
} catch (e) {
|
|
log("_sortDays error: $e");
|
|
}
|
|
|
|
return days;
|
|
}
|
|
|
|
List<Lesson> _getLessonsByIndex(List<Lesson> lessons, int index) {
|
|
List<Lesson> ret = [];
|
|
|
|
for (var lesson in lessons) {
|
|
int? lessonIndex = int.tryParse(lesson.lessonIndex);
|
|
|
|
if (lessonIndex != null && lessonIndex == index) {
|
|
ret.add(lesson);
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
List<int> _getIndexes(List<Lesson> lessons) {
|
|
List<int> indexes = [];
|
|
for (var l in lessons) {
|
|
int? index = int.tryParse(l.lessonIndex);
|
|
if (index != null) indexes.add(index);
|
|
}
|
|
return indexes;
|
|
}
|
|
|
|
bool _differentDate(DateTime a, DateTime b) =>
|
|
!(a.year == b.year && a.month == b.month && a.day == b.day);
|
|
}
|