05 — Screen Inventory (Exams Module)
Every client screen for the Exams module. Screens S1–S8 derive from implemented endpoints; "state" columns list the states each screen must handle (see 06_Screen_Specifications.md for detail). Tokens referenced:
Sp(00-shared/02 §3),Ty(§2),El(§5),R(§4),Mo(§6). Analytics events are(proposed)per 00-shared/10_QA_Baseline.md §8.
| ID | Screen | Purpose | Route | Primary widgets | States | Permissions (target (planned)) | A11y focus | Animations | Analytics (proposed) |
|---|---|---|---|---|---|---|---|---|---|
| S1 | Exams List | Browse all exams of the tenant (paginated); entry point to planning & publish | /exams | AppBar, RefreshIndicator, ListView.builder of ExamCard, AppFAB.extended "New exam", AppFilterChip row (status/type), AppPaginationBar | Initial/loading (skeleton), success (list), empty (no exams), error (5xx + requestId), offline (banner + cache), pagination (loading-more, last-page) | exam.read | Screen reader reads status badges (never color-only), focus order filter→list→FAB, touch target ≥48 dp | Fade-in rows Mo.fast; pull-to-refresh spinner; FAB hero transition | exam.list_view, exam.row_tap, exam.create_start |
| S2 | Exam Detail | Exam header + schedule (subject slots) + coverage + actions (edit/delete/add subject/publish) | /exams/:examId | AppBar + AppMenu, header card (ExamHeaderCard), segmented control Schedule/Coverage, slot ListView (ExamSubjectCard), action bar FilledButton "Add subject", PublishButton | Loading, success, empty (no slots), error 404 (exam removed), offline (cached header + stale slots), publish-in-progress | exam.read (actions: exam.update/exam.publish/exam.delete) | Status changes announced via Semantics(liveRegion); publish button labeled with exam name | Header fade/slide Mo.base; segmented control Mo.fast; publish progress spinner; slot list stagger Mo.fast | exam.detail_view, exam.publish_tap |
| S3 | Marks Entry | Enter/correct marks for one subject slot (class roster) | /exams/:examId/slots/:slotId/marks | SlotHeaderCard (subject, class, date/time, max/pass marks), roster ListView of MarksRow, MarksTextField per row, coverage bar (MarksSummaryBar), save-per-row | Loading (roster+marks), success, empty (roster empty), error 404 (slot removed → pop to detail), per-row saving, per-row failed, offline queue pending | exam.mark | Numeric keyboard friendly, per-row semantics label "{student}, {marks}/{max}", error announcements | Row save: check animation Mo.fast; failed row shake Mo.shake; coverage bar animates width | marks_entry_open, marks_saved, marks_row_failed, marks_coverage |
| S4 | Add Subject Slot | Add one class+subject+date+time+marks slot to an exam | /exams/:examId/slots/new | Form page: AppDropdown (subject, class), AppDatePicker, two AppTextField time inputs, two numeric fields (max/pass marks) | Form validation (inline errors), submitting (spinner), success → pop, conflict warning (overlap detected) | exam.update | Form fields labeled, error summaries announced, date picker a11y | Submit button spinner; error inline slide Mo.fast | exam_slot_add_start, exam_slot_add_submit, exam_slot_add_conflict_warned |
| S5 | Publish Confirm (dialog) | Final gate before POST /examinations/:id/publish; shows coverage summary | overlay on /exams/:examId | AppDialog (warning icon, coverage recap, FilledButton "Publish" / TextButton "Cancel") | Initial (summary), submitting (spinner, non-dismissable), success → pop + badge update, error (404/5xx) | exam.publish | Dialog focus trap, Escape cancels, confirm requires explicit tap | Dialog scale-in Mo.base; success check Mo.fast | exam_publish_confirm, exam_publish_success, exam_publish_failure |
| S6 | Student Results (mine) | Read-only marks list for a student | /results | AppBar, list of ResultRowCard grouped by exam, RefreshIndicator | Loading, success, empty ("No results yet"), error, offline | result.read | Marks read as {subject} {marks}/{max} | Row stagger Mo.fast | results_view |
| S7 | Report Card | Per-student, per-exam aggregate: subject table, totals, percentage, overall grade | /results/:examId/report-card | ReportCardHeader (exam, generatedAt), subject table (ReportCardTable), totals card, GradeBadge (overall), remarks column | Loading, success, empty (404 "No subjects scheduled"), error | result.read | Table header announced; grade badge label includes letter + threshold | Table rows fade Mo.fast; grade badge pop Mo.base | report_card_view, report_card_share |
| S8 / S8a | Create / Edit Exam | Form to create (POST /examinations) or edit (PATCH /examinations/:id) | /exams/new · /exams/:examId/edit | Form: AppDropdown (academic year, type), AppTextField name, two AppDatePicker; edit mode adds status read-only chip | Validation, submitting, success → pop to detail, error 400 field / 404 (edit deleted exam) | exam.create / exam.update | Same as S4 | Same as S4 | exam_form_submit, exam_form_error |
Cross-screen notes
- Shared empty/loading/error widgets:
AppSkeleton,AppEmptyState,AppErrorState,AppOfflineBannerfrom 00-shared/03 — no module-specific rebuilds. - Status badges (S1/S2):
draft,active,completed,published(examination.schema.ts:28-33) — one sharedExamStatusBadgecomponent (see 07). - Type chips (S1/S2/S8):
midterm,final,unit_test,quarterly,other(examination.schema.ts:15-20). - Published = terminal in UI (OQ-5): after
published, S2 hides Publish, Edit (status), Delete actions; S3 allows reads but marks edits are flagged. - Offline: S1/S2/S6/S7 read from last-good cache; S3 queues mark writes (module offline queue, 13_State_Management.md §4); S4/S8/S5 are online-only.
- Deep links
studylyon://exams/:idetc. —(forward-looking).