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 · BooksTrips and reads covering that day, with a "Day 3 of 8" pillEach bucket list screen
MoviesFilms planned for, or watched on, that dayThe movies 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 entriesEvery entry written that day, newest firstThe journal screen

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, movies, meals, gratitudes and journal entries don't get an Agenda-specific row style. They render that module's own row component — the same one its dedicated screen uses, where it has one.

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 eight sections lay out one card per row, matching how their own list screens look, rather than being packed inside a single section card — each row carries its own card. Only events, finance and time use the lighter shared section card: the first two have bespoke cards of their own, and a tracked session is a single line.

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.

5Things that take more than a day

A day view has an obvious failure mode: things that aren't a day long. A trip to Kyoto runs a week. A book takes a fortnight. Both used to be stored as a single date, which meant a week in Japan appeared on the day view once and was invisible for the other six days — the app quietly claiming you weren't doing the thing you were, in fact, doing.

Places and books now have a start day and an end day, and the day view shows them on every day in between, with a small "Day 3 of 8" pill next to the title so the same row on seven different days never looks like seven different trips. The end day is included: a trip that starts and ends on the same date is simply one day long, and setting it that way is still a two-tap flow.

You can't finish a trip on day three

Swiping to mark a place visited or a book read is offered only on the last day of a span. On the days in between there's nothing meaningful to confirm, so the action isn't there — and because the swipe travels with the shared row, that's equally true on the bucket list screens. Deleting still works from any day.

Books get a middle state

"To read" and "Read" left nowhere to put the book you're halfway through. A book with a start date and no finish date is now Reading, and it sits in the open half of its section on every day since you started it, rather than in the finished half. It isn't a new thing stored alongside the old ones — it's just what a start date without an end date means — so counts, limits and reminders that only ever cared whether a book was finished carry on unchanged. Marking it read keeps the day you started and adds today as the day you finished.

Two places at once

You can read three books at a time; that's normal. You cannot be in two countries at once, and the database itself refuses overlapping trips rather than trusting the app to check — with one deliberate exception: a trip may end on the day the next one starts, because flying home from France and out to Egypt on the same date is a real thing people do. The app catches the clash first and names the trip you're colliding with, so the refusal arrives as a sentence rather than an error.

Planned dates are a span too, so the weekly planning flow earmarks a run of days instead of one. Overlapping plans only warn — planning is speculative, and a planner that blocks you from sketching two possibilities is a planner you stop using.

Movies were left alone. A film is a one-sitting thing.

6Three 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 the one small module with a "View all"

The journal section lists every entry written on the selected day, newest first, using the journal module's own row component — the same one the journal screen renders, so an entry's preview, timestamp, mood, category chip and tag pills look identical in both places. A day can hold as many entries as you write; each carries its own time, because the point is a log rather than one page per day.

Unlike meals and gratitudes, it gets a "View all" chevron, and that difference is the reason it has a screen at all. A meal or a gratitude is only ever interesting on the day it belongs to, so the day view is the whole feature. Journal entries accumulate, and what you eventually want from them — searching, or reading the same date in earlier years — is a question about every day at once, which a single day's section structurally can't answer.

7Why 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.