feat(compose): remember last-used font and size #197

Merged
JMR-dev merged 2 commits from feat-78-remember-font-size into main 2026-07-03 04:55:24 +00:00
JMR-dev commented 2026-07-03 04:33:24 +00:00 (Migrated from github.com)

Summary

  • SettingsRepository: adds lastFontCss (String?) / lastFontSizePt (Int?) to AppSettings, their Keys/toAppSettings() mapping, and setLastFont(fontCss, fontSizePt) — following the same null-clears-the-key pattern as setDefaultAccountId (and the same shape as the licenseAccepted field added by #172).
  • ComposeViewModel (SettingsRepository was already injected, from #163's default-account work — no constructor change, so no call sites needed updating):
    • On send: after a successful send, parses the outgoing bodyHtml with RichTextHtml.fromHtml and persists the font — the message-wide RichBaseStyle if one is set, else the last FontFamily/FontSize inline span (each axis independently). A plaintext send, or a formatted one that never touched a font, leaves the stored preference untouched.
    • On brand-new compositions only (draftId == null — replies/forwards always arrive as drafts): after the sending account's signature is applied, seeds a RichBaseStyle from the remembered font so the whole message (including the signature) defaults to it. No-op when nothing has been remembered yet, so an unformatted message doesn't gain an HTML body for no visible reason.

No Room schema change — this is Preferences DataStore only.

Test plan

  • MockK ComposeViewModelTest: persists the base-style font on send; persists the last matching span per axis when there's no base style; does not persist when the sent message has no font styling or is plaintext-only; seeds a brand-new composition (bare and with a signature) with the remembered font; does not seed an existing/resumed draft; stays plaintext-only when composing new with no remembered font.
  • AppSettingsTest: lastFontCss/lastFontSizePt default/round-trip/independent-nullability coverage at the toAppSettings() mapping layer, matching the existing licenseAccepted/defaultAccountId pattern.
  • .\gradlew :app:assembleDebug
  • .\gradlew :app:testDebugUnitTest (28/28 ComposeViewModelTest, 11/11 AppSettingsTest)
  • .\gradlew :app:lintDebug
  • .\gradlew :app:ktlintCheck :app:detekt
  • .\gradlew :app:compileDebugAndroidTestKotlin (confirms ComposeScreenTest's direct VM construction still compiles)

Closes #78

🤖 Generated with Claude Code

## Summary - `SettingsRepository`: adds `lastFontCss` (String?) / `lastFontSizePt` (Int?) to `AppSettings`, their `Keys`/`toAppSettings()` mapping, and `setLastFont(fontCss, fontSizePt)` — following the same null-clears-the-key pattern as `setDefaultAccountId` (and the same shape as the `licenseAccepted` field added by #172). - `ComposeViewModel` (SettingsRepository was already injected, from #163's default-account work — no constructor change, so no call sites needed updating): - **On send**: after a successful send, parses the outgoing `bodyHtml` with `RichTextHtml.fromHtml` and persists the font — the message-wide `RichBaseStyle` if one is set, else the last `FontFamily`/`FontSize` inline span (each axis independently). A plaintext send, or a formatted one that never touched a font, leaves the stored preference untouched. - **On brand-new compositions only** (`draftId == null` — replies/forwards always arrive as drafts): after the sending account's signature is applied, seeds a `RichBaseStyle` from the remembered font so the whole message (including the signature) defaults to it. No-op when nothing has been remembered yet, so an unformatted message doesn't gain an HTML body for no visible reason. No Room schema change — this is Preferences DataStore only. ## Test plan - [x] MockK `ComposeViewModelTest`: persists the base-style font on send; persists the last matching span per axis when there's no base style; does *not* persist when the sent message has no font styling or is plaintext-only; seeds a brand-new composition (bare and with a signature) with the remembered font; does *not* seed an existing/resumed draft; stays plaintext-only when composing new with no remembered font. - [x] `AppSettingsTest`: `lastFontCss`/`lastFontSizePt` default/round-trip/independent-nullability coverage at the `toAppSettings()` mapping layer, matching the existing `licenseAccepted`/`defaultAccountId` pattern. - [x] `.\gradlew :app:assembleDebug` - [x] `.\gradlew :app:testDebugUnitTest` (28/28 `ComposeViewModelTest`, 11/11 `AppSettingsTest`) - [x] `.\gradlew :app:lintDebug` - [x] `.\gradlew :app:ktlintCheck :app:detekt` - [x] `.\gradlew :app:compileDebugAndroidTestKotlin` (confirms `ComposeScreenTest`'s direct VM construction still compiles) Closes #78 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Sign in to join this conversation.