06 — Screen Specifications (Homework Module)
- 1. Homework List
/homework - 2. Homework Detail
/homework/:id - 3. Create Homework Form
/homework/new - 4. Submission Form
/homework/:id/submit(sheet or page) - 5. Submissions List (teacher)
/homework/:id/submissions - 6. Grading Sheet
/homework/:id/submissions/:submissionId - 7. Grade Feedback View (student) — detail block (spec in §2)
- 8. Attachment Preview / Share
- 9. Shared micro-interaction & motion notes (all screens)
Production-grade specs for each Homework screen: chrome, states, components, micro-interactions, a11y, responsive, dark/light, keyboard, motion. Tokens:
Sp= 00-shared/02 §3,Ty= typography §2,El= elevation §5,R= radius §4,Mo= motion §6. All components reference 00-shared/03 and 07 (module).
1. Homework List /homework
Chrome: AppBar "Homework" (titleLarge, El-e1); class filter AppDropdown under
AppBar; body = RefreshIndicator + grouped ListView.builder (group "Due soon" /
"Past due" computed client-side vs dueDate); horizontal padding Sp.16 (phone), Sp.24
(tablet+). Teacher FAB AppFAB.extended "New homework" (Icons.add, heroTag unique).
Row (HomeworkCard, teacher & student):
[Subject chip] [status badge: active/closed] [my-state chip (student)]
Title titleMedium, 2 lines max
Grade 8 - C · Assigned 3d ago bodySmall onSurfaceVariant
Due 15 Aug · in 5d bodyMedium; overdue → tertiary + icon schedule
[attachment icon ×N] bodySmall
- Meta from doc:
title,subjectId(resolved),classId(resolved),dueDate,status(homework.schema.ts:18-34),assignedDate,attachments.length. - Late semantics (OQ-1): server never flags late. Client computes
isLate = dueDate.isBefore(now)— card showstertiarybadge "Overdue · 2d" +scheduleicon (color + icon + text, never color-only —09 §9). Once the server adds enforcement, render server truth only. - States: skeleton (
AppSkeleton(list)); emptyAppEmptyState"No homework yet" + FAB; errorAppErrorState(404 "Class not found" if class invalid, 5xx + requestId); offlineAppOfflineBanner+ cached list (TTL 5 min,06 §3.3). - Pull-to-refresh: re-fetch + WS resubscribe
(planned). - Row menu (teacher): Edit, Delete; delete →
AppDialogconfirm ("Delete this homework? Submissions are kept on the server." — soft delete, no cascade,homework.service.ts:70-81) →DELETE /homework/:idserver-confirmed, row fade-outMo.m-base, snackbar "Deleted". - A11y: card = one
Semantics(button)label"{title}, {subject}, due {date}"; status badges appended; focus order filter → list → FAB. - Dark/light: token-only; overdue badge
tertiaryContainer(light) /tertiary-tinted container (dark) with icon+label. - Tablet/desktop: master-detail at ≥ 840 dp (list left 360–400 dp, detail right);
hover tint on cards;
Nshortcut = new homework.
2. Homework Detail /homework/:id
Chrome: AppBar title "Homework" + trailing AppMenu (teacher: Edit / Delete);
scrollable SingleChildScrollView, sections spaced Sp.24.
Header card (surfaceContainerLow, r-lg, e-1)
title headlineMedium (Ty)
chips: subject · class [status badge] [my-state chip (student)]
Info card
AppInfoRow: Teacher (resolved), Assigned (assignedDate), Due (dueDate; overdue styled)
AppInfoRow: Attachments (N) → tap opens attachment sheet
Description AppMarkdownViewer (data = description; sanitized links)
Actions (role-gated):
student, no submission → FilledButton "Submit" (fullWidth 48h)
student, submitted → SubmissionStatusChip + submittedAt + (graded? marks card)
teacher → OutlinedButton "Submissions (N)" → /submissions
parent → read-only, no actions
States: loading skeleton; 404 → AppEmptyState "This homework was removed or is not
available." (matches server NotFoundException, homework.service.ts:47); offline →
banner + cached detail (00-shared/06 §3.3 — detail views cached last-good).
Grade feedback block (student, when my submission status='graded'):
Card (secondaryContainer tint) "Grade"
marks displaySmall mono tabular · badge "Graded"
remarks → AppMarkdownViewer
gradedAt bodySmall ("Graded 2d ago")
marks is Number? (homework-submission.schema.ts:30-31) — absent until graded;
render "Pending grade" AppBadge when status='submitted' (schema enum
['submitted','graded'], homework-submission.schema.ts:24).
Deep link studylyon://homework/:id → this screen; notification tap → same.
3. Create Homework Form /homework/new
Chrome: full-screen page (> 3 fields rule, 00-shared/05 §5); AppBar "New homework"
SaveTextButton; body form listSp.16gaps,resizeToAvoidBottomInset: true.
1 class AppDropdown (Academics classes; required; onChanged → subject options filter)
2 subject AppDropdown (Subjects; required)
3 title AppTextField (required; maxLength 200 client; autofocus)
4 description AppTextField multiline 4-6 lines; note "Markdown supported" (AppMarkdownViewer
renders it — 00-shared/03 E)
5 dueDate AppDatePicker (required; client min = today; locale-aware; time optional 23:59)
6 attachments AppAttachmentUploader (multi; upload via POST /files/upload per file)
Submit flow: button "Assign homework" → loading spinner; server 201 doc returned
(homework.service.ts:27-43); success → detail + snackbar "Homework assigned".
Validation errors (400 VALIDATION_ERROR): field-level inline, focus first invalid
(submission.dto/homework.dto decorators: IsMongoId, IsString, IsDateString,
IsOptional — homework.dto.ts:4-33).
Attachment UX: each file uploads immediately (id → chip); failures retryable per
file; homework is only created after all attachments uploaded (separate requests —
create must not fire with pending uploads).
4. Submission Form /homework/:id/submit (sheet or page)
Chrome: page (or full-height sheet on phone) with AppBar "Submit homework".
Student identity (from profile; sent as studentId in body — client fills, hidden)
remarks AppTextField multiline "Add a note to your teacher" (optional; server
@IsOptional @IsString — submission.dto.ts:13-16)
attachments AppAttachmentUploader (optional; same file.upload flow)
[Submit button] FilledButton fullWidth "Submit homework"
States:
submitting→ button spinner, inputs disabled, anti-double-submit (00-shared/08 §6).- Success 201 → replace with success view (check icon
success, "Submitted on {submittedAt}") → button "View homework" → detail.submittedAtcomes from the server doc (homework.service.ts:96). - 409
DUPLICATE_RESOURCE"Already submitted." (homework.service.ts:92) → NOT an error: navigate to detail with "Already submitted"AppBanner(info)— the student may have submitted from another device. - 404 → detail empty state ("removed").
- 400 → field errors. 5xx →
AppErrorState+ form state preserved.
Late-submit moment (OQ-1): when now > dueDate, show inline AppBanner(warning)
"Due date has passed — your teacher may accept it" but do not block (server accepts;
blocking client-side would contradict the server contract).
Double-submit safety: submit is not optimistic (00-shared/07 §9 write-once op);
the button locks after first tap; the 409 handler covers retried requests
(Idempotency-Key header supported pattern — 00-shared/07 §9).
5. Submissions List (teacher) /homework/:id/submissions
Chrome: AppBar "Submissions · {title}"; summary line bodySmall "N submitted · M
graded"; RefreshIndicator + ListView.builder.
Row (SubmissionRow):
[avatar initial] Student name titleMedium
Submitted 3d ago · Late badge? bodySmall
[status chip] submitted → tertiary-tinted "Pending"; graded → success "Graded"
[marks badge] mono "17" (graded only)
[attachment icons ×N]
- Late badge: client-computed
submittedAt > dueDate→AppBadge(tertiary, icon schedule)"Late · 2d" (AppBadge+ icon + text — a11y09 §9). Semantics: "Submitted late by 2 days". - Grouping: "Ungraded" first (status='submitted'), then "Graded"
(status='graded') — no server sort (
findByHomeworkreturns insertion order,homework-submission.repository.ts:20-24); client groups. Proposed: server sort bysubmittedAt. - States: empty
AppEmptyState"No submissions yet" + "Share the homework link" (proposed); 404 → detail-removed empty state. - Row tap: ungraded → grading sheet; graded → read-only feedback w/ "Regrade" action.
6. Grading Sheet /homework/:id/submissions/:submissionId
Chrome: page; AppBar "Grade · {student}"; body scrollable.
Student header avatar + name + submittedAt (+ late badge)
Attachment preview AppAttachmentList (download via GET /files/:id/download)
marks AppTextField numeric (label "Marks"; hint "e.g. 20")
client rules: required, ≥ 0, ≤ 100 default (configurable per org —
server has NO bounds, OQ-4: submission.dto.ts:20-21)
remarks AppTextField multiline "Feedback for the student" (optional,
@IsOptional @IsString — submission.dto.ts:24-26)
[Grade button] FilledButton fullWidth "Save grade"
Regrade mode (existing status='graded'): show current marks + remarks; button
"Save new grade" + AppBanner(warning) "This overwrites the previous grade"
(server overwrites unconditionally and emits HomeworkGraded again — homework.service.ts:127-143, OQ-2).
States: grading (button spinner, no double-submit); success → row state updates via
pop result + snackbar "Grade saved"; 404 "Submission not found." (homework.service.ts:126)
→ back + refresh; 400 → field errors.
Optimistic vs server-confirmed (see 13): grading is server-confirmed — the
updated doc (marks, remarks, status:'graded', gradedAt) is written only on 200.
No local paint-before-write (side effects: event → notifications).
Batch flow (proposed): after saving a grade, "Next ungraded" chip appears → advances
to the next status='submitted' row (client-side; list already loaded).
7. Grade Feedback View (student) — detail block (spec in §2)
Reuses GradeFeedbackCard component; read-only; marks in mono tabular figures.
8. Attachment Preview / Share
- PDF/image preview in app (
PageView+ zoom,00-shared/08 §1double-tap zoom); other types → share sheet / external viewer. - Download:
GET /files/:id/download→ buffer → save/share; error 404 → snackbar "File no longer available". - Upload (from create/submit forms):
AppAttachmentUploader— per-file states{idle, uploading(progress), uploaded(fileId), failed(retry), removed}; retry = re-POST same file (new upload each attempt — no resume;00-shared/12 B7).
9. Shared micro-interaction & motion notes (all screens)
- Route transitions
Mo.m-base; cardsEl-e1; FABMo.m-entrancescale, hide on scroll-down (00-shared/03 D). - Snackbars: success < 3 s, error ≥ 4 s.
- Status chip change (
submitted→graded) animatesAnimatedSwitcherMo.m-fast. - Keyboard: numeric
TextInputType.numberfor marks; multiline for remarks;Ctrl+Entersubmits on desktop (00-shared/08 §2). - Safe areas: bottom padding under FAB/lists; sheets respect
MediaQuery. - Reduced motion: fades + instant only, no shake/stagger.