Files
psu-schedule/scripts/snapshot-lines.js
Zakhar Timoshenko b9c1f63301 feat: Add skeleton loading UI components for various screens
- Implemented `Skeleton.kt` for loading placeholders in the app, including lesson cards, schedule, overview, and subjects.
- Introduced `Undo.kt` to manage undo actions with a snackbar interface.
- Created `WeekWidget.kt` for a widget displaying the week's schedule, including dynamic updates based on the current timetable.
- Added various splash animations in the `animator` directory for a smooth launch experience.
- Designed drawable resources for the widget and splash screen, including icons for city and room moves.
- Defined XML resources for widget configuration and photo paths.
2026-10-23 21:56:07 +03:00

51 lines
2.6 KiB
JavaScript
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.
// One readable line per parsed lesson, the form both snapshots compare: what a student sees
// (day, time, weeks or dates, subject, kind, room, teacher, groups), not ids or source colours.
const DAYS = ["", "пн", "вт", "ср", "чт", "пт", "сб", "вс"];
const weeks = (ranges) =>
ranges?.map(([a, b]) => (b === null ? `с ${a}` : a === b ? `${a}` : `${a}-${b}`)).join(",") || "";
export const lessonLine = (l) =>
[
`${l.date || DAYS[l.day]} ${l.start}${l.end ? `–${l.end}` : ""}`,
(l.date ? "один раз" : l.dates?.length ? `даты ${l.dates.join(",")}` : l.weekRanges ? `нед. ${weeks(l.weekRanges)}` : "каждую неделю") +
(l.variant === "upper" ? ", верхняя строка" : l.variant === "lower" ? ", нижняя строка" : ""),
l.subject,
l.type,
// The town only when the cell names one or the day's note puts the lesson there.
[l.room, l.place].filter(Boolean).join(", "),
l.teacher,
[...l.groups, ...l.subgroups.map((s) => `${s.group}/${s.label.replace("Подгруппа ", "п")}`)].join(",") +
// "Немецкий язык" or "Французский язык": a part of the group takes one of them.
(l.option ? " · на выбор" : "") +
// Russian for foreign students while the others have physical education.
(l.audience === "foreign" ? " · иностранцам" : l.audience === "local" ? " · кроме иностранцев" : ""),
]
.map((part) => String(part ?? "").replace(/\s+/g, " ").trim())
.join(" | ");
// "Занятия в Полоцке": a day of a group or subgroup in another town, not a lesson.
const placeLine = (p) =>
[
`@ ${p.date || DAYS[p.day]}`,
p.text,
[...p.groups, ...p.subgroups.map((s) => `${s.group}/${s.label.replace("Подгруппа ", "п")}`)].join(","),
].join(" | ");
/** Sorted lesson lines of a parsed document, with its groups and period on top. */
export const snapshotOf = (schedule) => [
`# ${schedule.period} · ${schedule.groups.join(", ")}`,
...(schedule.places || []).map(placeLine).sort(),
...schedule.lessons.map(lessonLine).sort(),
];
/** Lines only in `before` (removed) and only in `after` (added), duplicates counted. */
export function diffLines(before, after) {
const count = (lines) => lines.reduce((m, x) => m.set(x, (m.get(x) || 0) + 1), new Map());
const a = count(before), b = count(after);
const removed = [], added = [];
for (const [line, n] of a) for (let i = b.get(line) || 0; i < n; i++) removed.push(line);
for (const [line, n] of b) for (let i = a.get(line) || 0; i < n; i++) added.push(line);
return { removed, added };
}