Notechondria
Version: 0.1.18 Build Date: 2026-04-10T00:00
What's Changed
Planner — Learner folder grouping
-
The Learner (notes) view now groups notes into expandable course folders
instead of a single flat list. Each folder shows its course title, a note
count, and an
ExpansionTilethat defaults to expanded. Notes inside each folder keep the existing chronological order (most recent on top).
Planner — Activity view ics import with confirmation
-
The Activity view's floating add button now long-presses to open an
import / subscribe menu. The
Import iCal filepath accepts both raw.icsfiles and.ziparchives (extracting the first.icsentry with the pure-Dartarchivepackage), then surfaces a confirmation dialog before the feed is created. -
The confirmation dialog parses the iCal on the client with a
lightweight RFC 5545 scanner that unfolds continuation lines, walks
BEGIN:VEVENT/END:VEVENTblocks, and extractsSUMMARY,DTSTARTandX-WR-CALNAME. It displays the event count, the first/last event dates, and the first five sample events with their start times. The default title is prefilled fromX-WR-CALNAMEwith an inline editable text field. -
Added
archive: ^3.4.10toplanner_app/pubspec.yaml. The package is only used at import time, so startup cost stays minimal.
Planner — Calendar subscribe link fix (Task 5)
-
Root-caused the "cannot subscribe from Google Calendar share links"
bug. The backend was fetching
feed.source_urlverbatim withurllib.request.urlopen, which fails against Google Calendar HTML share URLs (/calendar/embed?src=…or?cid=<base64>) because those are HTML pages, not iCal streams. The Grammarly stack trace the user saw was unrelated browser-extension noise. -
Added
normalize_calendar_url(url)inbackend/notes/services.py. It recognizes the two most common Google Calendar share shapes and rewrites them to the canonicalhttps://calendar.google.com/calendar/ical/<id>/public/basic.icsform. Non-Google URLs (iCloud, Outlook, raw.ics) pass through unchanged. -
CalendarFeedListCreateApiView.postnow normalizessource_urlbefore persisting, so the stored feed is always fetchable. -
read_calendar_feednow issues the HTTP GET via aurllib.request.Requestwith a realUser-AgentandAccept: text/calendarheader, working around providers that reject default Python user agents. -
Frontend: the subscribe dialog's helper text now tells users to
prefer the "Secret address in iCal format" from Google Calendar
settings and notes that public share URLs and direct
.icsURLs also work. -
New
NormalizeCalendarUrlTestsinbackend/notes/tests.pycover pass-through,embed?src=rewrites,cid=base64 rewrites, direct.icsURLs, and empty inputs.
Portal — Full sidebar with Learner / Course / Activity / Settings
-
Portal now surfaces all five modules (Front, Learner, Course,
Activity, Settings) via
visibleIndices: <int>[0, 1, 2, 3, 4]inportal_app/lib/main.dart, renamed_titles/_destinationsinportal_app/lib/app_shell.dart, and real icons for each route.
Portal — Front page with public courses and heatmap
-
Rewrote
portal_app/lib/modules/front.dart. The old "portal route cards" widget is gone; the new front page renders three sections driven by the existing/api/v1/front-page/payload:_PublicCoursesSection— horizontally-scrolling carousel of recent public courses with cover image (or theme-colored placeholder), title and description. Tapping a card routes into the Course view._HeatmapSection— GitHub-style contribution heatmap that groups cells into 7-row weekly columns, tints past cells with the primary color and upcoming planner load with the tertiary color, and marks the current day with a border. Only visible when authenticated._RecentPublicNotesSection— compact discovery list of six recent public notes that opens the note viewer on tap.
Portal — Root URL redirect
-
The Pages root
*.github.io/Notechondria/now lands on the portal app. The gh-pages workflow writes aindex.htmlwith both ameta http-equiv="refresh"and a JavaScript fallback that preserves any incoming query/hash, so deep links keep working. -
The docker gateway already routed
/→/portal/(seedeployment/docker/nginx/default.conf), so the fullstack stack was already correct for this task.
Backend — Welcome note on first sign-in
-
Added
seed_inbox_and_welcome_note(creator)inbackend/notes/services.py. It ensures the creator has a default Inbox category, then inserts a single onboarding note (title, twoNoteBlocks, matchingNoteIndexrows) if the Inbox is currently empty. The helper is fully idempotent so re-verifying or repeat OAuth sign-ins never duplicate the welcome note. -
VerifyEmailApiView.postcalls the helper after activating the user, giving every email-registered user a populated Inbox on first login. -
_get_or_create_oauth_useralso calls the helper in the "brand-new OAuth account" branch, so Google / GitHub sign-ups land on the same onboarding experience. -
New
WelcomeNoteSeedingTestsinbackend/notes/tests.pycover the three paths: fresh creator, creator with existing notes in Inbox (idempotent no-op), and creator with an empty Inbox course already present (reuse, do not duplicate).
Docs — Versions index
-
docs/SUMMARY.mdnow has aVersionssection listing every release doc underdocs/versions/in reverse chronological order, with the two most recent entries annotated so the mdBook site doubles as a changelog.
Deferred
- Task 14 (Portal Settings aggregation with full feature parity to editor
Settings) is only partially delivered in 0.1.18: the Settings module is
now visible in portal's sidebar and covers account/preferences/sync, but
the v0.1.17 editor-only additions (API key section, password/email
change dialogs with identity-code verification, config file download)
still need to be ported into portal's
modules/settings.dart. This requires syncing client methods, app_shell callback wiring, and the_ApiKeySectionwidget; tracking for 0.1.19.
Files Changed
frontend/planner_app/lib/main.dart— 4-modulevisibleIndices,archiveimportfrontend/planner_app/lib/app_shell.dart— fixed hardcoded index references for the 4-module planner (Settings at index 3, Course at 1)frontend/planner_app/lib/modules/learner.dart—_NoteFolder,_groupNotesByCourse,_NoteFolderSectionfolder-grouped renderingfrontend/planner_app/lib/modules/activity.dart— comprehensive_showImportCalendarDialogwith.ics/.zipinput, RFC 5545 preview parsing, confirmation dialog; subscribe dialog helper text updatefrontend/planner_app/pubspec.yaml—archive: ^3.4.10frontend/portal_app/lib/main.dart— 5-modulevisibleIndicesfrontend/portal_app/lib/app_shell.dart— renamed titles/destinationsfrontend/portal_app/lib/modules/front.dart— rewrite with_PublicCoursesSection,_HeatmapSection,_RecentPublicNotesSection.github/workflows/frontend-pages.yml— rootindex.htmlredirect to./portal/backend/notes/services.py—normalize_calendar_url,seed_inbox_and_welcome_note, User-Agent header on feed readsbackend/notes/api.py— normalize URL inCalendarFeedListCreateApiViewbackend/notes/tests.py—NormalizeCalendarUrlTests,WelcomeNoteSeedingTestsbackend/creators/api.py— welcome-note seeding inVerifyEmailApiView.postand_get_or_create_oauth_userdocs/SUMMARY.md— newVersionssectiondocs/TASKS.md— moved completed items into the 0.1.18 sectiondocs/versions/0.1.18.md— this documentVERSION— bumped from 0.1.17 to 0.1.18