Notechondria
Version: 0.1.71 Build Date: 2026-04-26T16:00
What's Changed
Bug — local courses pulled public notes that didn't belong to them
-
User-reported: "when user in offline mode and create offline categories, the public notes will still pop. Public notes only fit for online category and should never appear on local user-created category". Root cause:
_loadLearnerNotesineditor_app/lib/core/note_loading.dartalways calledwidget.client.listNotes(...)regardless of which category was selected. When the active course had a negative id (locally-created, not yet synced) the call still went out — withcourseId=nullbecause the backend can't filter by a negative id — and the server returned a generic public-notes feed that got rendered under the user's offline category. -
Fix: short-circuit
_loadLearnerNoteswhen the selected category id is negative or when the explicit filter scope islocal. Both paths clear_learnerNotes, set_hasMoreLearnerNotes=false, and return without hitting the network.
Note-state filter — 4-option dropdown replaces the old checkbox
-
Spec: "create a drop down (local notes, personal notes, public notes, private notes) allow user to filter their own notes, default set to show personal notes (include private and public)". The previous "Include public notes from other users" checkbox is gone. New
DropdownButtonFormFieldlives at the top of the learner page with four options: Personal (default, private + public own notes), Private (own private), Public (own public), Local drafts only. -
Backend
notes/api.pyextended to honorscope=privateandscope=public(own + visibility filter).scope=alland the defaultscope=personalare unchanged for back-compat. -
When the user opens a locally-created (negative-id) category the dropdown is force-pinned to "Local" and disabled, with an info-icon tooltip explaining why ("Local categories only contain local drafts. Switch to a synced category to filter cloud notes.").
Local-note search — entirely client-side
-
Spec: "Implement search function for local notes over
frontend."
_visibleLocalDraftsalready used_localSearchScore; this round adds course-scoped local drafts: when a category is selected,build_helpers.dartpasses_localNotesForCourse(_selectedCourse)to_LearnerPageinstead of all_localDrafts. The local search now operates on the right list — drafts that belong to the current category — and respects the new "Local drafts only" filter.
Visual state distinction for notes
-
Spec: "Make clear distinction between the states of the
notes." New
_NoteStateBadgepill widget renders inline next to each note title, with icon + colored background pulled from thecolorScheme:- Local draft:
cloud_off_outlinedicon,tertiaryContainerbackground. - Public:
publicicon,primaryContainerbackground. - Private:
lock_outlineicon,surfaceContainerHighestbackground. Replaces the previous single-line text concatenation (Local draft | course | timestamp) with a clearer at-a-glance signal.
- Local draft:
Live-markdown editor — padding fix
-
Spec: "Remove the extra container border for live markdown
editor, rendering have too much padding on left and right make
the horizontal view too narrow." The wrapping
Cardaround_buildInlineLiveMarkdownBodyis gone; the innerSingleChildScrollView's horizontal padding drops from 20 to 4. The dialog already provides a 20px outer gutter, so the old total of 40+px on each side made the rendered view feel cramped on phones.
Files Changed
frontend/editor_app/lib/core/note_loading.dart—_loadLearnerNotesshort-circuit for local-course /scope=local.frontend/editor_app/lib/core/build_helpers.dart— pass_localNotesForCourse(_selectedCourse)to_LearnerPage; pass newisLocalCourseSelectedprop.frontend/editor_app/lib/modules/learner.dart— replace checkbox with 4-option dropdown;_NoteStateBadgewidget;_searchHint/_cloudSectionLabel/_emptyCloudCopy/_buildScopeItemshelpers; visibility logic for the cloud section keyed offeffectiveScope.frontend/editor_app/lib/modules/note_editor.dart—_buildLiveMarkdownEditorreturns the body directly (no Card wrapper); inner padding 20 → 4.backend/notes/api.py—scope=privateandscope=publicbranches added to the list endpoint, with comments explaining the new semantics.
Notes
- Backend
scope=allis preserved for back-compat. The frontend doesn't surface it in the new dropdown, but third-party clients (and an older frontend mid-rollout) can still request it. - Round-trip behavior: switching from a local category to a
synced one re-issues
_loadLearnerNoteswith the previous scope; switching back to a local category resets the cloud list to empty as documented above.