forked from firka/firka
298 lines
8.4 KiB
Dart
298 lines
8.4 KiB
Dart
import 'package:intl/intl.dart';
|
|
|
|
import 'package:firka/l10n/app_localizations.dart';
|
|
import 'package:firka_common/core/debug_helper.dart';
|
|
import 'package:firka_common/core/extensions.dart';
|
|
import 'package:kreta_api/kreta_api.dart';
|
|
|
|
export 'package:firka_common/core/extensions.dart';
|
|
|
|
extension TimetableExtension on Iterable<Lesson> {
|
|
List<Lesson> getAllSeqs(Lesson reference) {
|
|
List<Lesson> lessons = List.empty(growable: true);
|
|
|
|
for (var lesson in this) {
|
|
if (lesson.lessonNumber == null) continue;
|
|
|
|
if (!lessons.any(
|
|
(lesson2) => lesson.lessonNumber == lesson2.lessonNumber,
|
|
)) {
|
|
final ref = reference.start;
|
|
final newStart = DateTime(
|
|
ref.year,
|
|
ref.month,
|
|
ref.day,
|
|
lesson.start.hour,
|
|
lesson.start.minute,
|
|
lesson.start.second,
|
|
);
|
|
final newEnd = DateTime(
|
|
ref.year,
|
|
ref.month,
|
|
ref.day,
|
|
lesson.end.hour,
|
|
lesson.end.minute,
|
|
lesson.end.second,
|
|
);
|
|
final lessonCopy = Lesson(
|
|
uid: lesson.uid,
|
|
date: lesson.date,
|
|
start: newStart,
|
|
end: newEnd,
|
|
name: lesson.name,
|
|
type: lesson.type,
|
|
state: lesson.state,
|
|
canStudentEditHomework: lesson.canStudentEditHomework,
|
|
isHomeworkComplete: lesson.isHomeworkComplete,
|
|
attachments: lesson.attachments,
|
|
lessonNumber: lesson.lessonNumber,
|
|
isDigitalLesson: lesson.isDigitalLesson,
|
|
digitalSupportDeviceTypeList: lesson.digitalSupportDeviceTypeList,
|
|
createdAt: lesson.createdAt,
|
|
lastModifiedAt: lesson.lastModifiedAt,
|
|
);
|
|
lessons.add(lessonCopy);
|
|
}
|
|
}
|
|
|
|
lessons.sort((l1, l2) => l1.lessonNumber! - l2.lessonNumber!);
|
|
|
|
return lessons;
|
|
}
|
|
}
|
|
|
|
extension DurationExtension on Duration {
|
|
String formatDuration() {
|
|
String hours = inHours.toString().padLeft(2, '0');
|
|
String minutes = inMinutes.remainder(60).toString().padLeft(2, '0');
|
|
String seconds = inSeconds.remainder(60).toString().padLeft(2, '0');
|
|
return "$hours:$minutes:$seconds";
|
|
}
|
|
|
|
String? timeLeft(AppLocalizations l10n) {
|
|
return inMinutes > 0
|
|
? "${inMinutes + 1} ${l10n.starting_min_plural}"
|
|
: inSeconds > 0
|
|
? "$inSeconds ${inSeconds == 1 ? l10n.starting_sec : l10n.starting_sec_plural}"
|
|
: null;
|
|
}
|
|
}
|
|
|
|
enum FormatMode {
|
|
yearly,
|
|
mmmd,
|
|
main,
|
|
grades,
|
|
welcome,
|
|
hmm,
|
|
d,
|
|
da,
|
|
dd,
|
|
yyyymmddwedd,
|
|
yyyymmmm,
|
|
yyyymmdd,
|
|
yyyymmddhhmmss,
|
|
}
|
|
|
|
enum Cycle { morning, day, afternoon, night }
|
|
|
|
extension ComparableExtension<T extends Comparable<T>> on Comparable<T> {
|
|
T min(T other) {
|
|
return compareTo(other) < 0 ? this as T : other;
|
|
}
|
|
|
|
bool isBetween(T from, T to) {
|
|
return compareTo(from) > 0 && compareTo(to) < 0;
|
|
}
|
|
|
|
T max(T other) {
|
|
return compareTo(other) > 0 ? this as T : other;
|
|
}
|
|
}
|
|
|
|
extension DateExtension on DateTime {
|
|
String? translatedDay(AppLocalizations l10n) {
|
|
var today = timeNow().getMidnight();
|
|
|
|
var tomorrowLim = today.add(Duration(days: 2));
|
|
var tomorrow = today.add(Duration(days: 1));
|
|
var yesterday = today.subtract(Duration(days: 1));
|
|
var yesterdayLim = today.subtract(Duration(days: 2));
|
|
|
|
if (isAfter(yesterdayLim) && isBefore(today)) {
|
|
return l10n.yesterday;
|
|
}
|
|
if (isAfter(yesterday) && isBefore(tomorrow)) {
|
|
return l10n.today;
|
|
}
|
|
if (isAfter(today) && isBefore(tomorrowLim)) {
|
|
return l10n.tomorrow;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
String format(AppLocalizations l10n, FormatMode mode) {
|
|
var weekStart = getMonday();
|
|
var weekEnd = weekStart.add(Duration(days: 6));
|
|
|
|
switch (mode) {
|
|
case FormatMode.main:
|
|
var lastWeek = timeNow().getMidnight().subtract(Duration(days: 8));
|
|
var isLastWeek =
|
|
lastWeek.millisecondsSinceEpoch <
|
|
getMidnight().millisecondsSinceEpoch;
|
|
final dayName = DateFormat(
|
|
'EEEE',
|
|
l10n.localeName,
|
|
).format(this).firstUpper();
|
|
return translatedDay(l10n) ??
|
|
(isLastWeek
|
|
? "$dayName (${format(l10n, FormatMode.mmmd).firstUpper()})"
|
|
: "${format(l10n, FormatMode.yearly).firstUpper()} ($dayName)");
|
|
case FormatMode.grades:
|
|
return translatedDay(l10n) ?? format(l10n, FormatMode.yearly);
|
|
case FormatMode.yearly:
|
|
return DateFormat('MMMM d', l10n.localeName).format(this);
|
|
case FormatMode.mmmd:
|
|
return DateFormat('MMM d', l10n.localeName).format(this);
|
|
case FormatMode.hmm:
|
|
return DateFormat('H:mm', l10n.localeName).format(this);
|
|
case FormatMode.welcome:
|
|
final dayName = DateFormat(
|
|
'EEEE',
|
|
l10n.localeName,
|
|
).format(this).firstUpper();
|
|
final monthAbbr = DateFormat(
|
|
'MMM',
|
|
l10n.localeName,
|
|
).format(this).firstUpper();
|
|
final day = DateFormat('d', l10n.localeName).format(this);
|
|
return "$dayName, $monthAbbr $day";
|
|
case FormatMode.d:
|
|
return DateFormat('d', l10n.localeName).format(this);
|
|
case FormatMode.da:
|
|
return DateFormat(
|
|
'EEEE',
|
|
l10n.localeName,
|
|
).format(this).substring(0, 2).firstUpper();
|
|
case FormatMode.dd:
|
|
return DateFormat('dd', l10n.localeName).format(this);
|
|
case FormatMode.yyyymmddwedd:
|
|
if (l10n.localeName == "en") {
|
|
return "${DateFormat('yyyy MMM. dd', l10n.localeName).format(weekStart).toLowerCase()}-${DateFormat('dd', l10n.localeName).format(weekEnd)}";
|
|
} else {
|
|
return "${DateFormat('yyyy MMM dd', l10n.localeName).format(weekStart).toLowerCase()}-${DateFormat('dd', l10n.localeName).format(weekEnd)}";
|
|
}
|
|
case FormatMode.yyyymmmm:
|
|
return DateFormat('yyyy MMMM', l10n.localeName).format(this);
|
|
case FormatMode.yyyymmdd:
|
|
return DateFormat('yyyy. MM. dd.', l10n.localeName).format(this);
|
|
case FormatMode.yyyymmddhhmmss:
|
|
return DateFormat(
|
|
'yyyy. MM. dd. H:mm:ss',
|
|
l10n.localeName,
|
|
).format(this);
|
|
}
|
|
}
|
|
|
|
int weekNumber() {
|
|
int dayOfYear = int.parse(DateFormat("D").format(this));
|
|
return ((dayOfYear - weekday + 10) / 7).floor();
|
|
}
|
|
|
|
bool isAWeek() {
|
|
return weekNumber() % 2 == 0;
|
|
}
|
|
|
|
DateTime getMonday() {
|
|
return subtract(Duration(days: weekday - 1));
|
|
}
|
|
|
|
DateTime getMidnight() {
|
|
return subtract(
|
|
Duration(
|
|
hours: hour,
|
|
minutes: minute,
|
|
seconds: second,
|
|
milliseconds: millisecond,
|
|
microseconds: microsecond,
|
|
),
|
|
);
|
|
}
|
|
|
|
Cycle getDayCycle() {
|
|
var midnight = getMidnight();
|
|
if (isAfter(midnight.add(Duration(hours: 5, minutes: 30))) &&
|
|
isBefore(midnight.add(Duration(hours: 9)))) {
|
|
return Cycle.morning;
|
|
}
|
|
if (isAfter(midnight.add(Duration(hours: 5, minutes: 30))) &&
|
|
isBefore(midnight.add(Duration(hours: 14)))) {
|
|
return Cycle.day;
|
|
}
|
|
if (isAfter(midnight.add(Duration(hours: 5, minutes: 30))) &&
|
|
isBefore(midnight.add(Duration(hours: 18)))) {
|
|
return Cycle.afternoon;
|
|
}
|
|
|
|
return Cycle.night;
|
|
}
|
|
}
|
|
|
|
extension DateGrouper<T> on Iterable<T> {
|
|
Map<DateTime, List<T>> groupList(DateTime Function(T elem) getDate) {
|
|
Map<DateTime, List<T>> newList = {};
|
|
|
|
for (var elem in this) {
|
|
var date = getDate(elem);
|
|
var day = date.getMidnight();
|
|
|
|
if (newList[day] == null) {
|
|
newList[day] = List<T>.empty(growable: true);
|
|
}
|
|
|
|
newList[day]!.add(elem);
|
|
}
|
|
|
|
return newList;
|
|
}
|
|
}
|
|
|
|
extension LessonExtension on List<Lesson> {
|
|
int getLessonNo(Lesson lesson) {
|
|
return lesson.lessonNumber ?? indexOf(lesson);
|
|
}
|
|
|
|
Lesson? getCurrentLesson(DateTime now) {
|
|
return firstWhereOrNull(
|
|
(lesson) => now.isAfter(lesson.start) && now.isBefore(lesson.end),
|
|
);
|
|
}
|
|
|
|
Lesson? getPrevLesson(DateTime now) {
|
|
return reversed.firstWhereOrNull(
|
|
(lesson) => lesson.end.isBefore(now.add(Duration(milliseconds: 1))),
|
|
);
|
|
}
|
|
|
|
Lesson? getNextLesson(DateTime now) {
|
|
return firstWhereOrNull(
|
|
(lesson) => lesson.start.isAfter(now.add(Duration(milliseconds: 1))),
|
|
);
|
|
}
|
|
}
|
|
|
|
extension StringExtension on String {
|
|
bool isNumeric() {
|
|
final regex = RegExp(r'^[+-]?(\d+(\.\d*)?|\.\d+)([eE][+-]?\d+)?$');
|
|
return regex.hasMatch(trim());
|
|
}
|
|
|
|
String firstUpper() {
|
|
if (isEmpty) return this;
|
|
if (length == 1) this[0].toUpperCase();
|
|
return this[0].toUpperCase() + substring(1, length);
|
|
}
|
|
}
|