chadtmiller.com/knotless
git that lives in your Atmosphere account
The iOS app is drawn in knotless's themes, the account's own included
MergedThis pull draws the iOS app in knotless's themes. It adds colour tokens in Palette.swift, a themed Appearance screen, and a cached copy of the account's theme and own themes. I read the models, client, app entry, Palette.swift, AppearanceView.swift and Theme.swift closely. The remaining view files are mostly token swaps, and I did not read them.
The design holds up. The old automatic, light and dark raw values still mean the same thing, so existing choices carry over. A theme the account no longer has falls back to iOS's colours.
- Merge conflict: the head conflicts with main in
Support/Markdown.swiftandViews/RepoView.swift, so every check failed without running. Merge main into the branch and run them again. The checks enforce this, so I'm not holding the approval for it. - Fragile theme load: one note on
AccountTheme.load, in the line comment below. It is a robustness issue rather than a blocker.
ios/Knotless/Views/AppearanceView.swiftline 122
for i in added.indices { added[i].maker = found.themes.first { $0.uri == added[i].uri }?.creator?.handle } | |
} | |
let all = (mine + added).sorted { ($0.at ?? "") > ($1.at ?? "") } | |
hold(answer.appearance, themes: all) |
If the listThemes call with actor fails (made is nil) while getPreferences succeeds, mine is empty and hold overwrites the cached list with only the added themes. The account's published themes then disappear from the picker. If one of them was selected, the app falls back to iOS's colours, and that is saved too, so it stays that way offline. When either themes query fails, keep the previous themes rather than replacing them.
The only change since my approval is the merge of main, which resolved the two conflicts in Support/Markdown.swift and Views/RepoView.swift. I read the pull's diff for both files. Each side's change is kept: main's PagedList and ItemsView bodies are now wrapped in a Group with .listRowBackground(Color.page), and the remaining colours use the tokens. I found nothing wrong. The pull now merges cleanly.
My earlier note on AccountTheme.load still applies. If the listThemes call with actor fails while getPreferences succeeds, hold overwrites the cached themes with only the added ones. It is not a blocker.
8 passed, 2 skipped
What changes
Themes on iOS. The app is drawn in the themes knotless's pages are. Settings, Appearance is now a screen of its own, each choice with a swatch of its colours: Same as knotless.dev (the default), which follows the account's
appearancePref, day and night pairs included; Automatic, Light and Dark, iOS's own colours as before; the six themes the pages offer by name; and Your themes, those the account published (listThemeswithactor) and those it added (themesPref), each added one saying who made it (listThemeswithuris). A choice changes the whole app at once, with no screen rebuilt. The account's theme and its own are kept, so the app starts in them offline.Colour tokens. Every iOS colour the screens took directly (
systemBackground,secondarySystemGroupedBackground,separator,Color.primary, …) is now a token inSupport/Palette.swiftthat stands for that same iOS colour where there's no theme, and for the theme's where there is. Lists and screens draw on the theme's page. The states' colours, the accent and code's highlighting follow the theme too. A palette that leaves colours out is filled in astokens.cssdoes.Buttons as on the pages. In a theme the main button (Merge pull, Review, a review's send) is the theme's
primaryunder itsonPrimary; a state's pill and an icon square its colour underonSolid; and a button beside the main one (Add to merge queue, Leave the queue, Unblock) sits on the theme's surface. In iOS's own colours they're as they were, but for Merge pull in dark mode, now the darker green under white that light mode has, as white on dark mode's green read poorly.ios-look.
--theme dracula(orlatte/mochafor a pair) draws a screen in a theme,appearanceis a new screen, and each run starts as a new install, so what the simulator was left in doesn't show.look-answers.jsonrecords two themes of alice's for it.Why
The pages have themes, and anyone can make and share one; the app was the one place they didn't reach. A theme's colours are named for what they colour, so they map onto the app's surfaces, texts and states as they do the pages', and the pairs the pages' contrast check holds a theme to (
on-primaryonprimary,on-solidon the states') are the ones the app draws, so a theme that passes there reads here. Choosing on the phone stays on the phone, an override of the default rather than a change to the account's pages.How it was checked
Every
ios-lookscreen, scrolled to its end, in iOS's light and dark, Dracula and Latte, each looked at: the default as before, the themes whole. Picking a theme in Settings and one of the account's own (Ember, recorded) changes the app at once.ios/check-models.shcompiles the models with only Foundation and reads all the recorded answers; its write check, and the rest, are left to CI.Shortcomings
Sheets (new issue, review, report) weren't looked at in a theme, as
ios-lookdoesn't open them, and neither were pckt, plyr and Blacksky. A pair whose halves are both dark has iOS's light chrome by day. Themes are made and edited on the pages only.Review
A look at the pictures, then
Support/Palette.swift(the tokens and how a change of theme reaches them) andViews/AppearanceView.swift. Most of the rest is a colour swapped for its token, or a list's rows given the theme's background.🤖 Generated with Claude Code