Dawnlet · under the hood

Agenda & the day model

Agenda is the screen the whole app is arranged around. It replaced three separate tabs, and the way it's put together is the clearest statement of what Dawnlet thinks a day is.

11 sections One shared row per module Reorderable Replaced 3 tabs

§The idea

Dawnlet used to have three tabs: a planner, a calendar, and a today view. They were three ways of looking at the same information, and switching between them was the user doing a join the app should have done.

They're now one screen: a scheduling grid you page through by week or month, and beneath it the selected day, broken down module by module.

The decision that shaped everything below

An earlier version split the day into "Planned" and "Completed". It was replaced by one section per module, each showing both what's outstanding and what got done. A day reads better module-by-module than status-by-status — you think "what about money today", not "what about things I've finished". It also gave every module somewhere to link out from.

1The grid

A paged week or month grid at the top, with arrows stepping a reference date forward and back and a range label underneath. The reference date is independent of today's actual date, so paging to next month doesn't mean "today" moves — a distinction that sounds pedantic until you page forward three months and come back.

Each day cell carries small coloured dots for the modules that have something on that day, using the same hues the section headers and rows use. The grid, the headers and the rows read as one colour language rather than three.

Week numbering respects a week-start preference, and the same weekday indexing is shared with the habit week strip — so a habit's week and the grid's week always begin on the same day. That sounds obvious and is exactly the kind of thing that silently disagrees when two features compute it independently.

2One section per module

The selected day is rendered as an ordered list of module sections. Each shows what's due or planned for the day and what was completed on it, with outstanding items first and finished ones after.

SectionShowsLinks out to
EventsTimed and all-day occurrencesThe events screen
HabitsHabits due that day, with week strip and streakThe habits screen
TodosDue, overdue, and completed todosThe todos screen
Places · Books · MoviesItems planned for that dayEach bucket list screen
FinanceThat day's transactions and a net totalThe money tab
TimeSessions logged that dayThe time tab
Meals · GratitudesWhat you loggedNowhere — created and edited here only
Journal entriesA placeholderNot built yet

A section header carries a coloured dot in that module's hue and, where there's a screen to go to, a "View all" chevron pushing it.

3Whose rows they are

Habits, todos, places, books and movies don't get an Agenda-specific row style. They render that module's own row component — the same one its dedicated screen uses.

So a habit looks identical in both places: same category chip, same tag pills, same week strip, same streak. A movie carries the same star rating. And because each row bundles its own swipe actions, skipping a recurring todo or restoring a habit day behaves the same on both screens by construction. See shared rows for why that bundling is the important part.

Those five sections lay out one card per row, matching how their own list screens look, rather than being packed inside a single section card. The remaining sections use the lighter shared section card, because their rows are simpler.

The one thing that differs by host

What a tap does. A module screen opens that item's editor; Agenda has no editor, so a tap checks the item off — which is also what a tap does on the habits screen. Marking a movie, book or place done shows the same rating sheet either way.

These rows need categories and tags to draw their chips, so Agenda fetches the full taxonomy once and hands it down, rather than each row fetching what it needs.

4Reordering and hiding

The section list is a parameter, not a hardcoded sequence. That was true before the reordering feature existed — it was built that way specifically so the eventual setting would only have to persist an ordered list and pass it in.

It now does: the order and the hidden set are stored on your account, so a day arranged the way you think about it stays that way on every device.

Events is deliberately not reorderable

Events is always shown and always first, and it can't be represented in the stored order at all. That's what keeps the invariant safe: it doesn't depend on the reorder screen remembering to special-case it, because the reorder screen never sees it.

5Three special cases

Finance is a slot, not a section

The money section is Plus-gated and has its own self-contained card — its own header, its own net total, its own locked state. So the day view takes that card as a slot and merely places it in the order. Every piece of money state stays outside the day-rendering code, which would otherwise have to know about entitlements.

Meals and gratitudes have no home screen

Both are real and fully working, but neither has a screen of its own: they're created and edited entirely from the day view. So they render rows like everyone else, and deliberately have no "View all" — there's nowhere for it to go.

Journal is an honest placeholder

It renders a short "coming soon" note. It's listed anyway so the shape of the day is already right for when it's built, rather than the layout shifting under people later.

6Why it's a list

Swipe actions only work inside a real list. The shared rows bundle their swipe actions. Agenda renders the shared rows. Therefore Agenda is a list.

That chain is worth spelling out because the alternative was tried. A scroll view gives far more layout freedom on what is the busiest screen in the app, so an earlier version used one and reimplemented swiping by hand. It never matched: the rubber-banding, the velocity response, the full-swipe threshold and the way the system cancels a swipe are all subtler than they look. It was deleted and won't come back.

A composed view that emits several rows flattens into separate list rows correctly — which was verified in a simulator rather than assumed, because it's exactly the kind of thing that works until the day it quietly doesn't.