feat: add Next Lesson widget and enhance existing widgets
- Implemented a new Next Lesson widget to display the upcoming lesson details on the home screen. - Updated Today widget to dynamically adjust the number of lessons displayed based on available space. - Enhanced the Settings screen to allow users to manage hidden lessons more effectively. - Introduced harmonized color palettes for better visual consistency across themes. - Updated the timetable API to support a new range parameter for semester-based queries. - Added tests to ensure the new semester range functionality works as expected. - Refactored widget styling for improved appearance on devices with different Android versions.
This commit is contained in:
@@ -29,8 +29,8 @@ app.use("/api", (_req, res, next) => {
|
||||
next();
|
||||
});
|
||||
// Raised whenever an endpoint is added or changed, so a deployment is easy to verify:
|
||||
// 2 — /api/timetable for the Android client.
|
||||
const API_VERSION = 2;
|
||||
// 2 — /api/timetable for the Android client; 3 — its range=semester.
|
||||
const API_VERSION = 3;
|
||||
|
||||
// Liveness plus what the server currently reads from the university, without network calls.
|
||||
app.get("/api/health", async (_req, res) => {
|
||||
@@ -110,6 +110,8 @@ app.get("/api/timetable", async (req, res, next) => {
|
||||
group,
|
||||
from,
|
||||
days: req.query.days,
|
||||
range: req.query.range === "semester" ? "semester" : undefined,
|
||||
today: todayIso(),
|
||||
}),
|
||||
);
|
||||
} catch (e) {
|
||||
|
||||
@@ -5,6 +5,9 @@ import { lessonKey, subgroupsOf } from "../shared/lessons.js";
|
||||
import { occurrence, peopleAndRooms, roomsOn } from "./directory.js";
|
||||
|
||||
const MAX_DAYS = 62;
|
||||
// A whole semester with its session fits easily; the cap only guards against abuse.
|
||||
const MAX_SEMESTER_DAYS = 200;
|
||||
const DAY_MS = 86_400_000;
|
||||
|
||||
function lessonOut(lesson, group, people, date, status, calendar) {
|
||||
const bell = calendar?.bells.find((b) => b.start === lesson.start);
|
||||
@@ -33,13 +36,23 @@ function lessonOut(lesson, group, people, date, status, calendar) {
|
||||
* days: one entry per date from `from`, with the lessons that take place that day.
|
||||
* weekly: the Word rows by weekday, for when dates cannot be calculated.
|
||||
*/
|
||||
export function timetable({ file, schedule, calendar, group, from, days }) {
|
||||
export function timetable({ file, schedule, calendar, group, from, days, range, today }) {
|
||||
if (!schedule.groups.includes(group)) {
|
||||
const error = new Error(`В документе нет группы ${group}.`);
|
||||
error.status = 404;
|
||||
throw error;
|
||||
}
|
||||
const count = Math.min(Math.max(Number(days) || 7, 1), MAX_DAYS);
|
||||
let count = Math.min(Math.max(Number(days) || 7, 1), MAX_DAYS);
|
||||
// range=semester: every day of the semester `today` falls in, so a client can keep
|
||||
// the whole term offline. Without a known semester it keeps the plain from/days window.
|
||||
if (range === "semester") {
|
||||
const current = semesterView(calendar, schedule, today || from);
|
||||
if (current) {
|
||||
from = current.semester.start;
|
||||
const span = Math.round((Date.parse(current.semester.end) - Date.parse(from)) / DAY_MS) + 1;
|
||||
count = Math.min(Math.max(span, 1), MAX_SEMESTER_DAYS);
|
||||
}
|
||||
}
|
||||
const lessons = schedule.lessons.filter((l) => l.groups.includes(group));
|
||||
const entries = lessons.map((lesson) => ({
|
||||
doc: { id: file.id, schedule },
|
||||
|
||||
Reference in New Issue
Block a user