Skip to content

feat: add Today dashboard, backup conflict resolution, and student call names - #58

Merged
mikebarkmin merged 7 commits into
mainfrom
claude/teacher-perspective-review-gc43yb
Aug 5, 2026
Merged

feat: add Today dashboard, backup conflict resolution, and student call names#58
mikebarkmin merged 7 commits into
mainfrom
claude/teacher-perspective-review-gc43yb

Conversation

@mikebarkmin

@mikebarkmin mikebarkmin commented Aug 4, 2026

Copy link
Copy Markdown
Member

Three teacher-facing features, plus fixes for bugs found while building them.

Today dashboard

A landing screen showing every active group's status for one date in one place — attendance, grades, homework, and material — with a single tap into that group's lesson. Replaces the flat Groups list as the post-unlock destination, so a teacher with several periods a day no longer has to open each group and its calendar to find out whether a lesson has already been logged.

  • Defaults to today; a date picker (app-bar icon or the date header) browses back over past days to catch up on missed entries, and a "jump to today" icon appears whenever you've navigated away.
  • The date is deep-linkable via /today?date=YYYY-MM-DD, matching the convention Lesson Mode already uses.
  • Backed by a single reactive query (TodayRepository), so cards update live as data changes.

Backup conflict resolution

When a WebDAV export finds the canonical backup has moved on to a revision this device never saw, it already uploaded local changes as a separate _CONFLICT_ copy rather than overwriting. Until now the teacher had to spot and interpret those raw files in the flat backup list themselves.

  • A warning banner in Settings → Backups surfaces pending conflicts and opens a resolution screen comparing both versions side by side (device, time, size).
  • Keep this device's version re-exports local content as the new canonical; Use the server version restores the server copy locally. Neither deletes anything — the version not chosen stays in the backup list.
  • Raw _CONFLICT_ entries are hidden from the flat list, since they're now represented by the banner.
  • Fixes libraryNameForBackupFile, which didn't strip the _CONFLICT_<timestamp> suffix and so displayed those backups under a mangled library name.

Student call names (Rufname)

Teachers often address a student by a name that isn't their official first name.

  • New optional callName on students, shown in place of the first name everywhere a name is displayed, with the surname always kept alongside it in both sort orders ("Alex Mustermann" / "Mustermann, Alex").
  • firstName/lastName are unchanged, so CSV exports and WebUntis import matching still use official names.
  • Leaving it blank preserves today's behaviour exactly; existing students are unaffected until edited.

Schema: adds a nullable students_table.call_name column, schema version 21 → 22, with a migration.

Fixes found while building the above

  • Chip labels with an unbounded Text inside a mainAxisSize.min Row overflowed instead of ellipsising on narrow widths — hit by the new dashboard's stat chips and latent in the existing LessonSummaryCard chips they were modelled on.
  • A checklist label stored before a call name was set stopped counting as auto-generated once one was added, freezing at the old name and growing a redundant linked-student chip. Generated-name matching now accepts both the call name and the plain first name.
  • Resolving a conflict with "keep this device's version" adopted the server's revision before re-exporting, but exportNow() reports upload failures through the status message rather than its return value. A failed upload therefore looked like success: the screen said the conflict was resolved, and the adopted revision stayed persisted, so the next auto-export would silently overwrite the server copy. The revision is now rolled back unless the export actually lands, and the failure is reported.

Testing

flutter analyze clean; full suite green (102 tests, 5 added covering call-name fallback, generated-label matching, conflict-copy filename parsing, and the revision rollback).

Not covered by tests: the multi-device WebDAV conflict flow end to end, which needs two real devices against a live server — the unit tests exercise the controller and filename logic against a fake backup service only.

🤖 Generated with Claude Code

https://claude.ai/code/session_01LJRKq8YRXgS65F9dAcQxNi

claude added 7 commits August 4, 2026 17:29
Add a Today landing screen showing every active group's attendance,
grade, homework, and material status for the current date with a
one-tap entry into that group's lesson, replacing the flat Groups list
as the post-unlock destination.

Add a guided conflict resolution screen for WebDAV sync conflicts,
reachable from a new warning banner in Settings > Backups. Lets the
teacher compare the canonical and conflicting backups (device, time,
size) and either keep this device's version (re-exports it as the new
canonical) or adopt the server version, instead of having to spot and
interpret raw `_CONFLICT_` files in the flat backup list.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LJRKq8YRXgS65F9dAcQxNi
flutter analyze and a widget-test render pass turned up two real bugs:
an unbounded Text inside a mainAxisSize.min Row overflows instead of
ellipsizing once the available width is narrower than the label (hit
by the new Today dashboard's stat chips, and latent in the pre-existing
LessonSummaryCard chip they were modeled on). Wrap both in Flexible so
they actually shrink. Also drop two now-unused imports flagged by
analyze after fixing the wrong colorFromHex import and an intl import
already covered by easy_localization.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LJRKq8YRXgS65F9dAcQxNi
Turn the screen stateful so a teacher can pick any date via a date
picker (tap the date header or the calendar icon in the app bar) to
review or catch up on a past day's attendance/grades/homework/material
across all groups, the same way as for today. A "jump to today" icon
appears in the app bar whenever browsing away from the current date.

No new repository work needed: TodayRepository.watchTodayOverview was
already parameterized by date.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LJRKq8YRXgS65F9dAcQxNi
Accept an optional initialDate on TodayDashboardScreen and read it
from a ?date= route query parameter in /today, the same convention
Lesson Mode already uses for its own initialDate. Falls back to today
when absent, so existing links and the nav bar destination are
unaffected; this only adds the ability to open the dashboard directly
onto a specific date from a URL.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LJRKq8YRXgS65F9dAcQxNi
Teachers often call a student by a name that isn't their official
first name. Add an optional callName field to Student, shown in place
of firstName everywhere a name is displayed while the surname always
stays visible alongside it (both sort orders). The official firstName
and lastName are unchanged and still what CSV exports and WebUntis
import matching use.

- New nullable students_table.callName column (schema v22, migrated).
- studentDisplayName/studentDisplayNameWithOrigin/
  isGeneratedStudentDisplayName in formatting.dart prefer callName,
  falling back to firstName when unset or blank.
- Student form gains an optional "Call name" field; StudentDraft,
  StudentRepository.addStudent/updateStudent, and GroupRepository's
  clone-group student copy all carry it through.
- Every existing display call site (lesson roster, seating plan,
  notes, lists, group/student detail and summary screens, avatar
  widgets) now passes the student's callName.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LJRKq8YRXgS65F9dAcQxNi
isGeneratedStudentDisplayName only compared the stored label against the
name built from the call name, so a checklist label written before a call
name was set (e.g. "Mustermann, Alexander") stopped being recognized as
auto-generated the moment one was added. The item then froze at the old
name and grew a redundant linked-student chip, because the screen treated
it as a custom label.

Match against the plain first name as well as the call name, so labels
generated either side of the change still re-render with the current name.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LJRKq8YRXgS65F9dAcQxNi
Resolving a sync conflict with "keep this device's version" adopted the
server's revision and then re-exported. But exportNow() reports upload
failures through the backup status message, not its return value, so a
failed upload looked like success: the conflict screen told the teacher
it was resolved, and the adopted revision stayed persisted. The next
auto-export would then overwrite the server copy without ever raising
the conflict again.

Treat the export as successful only when lastExportedAt actually
advances, restore the previous revision otherwise, and return a real
error code so the screen reports the failure instead of dismissing.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LJRKq8YRXgS65F9dAcQxNi
@mikebarkmin mikebarkmin changed the title feat: add Today dashboard and backup conflict resolution UI feat: add Today dashboard, backup conflict resolution, and student call names Aug 5, 2026
@mikebarkmin
mikebarkmin merged commit 7102769 into main Aug 5, 2026
1 check passed
@mikebarkmin
mikebarkmin deleted the claude/teacher-perspective-review-gc43yb branch August 5, 2026 06:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants