Commit Graph

17 Commits

Author SHA1 Message Date
jacobh2 75b549fb4f Goldens: three variants at 1x density (sv_light, sv_dark, en_light; D-098)
Drop the en_dark variant from every screenshot helper and render every
golden at mdpi (Robolectric qualifier w411dp-h<height>dp-mdpi instead of
xhdpi/xxhdpi), so a 411 x 891 dp screen is 411 x 891 px. All goldens
deleted and re-recorded; 1143 -> 865 PNGs. README describes the layout.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TQd3pEP9UeN2uifbHknQ7B
2026-10-18 21:30:33 +02:00
jacobh2 328c4666c4 M8b: UI fixes from the first phone test
- Invite code field (S-1): the value stays the raw normalised code and the
  grouping hyphens are a VisualTransformation with an exact OffsetMapping, so
  the cursor stays after the last typed character when a hyphen appears and a
  backspace after a hyphen removes the character before it. Unit tests.
- Category quick row and grid: the selected item's check badge is drawn in a
  layer above the clipped item, so it is no longer cut at the tile corner.
- Edge to edge: KvittTopAppBar pads for the top safe-drawing inset (status
  bar) with its fill behind it; an ancestor's inset is consumed, not doubled.
  Catalogue sample with a 24 dp inset.
- Stacked bar chart corners 4 / 2 dp (owner override of 10 / 4, proposed D-097).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TQd3pEP9UeN2uifbHknQ7B
2026-10-18 21:08:08 +02:00
jacobh2 a3127586ca Cleanup: remove unused Vico catalog entries (D-063)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TQd3pEP9UeN2uifbHknQ7B
2026-10-18 15:15:30 +02:00
jacobh2 8c607153c0 M12e: contract pass (pair invite kind, admin name in invite links, sync failed flag, rejection actor, device version name, template id, update check result, untouched accounts, D-027 re-stamp, PushEvent in :core:model, snackbar hosts)
Server: E-3 invite_kind; E-12 link ?from=<admin name>, E-4 passes it into kvitt://invite;
X-Kvitt-App-Version-Name stored in devices.app_version_name (migration 0003, schema 3);
OpenAPI and examples follow. Phone: :core:model, :core:fakes, :data, features and :app
updated together; goldens re-recorded for S-20 (version name) and new S-1/S-22 states.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TQd3pEP9UeN2uifbHknQ7B
2026-10-18 15:00:56 +02:00
jacobh2 b24c8b5ba3 M6b: core:design fixes after the M7 wave
Bugs: viewerPercentOf reads basis points (Samples in bp); FullSplitPicker and the
split labels use editor_split_full_on_you ("Allt på dig"); AmountInput.of restores
money with both decimals (AmountInput.percent for ratio fields), replacing M7c's
moneyInput; quickRowCategories does the D-060 fill itself; KvittScaffold resolves
resource-backed snackbars (showKvittSnackbar) while shown.

Gaps: ConfirmDialog optional and styled body; KvittButton loading form (M7a uses it,
ProgressBottomButton removed); InviteCodeField wraps after a group, placeholder,
imeAction; EmptyState icon tile and actionEnabled; DateFormatter.monthName and
dayRangeLong; AnalyticsFilterBar periodOwnRow; segmentedItem builder; screen tokens
in KvittDimens (OnboardingDimens removed); common_ok, common_undo; module-proposed
keys recorded in strings.csv; quick-row labels end in an ellipsis on line two.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TQd3pEP9UeN2uifbHknQ7B
2026-10-18 11:35:06 +02:00
jacobh2 c4ab35f66e M7f: feature settings, S-13 to S-15 and S-19 to S-22
Hub, profile (photo picker), categories (drag reorder, editor with D-059 delete reasons), recurring
expenses (list and S-7-style editor with schedule, AC-9.8 default start), devices, invites and about,
against the :core:model interfaces. Scenarios and scripted online failures in fakes/settings.
84 states screenshot-tested in sv/en x light/dark (336 goldens); state-holder unit tests.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TQd3pEP9UeN2uifbHknQ7B
2026-10-18 11:04:32 +02:00
jacobh2 0b140aa3ad M7c: feature expense, S-7 editor and S-8 detail with timeline
Expense editor (S-7) and expense detail (S-8) in :feature:expense against the
:core:model interfaces and :core:design components: defaults (AC-8.6), keypad
input (§9.6), the four split modes with live preview (AC-8.5, AC-8.7, AC-8.8),
category suggestion with the picked-by-hand flag (CS-2, CS-3, CS-7), quick row
from frequentCategoryIds (D-059, D-060), inline errors, delete and discard
confirmations; detail with hero, facts, timeline, recurring, deleted and missing
states. Fake scenarios in fakes/expense, view-model tests and 127 goldens.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TQd3pEP9UeN2uifbHknQ7B
2026-10-18 10:54:28 +02:00
jacobh2 0e1d99df93 M7b: feature home and account (S-4, S-5, S-6, S-16, S-17)
:feature:home: Home with balance hero, sync pill, accounts, archived section,
empty and first-sync states, update banner and "Tillåt installation" dialog;
sync status with pending rows, rejections of every §14.4.6 reason and the
clock-skew banner. :feature:account: account detail with header, ledger by
month, overflow menu, archive/unarchive/delete and their errors; account
editor with name, percent fields (two decimals), slider, presets, preview,
name_taken/validation errors and offline state. Fake scenarios in
fakes/home and fakes/account; full-screen Roborazzi goldens for every state
in sv/en × light/dark (200 % for long states); ViewModel unit tests.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TQd3pEP9UeN2uifbHknQ7B
2026-10-18 10:49:55 +02:00
jacobh2 7380e50ae3 M7d: feature settle, S-9 settle up and S-10 settlement detail
SettleScreen (global, per account, editing) and SettlementDetailScreen with
Hilt ViewModels over the :core:model interfaces; proposals, remaining,
warnings and enablement come from SettlementRepository. Fake scenarios in
fakes/settle/, 19 states x sv/en x light/dark goldens (+ 200 % for long),
unit tests for amount input and both state holders.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TQd3pEP9UeN2uifbHknQ7B
2026-10-18 10:46:54 +02:00
jacobh2 ea7d494ffa M7e: feature analytics (S-11, S-12) with fake scenarios and screenshot tests
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TQd3pEP9UeN2uifbHknQ7B
2026-10-18 10:44:45 +02:00
jacobh2 1ea752cd80 M7a: feature onboarding (S-1, S-2, S-3, S-18) with fakes, unit and screenshot tests
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TQd3pEP9UeN2uifbHknQ7B
2026-10-18 10:41:52 +02:00
jacobh2 9ee67d4c64 SPEC v0.10: M12d and M6 outcomes (D-060 to D-068), Dining label, ledger_settlement_label
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TQd3pEP9UeN2uifbHknQ7B
2026-10-18 10:32:06 +02:00
jacobh2 7730a31af6 M6: design system in :core:design (Kalas muted, design-spec §2 and §3)
KvittTheme with every Material and Kvitt colour role light and dark, the 14
category colours with containers, chart and avatar colours, type scale with
tabular amount styles, spacing, shapes (stable fallbacks: MaterialShapes is not
in Material 3 1.4.0), elevation and motion springs; 191 Material Symbols
Rounded vector drawables (33 category tokens filled and outline, UI icons);
253 shared strings from docs/ux/strings.csv in values and values-sv with
plurals; pure-Kotlin MoneyFormatter, DateFormatter (ISO weeks) and AmountInput
with unit tests; every component of design-spec §3 with TalkBack semantics,
including the ledger rows and editor fields (D-019) and Canvas charts; a
preview catalogue in the debug source set; 212 Roborazzi goldens (49 sheets x
light/dark x sv/en plus 16 at 200 %). The two :app empty-screen goldens are
re-recorded because they render the real theme now (PNG only).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TQd3pEP9UeN2uifbHknQ7B
2026-10-18 09:30:49 +02:00
jacobh2 557af7e00a M12d: frequentCategoryIds and CategoryRepository.deletable (UX-9, D-059)
ExpenseEditorOptions.frequentCategoryIds per active account (up to five active
categories by non-deleted expense count in the account, ties by sort_order) and
CategoryRepository.deletable(id) (AC-7.6), from Room queries in :data and the
same rule in :core:fakes. Room schema unchanged (version 1).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TQd3pEP9UeN2uifbHknQ7B
2026-10-18 08:35:35 +02:00
jacobh2 b09f3220a1 M12c: category contract v2 on Android (14 defaults, suggestCategory)
- :core:model: DefaultCategoryKey in AC-7.2 order (14 keys: housing, insurance, children, fees added),
  ColorToken + SLATE, AMBER, CategoryIcons.ALL + key, shield, account_balance (33),
  ExpenseRepository.suggestCategory(accountId, description); ContractTest updated.
- :domain: parseCategoryKeywords (pure, shared by :data and :core:fakes) with a parser test; the
  suggestCategory records and rule unchanged, suggest_category vectors pass.
- :data: PlatformUnicodeText (java.text.Normalizer, Character), CategoryKeywords parsed once from the
  Java resource that copyCategoryKeywords copies from contracts/category-keywords.csv at build time
  (missing file fails the build), ExpenseRepositoryImpl.suggestCategory over the Room snapshot and the
  DataStore last-used category; tests: byte identity and the 14.8 rules of the bundled table, the
  UnicodeText binding, and Room/Robolectric cases for history, first token, ties, keywords, fallback,
  archived categories, deleted expenses, both users and accounts, null account.
- :core:fakes: the 14 defaults with the schema v2 ids, fake suggestCategory through :domain with its own
  build-time copy of the table; tests.
- Room schema unchanged (version 1).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TQd3pEP9UeN2uifbHknQ7B
2026-10-18 08:21:59 +02:00
jacobh2 8f0e156b38 M5: Android data layer: DAOs, Ktor client and DTOs, token store, sync engine and workers, repositories, APK updater
DAOs on M2b's Room 3 entities and KvittDatabase v1 (schema 1.json unchanged), DTOs for every wire
object and endpoint body with a round-trip test over all 80 contract examples, the Ktor client with the
section 14.3.1 headers and 14.3.2 error mapping, the Keystore-encrypted token store in auth.preferences_pb,
the sync engine of section 14.4 (push batches, pull pages, epoch recovery, rejections, clock skew, 401 and
426 handling) tested with MockEngine including AC-15.6, WorkManager triggers, every :core:model repository,
the APK updater behind an installer interface, Coil pictures, Hilt modules, Room migration test
infrastructure. Fakes: the five settled TODO(spec) comments resolved per SPEC v0.4 (settlement row in an
account's ledger carries that account's allocation).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-17 22:14:53 +02:00
jacobh2 c277ee37c2 M2b: Android skeleton, :core:model contract, :domain passing all vectors
Gradle project in android/ with every module of SPEC §6.2 (build-logic convention plugins, version catalog,
architecture check in check), :core:model types and repository interfaces of §14.2.4 and §14.5, :domain
implementing §14.5.2 and §14.5.4 (125 vector cases), scenario-driven fakes with the empty scenario, Room 3
entities and KvittDatabase v1 with exported schema, :app shell with Hilt, en/sv strings with MissingTranslation
as a lint error, Roborazzi goldens of the empty screen in light and dark.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-17 21:25:19 +02:00