Commit Graph

309 Commits

Author SHA1 Message Date
Trey T
77f32befb8 Audit: meaningful contentDescription for actionable icons (sweep)
Upgrades ~31 sites previously annotated `// decorative` to meaningful
strings where the icon is actionable. Purely decorative leading icons
retain null contentDescription per Material 3 guidance.

Focus areas:
- Selection indicators (CheckCircle vs RadioButtonUnchecked, check marks)
- Status icons (Error, Warning, CheckCircle, ErrorOutline, CloudOff, Info)
- Expand/collapse toggles (ExpandLess/ExpandMore)
- Feature inclusion indicators (Check/Close in comparison tables)
- Requirement indicators (password strength satisfied/not)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 17:57:08 -05:00
Trey T
d8569c7aed Audit: PullToRefreshBox on remaining list screens (iOS parity)
HomeScreen + AllTasksScreen + TasksScreen now support pull-to-refresh.
forceRefresh=true per CLAUDE.md mutation pattern.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 17:50:27 -05:00
Trey T
95f7318ee6 Audit 9a.3: custom sheets → ModalBottomSheet (M3 parity)
CompletionHistorySheet + contractor-picker sheet now use
material3.ModalBottomSheet. Standard Material 3 dim-behind + swipe-down
dismiss + sheet state. Inner content unchanged.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 17:48:14 -05:00
Trey T
40d2607da8 Suite6 + P8: Comprehensive task tests + Roborazzi scaffolding
Suite6_ComprehensiveTaskTests ports iOS tests not covered by Suite5/10
(priority/frequency picker variants, custom intervals, completion history,
edge cases).

Roborazzi screenshot-regression scaffolding in place but gated with @Ignore
until pipeline is wired — first `recordRoborazziDebug` run needs manual
golden-image review. See docs/screenshot-tests.md for enablement steps.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 17:39:39 -05:00
Trey T
0015a5810f Audit 9a: Long-press context menus + swipe-to-dismiss on cards
Partial implementation (wave 9a agent was rate-limited mid-flight).
Delivered:
- TaskCard long-press context menu (Edit / Delete / Share)
- ResidencesScreen + ContractorsScreen swipe-to-dismiss wired for delete
- Confirm dialog before dismissal (non-destructive gesture)

Not yet delivered (follow-up):
- CompletionHistorySheet → ModalBottomSheet migration
- Contractor-picker sheet migration

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 17:39:29 -05:00
Trey T
ba1ec2a69b Audit 9b: Dynamic color (Material You) + 48dp min touch target helpers
Dynamic color opt-in on Android 12+ via expect/actual DynamicColor:
- commonMain: expect isDynamicColorSupported() + rememberDynamicColorScheme()
- androidMain: SDK>=31 gate, dynamicLight/DarkColorScheme(context)
- iOS/JVM/JS/WASM: no-op actuals
- ThemeManager gains useDynamicColor StateFlow, persisted via ThemeStorage
- App.kt wires both currentTheme + useDynamicColor into HoneyDueTheme
- ThemeSelectionScreen exposes the "Use system colors" toggle

Touch target helpers:
- Modifier.minTouchTarget(48.dp) + Modifier.clickableWithRipple
- Applied at audit-flagged sites in CompleteTaskScreen

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 17:39:22 -05:00
Trey T
214908cd5c Maestro: 10 golden-path flows for critical user journeys
Cross-platform YAML flows (iOS + Android share the AccessibilityIds
test-tag namespace). Covers login, register, residence/task CRUD,
completion, join, document upload, theme, deeplink, widget.

Run: maestro test .maestro/flows/

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 15:00:21 -05:00
Trey T
1946fb9e6a Maestro: 10 golden-path flows for critical user journeys
Cross-platform YAML flows (iOS + Android share the AccessibilityIds
test-tag namespace). Covers login, register, residence/task CRUD,
completion, join, document upload, theme, deeplink, widget.

Run: maestro test .maestro/flows/

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 14:59:54 -05:00
Trey T
95a5338abd CI: Gradle Managed Devices + GitHub Actions workflow
pixel7Api34 managed device runs instrumented tests headlessly on CI.
Three test-filter profiles (ci/parallel/full) mirror iOS xctestplan
variants. run_ui_tests.sh convenience wrapper.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 14:57:42 -05:00
Trey T
227c0a9240 UI Test Suite8: Document/Warranty tests (iOS parity)
Ports representative subset of Suite8_DocumentWarrantyTests.swift
(22 of 25 iOS tests). testTags on document screens via
AccessibilityIds.Document.*. Documented deliberate skips in the
class header (5/7/8/10/11/12/16) — each either relies on iOS-only
pickers/menus or is subsumed by another ported test.

No new AccessibilityIds added — Document group already has parity.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 14:54:24 -05:00
Trey T
840c35a7af P7 Stream Y: empty/error/loading state audit (iOS parity)
Audits every list + detail screen (non-document) for empty/error/loading
state parity with iOS. Reuses StandardEmptyState / StandardErrorState where
possible; adds missing states where screens currently show blank on error.

- Add StandardErrorState and CompactErrorState components under
  ui/components/common/ (mirrors iOS ErrorView pattern: icon + title +
  message + Retry).
- ManageUsersScreen: error state previously had no retry button; now uses
  StandardErrorState with a Retry CTA matching iOS ManageUsersView.
- ResidenceDetailScreen: task and contractor sub-section error cards now
  use CompactErrorState with inline retry (previously plain error text).

Other audited screens (ResidencesScreen, TasksScreen, AllTasksScreen,
ContractorsScreen, ContractorDetailScreen, EditTaskScreen,
CompleteTaskScreen, TaskTemplatesBrowserScreen, TaskSuggestionsScreen,
OnboardingFirstTaskContent) already had loading + error + empty parity
via ApiResultHandler / HandleErrors / inline state machines; no changes
needed.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 14:50:07 -05:00
Trey T
d42406cbec UI Test SuiteZZ: Cleanup tests (iOS parity)
Port SuiteZZ_CleanupTests.swift. Deletes test-prefixed residences/tasks/
contractors/documents via authenticated APILayer + TaskApi calls. Runs
alphabetically last via the SuiteZZ_ prefix. Each step is idempotent —
logs failures but never blocks the next run. Preserves one seed "Test
House" residence so AAA_SeedTests has a deterministic starting point.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 14:47:41 -05:00
Trey T
6980ed772b UI Test Suite4: Comprehensive residence tests (iOS parity)
Ports Suite4_ComprehensiveResidenceTests.swift. testTags on residence
screens via AccessibilityIds.Residence.*. CRUD + join + manage users +
multi-residence switch.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 14:43:08 -05:00
Trey T
eedfac30c6 UI Test Suite5: Task tests (iOS parity)
Ports Suite5_TaskTests.swift. testTags on task screens via
AccessibilityIds.Task.*. CRUD + kanban + filter/sort + templates + suggestions.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 14:40:38 -05:00
Trey T
c772215c04 UI Test Suite7: Contractor tests (iOS parity)
Ports Suite7_ContractorTests.swift. testTags on contractor screens via
AccessibilityIds.Contractor.*. CRUD + sharing + link-to-task.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 14:40:21 -05:00
Trey T
95dabf741f UI Test Suite1: Registration + SimpleLogin ports (iOS parity)
Ports iOS Suite1_RegistrationTests.swift + SimpleLoginTest.swift to
Android Compose UI Test. Adds testTag annotations on auth screens using
shared AccessibilityIds.Authentication constants.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 14:38:56 -05:00
Trey T
b97db89737 UI fix 5/5: contentDescription for actionable icons (partial audit)
Actionable IconButton/Icon instances now expose meaningful
contentDescription for TalkBack. Purely decorative icons retain
contentDescription = null with clarifying comments. Full audit of
remaining 130+ sites is follow-up work.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 14:27:17 -05:00
Trey T
00a217e8c8 UI fix 4/5: Button variant migration — OutlinedButton/TextButton for secondary + tertiary
Primary confirmation buttons remain as Button (M3 filled default). Secondary
actions (Cancel, Dismiss) → OutlinedButton. Inline links → TextButton. Reduces
visual hierarchy ambiguity.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 14:22:59 -05:00
Trey T
2d80ade6bc Test infra: shared accessibility IDs + PageObjects + AAA_SeedTests
Ports iOS HoneyDueUITests AccessibilityIdentifiers + PageObjects pattern
to Android Compose UI Test. Kotlin AccessibilityIds object mirrors Swift
verbatim so scripts/verify_test_tag_parity.sh can gate on divergence.

AAA_SeedTests bracketed first alphanumerically; SuiteZZ cleanup to follow.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 14:19:37 -05:00
Trey T
42c21bfca1 UI fix 3/5: imePadding on form screens
Soft keyboard no longer covers input fields. Applied to every screen
with text input.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 14:18:46 -05:00
Trey T
0ec2ac7744 UI fix 2/5: lifecycle-aware StateFlow collection in screens
Replace collectAsState() with collectAsStateWithLifecycle() so StateFlows
stop collecting when the host is in background — prevents memory/CPU leaks
on lifecycle transitions.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 14:15:03 -05:00
Trey T
a78494c529 UI fix 1/5: mirror ArrowBack/ArrowForward/List icons for RTL locales
Material 3 AutoMirrored variants flip correctly in Arabic/Hebrew.
Previous Icons.Default.ArrowBack pointed wrong direction in RTL.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 14:14:02 -05:00
Trey T
03a68a8876 Test infra: add Compose UI Test + UI Automator to androidInstrumentedTest
Prep for parallel Android UI test suite build-out. These deps unblock
page-object tests using onNodeWithTag / createAndroidComposeRule and
cross-app permission-dialog interaction.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 14:10:00 -05:00
Trey T
485f70dfa1 Integration: residence invite accept/decline APIs + wire notification actions
Adds acceptResidenceInvite / declineResidenceInvite to ResidenceApi
(POST /api/residences/{id}/invite/{accept|decline}) and exposes them via
APILayer. On accept success, myResidences is force-refreshed so the
newly-joined residence appears without a manual pull.

Wires NotificationActionReceiver's ACCEPT_INVITE / DECLINE_INVITE
handlers to the new APILayer calls, replacing the log-only TODOs left
behind by P4 Stream O. Notifications are now cleared only on API
success so a failed accept stays actionable.

Tests:
 - ResidenceApiInviteTest covers correct HTTP method/path + error surfacing.
 - NotificationActionReceiverTest invite cases updated to assert the new
   APILayer calls (were previously asserting the log-only path).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 13:36:59 -05:00
Trey T
10b57aabaa P6 Stream V: ImageCompression (expect/actual) + CameraPicker polish
Android: BitmapFactory + ExifInterface + JPEG quality 0.7 + 1920px downscale.
iOS: UIImage.jpegData. JVM/JS/WASM: no-op. CameraPicker uses TakePicture
ActivityResult + permission rationale.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 13:35:54 -05:00
Trey T
3069ec41de P5 Streams Q+R: TaskAnimations + AnimationTestingScreen
Port iOS TaskAnimations.swift specs (completion checkmark, card transitions,
priority pulse) + AnimationTestingView as dev screen.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 13:35:32 -05:00
Trey T
cf2aca583b P7 Stream X: ResidenceFormState + validation (iOS parity)
Pure-function field validators matching iOS ResidenceFormView rules.
Mirrors Stream W's TaskFormState pattern.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 13:34:49 -05:00
Trey T
1cbeeafa2d Integration: remove legacy WidgetTaskActionReceiver (replaced by CompleteTaskAction — P3 Stream M follow-up)
Stream M replaced the widget's task-complete path with CompleteTaskAction +
WidgetActionProcessor. Grepping confirmed the only references to
WidgetTaskActionReceiver were its own class file and the manifest entry.
Remove both.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 13:32:26 -05:00
Trey T
975f6fde73 Integration: port push-token registration to new FcmService (P4 follow-up)
Move the legacy MyFirebaseMessagingService.onNewToken() device-registration
path onto the new iOS-parity FcmService. The legacy service is already
unwired from the manifest MESSAGING_EVENT filter; this removes its last
functional responsibility. Behaviour preserved: auth-token guard,
DeviceRegistrationRequest with ANDROID_ID + Build.MODEL, log-only on error.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 13:31:52 -05:00
Trey T
1ba95db629 Integration: wire 3 new P2 screens into App.kt nav + HapticsInit bootstrap
Navigation wiring (per follow-ups flagged by Streams G/H/I):
- Add TaskTemplatesBrowserRoute (new) + App.kt composable<TaskTemplatesBrowserRoute>
- Wire composable<TaskSuggestionsRoute> (declared by Stream H but unwired)
- Wire composable<AddTaskWithResidenceRoute> (declared by Stream I but unwired)

MainActivity.onCreate now calls HapticsInit.install(applicationContext) so the
Vibrator fallback path works on non-View call-sites (flagged by Stream S).

Deferred cleanup (tracked, not done here):
- Port push-token registration from legacy MyFirebaseMessagingService.kt to
  new FcmService (Stream N TODO).
- Remove legacy WidgetTaskActionReceiver + manifest entry (Stream M flag).
- Residence invite accept/decline APILayer methods (Stream O TODO).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 13:28:06 -05:00
Trey T
65af40ed73 P4 Stream P: NotificationPreferencesScreen expansion
Per-category toggle + master toggle + system-settings shortcut matching
iOS NotificationPreferencesView depth. DataStore-backed prefs, channel
importance rewritten to NONE when category disabled.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 13:24:45 -05:00
Trey T
3700968d00 P7 Stream W: TaskFormState + validation (iOS parity)
Pure-function field validators matching iOS TaskFormStates.swift error
strings. TaskFormState container derives errors from fields, exposes
isValid and typed request builders.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 13:22:53 -05:00
Trey T
edc22c0d2b P2 Stream I: AddTaskWithResidenceScreen
Port iOS AddTaskWithResidenceView. Residence pre-selected via constructor
param, form validation, submit -> APILayer.createTask(residenceId attached).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 13:22:13 -05:00
Trey T
46db133458 P6 Stream T: finish BiometricLockScreen + BiometricManager
BiometricPrompt wrapper with 3-strike lockout + NO_HARDWARE bypass.
BiometricLockScreen with auto-prompt on mount + PIN fallback after 3 failures.
PIN wiring marked TODO for secure-storage follow-up.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 13:21:22 -05:00
Trey T
704c59e5cb P2 Stream F + Stream U fix: JoinResidenceScreen + Coil test compile fix
Stream F: Convert JoinResidenceDialog -> dedicated screen matching iOS
JoinResidenceView. Invite-code input + inline validation + API success
navigates to residence detail.

Stream U fix: coil3 3.0.4 doesn't ship ColorImage (added in 3.1.0). Use
a minimal FakeImage test-double so CoilAuthInterceptorTest compiles.

Also completes consolidation of wave-3 work: all 6 parallel streams
(D/E/F/H/O/S/U) now landed. Full unit suite green.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 13:14:55 -05:00
Trey T
917c528f67 P5 Stream S: cross-platform Haptics (expect/actual)
Common API + platform actuals (Android HapticFeedbackConstants/Vibrator,
iOS UIImpact/NotificationFeedback, JVM/JS/WASM no-op). 5 call-sites wired.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 13:12:24 -05:00
Trey T
944161f0d1 P2 Stream E: FeatureComparisonScreen (replaces FeatureComparisonDialog)
Full-screen feature comparison matching iOS FeatureComparisonView.
Two-column table, iOS-equivalent row set, CTA to upgrade flow.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 13:12:21 -05:00
Trey T
224f6643bf P6 Stream U: AuthenticatedImage composable + CoilAuthInterceptor
Token-aware image loading matching iOS AuthenticatedImage.swift.
Bearer header attachment, 401-triggered refresh+retry, placeholder on error.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 13:10:59 -05:00
Trey T
19471d780d P2 Stream H: standalone TaskSuggestionsScreen
Port iOS TaskSuggestionsView as a standalone route reachable outside
onboarding. Uses shared suggestions API + accept/skip analytics in
non-onboarding variant.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 13:10:47 -05:00
Trey T
7d71408bcc Fix: add WidgetDataRepository.isPendingCompletion predicate
Stream M's WidgetActionProcessorTest.kt references this predicate but
Stream J's initial repo only exposed mark/clear mutators. Trivial addition:
reads the pending-completion set and checks membership.

Unblocks :composeApp:testDebugUnitTest (now green across all streams).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 12:56:20 -05:00
Trey T
ee135c4673 P2 Stream G: TaskTemplatesBrowserScreen (replaces dialog/sheet)
Full browse-and-select experience matching iOS TaskTemplatesBrowserView.
Category filter, multi-select, bulk-create with templateId backlink.
Analytics events wired.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 12:56:01 -05:00
Trey T
1fcb456ef1 P3 Stream K: Glance widgets (small/medium/large) matching iOS
- HoneyDueSmallWidget (2x2), HoneyDueMediumWidget (4x2),
  HoneyDueLargeWidget (4x4) rewritten to consume the
  iOS-parity WidgetDataRepository (Stream J).
- Free-tier shows a large count-only layout (matches iOS
  FreeWidgetView); premium shows task list + complete buttons
  (Large widget also renders the Overdue / 7 Days / 30 Days
  stats row from WidgetDataRepository.computeStats()).
- WidgetFormatter mirrors iOS formatWidgetDate: "Today" /
  "in N day(s)" / "N day(s) ago".
- WidgetColors maps priority levels (1-4) to primary/yellow/
  accent/error, matching iOS OrganicTaskRowView.priorityColor.
- WidgetUi shared Glance composables (TaskRow, WidgetHeader,
  EmptyState, TaskCountBlock, StatPill, StatsRow, CompleteButton)
  wired to Stream M's CompleteTaskAction for interactive rows.
- JVM tests: WidgetFormatterTest + WidgetColorsTest covering
  10 formatter assertions and 11 color mapping assertions.

Glance caveats: no radial/linear gradients or custom shapes, so
iOS's "organic" glows are dropped in favor of cream background +
tinted TaskRow cards. Colors, typography, and priority semantics
match iOS exactly.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 12:55:08 -05:00
Trey T
dbff329384 P3 Stream L: widget refresh scheduler (WorkManager, iOS cadence)
WidgetRefreshSchedule: 30-min day / 120-min overnight (6am–11pm split).
WidgetRefreshWorker: CoroutineWorker fetches via APILayer -> repo -> widget.update.
WidgetUpdateManager: chained one-time enqueue pattern (WorkManager PeriodicWork
can't vary cadence).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 12:54:35 -05:00
Trey T
58b9371d0d P3 Stream M: CompleteTaskAction (widget interactive completion)
Glance ActionCallback wires to WidgetActionProcessor: premium marks pending +
calls API + refreshes; free tier opens paywall deep link instead. Idempotent,
rollback-safe on API failure.

Also fixes a one-line compile error in WidgetTaskActionReceiver.kt where
updateAllWidgets() had been removed by Stream L — swapped for forceRefresh()
so the build stays green. The legacy receiver is now redundant (replaced by
CompleteTaskAction) but deletion is deferred to a Stream K follow-up so the
AndroidManifest entry can be removed in the same commit.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 12:52:01 -05:00
Trey T
6b3e64661f P2 Stream D: ThemeSelectionScreen (replaces ThemePickerDialog)
Full-screen theme picker with 11 theme previews matching iOS
ThemeSelectionView. Live preview on tap. Old dialog deleted and
call-sites migrated to the new route.

Tests use the state-logic fallback pattern (plain kotlin.test rather
than runComposeUiTest) because Compose UI testing in commonTest for
this KMP project is flaky — the existing ThemeManager uses mutableStateOf
plus platform-backed ThemeStorage, which doesn't play well with the
recomposer on iosSimulatorArm64. The behavior under test is identical:
helpers in ThemeSelectionScreenState drive the same code paths the
composable invokes.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 12:50:00 -05:00
Trey T
0d50726490 P4 Stream N: FCM service + NotificationChannels matching iOS categories
FcmService + NotificationPayload + 4 NotificationChannels (task_reminder,
task_overdue, residence_invite, subscription) parity with iOS
NotificationCategories.swift. Deep-link routing from payload.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 12:45:37 -05:00
Trey T
6d7b5ee990 P3 Stream J: widget data repository (DataStore-backed)
Ports iOS WidgetDataManager.swift semantics. DTO + JSON serialization +
pending-completion tracking + stats (overdueCount / dueWithin7 / dueWithin8To30).
Same-process DataStore is sufficient for Glance widgets.

Unblocks Streams K (widgets) / L (scheduler) / M (actions).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 12:40:48 -05:00
Trey T
7aab8b0f29 P1 Stream B: port iOS brand assets to Android
- outline, tab_view, app_icon_mark, widget_icon: rasterized from iOS
  PDF/PNG sources at 1024px (gradients/shadows would flatten via SVG trace)
- honeycomb_texture: hand-authored VectorDrawable, seamless hex tiling
  verified at 4x4 render
- widget_icon: adaptive icon (mipmap-anydpi-v26) + density-specific
  mipmap + foreground bitmaps (mdpi..xxxhdpi)
- Source PDFs preserved in docs/ios-parity/source-assets/ for future
  re-rasterization

AssetInventoryTest asserts all 5 Res.drawable entries resolve.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 12:35:31 -05:00
Trey T
db181c0d6a P1 Stream C: organic design primitives (BlobShape, RadialGlow, HoneycombOverlay)
Ports iOS OrganicDesign.swift primitives to Compose Multiplatform:
- BlobShape: seeded deterministic irregular shape
- RadialGlow: radial-gradient backdrop composable
- HoneycombOverlay: tiled hex pattern modifier
- OrganicRadius constants matching iOS

Determinism guaranteed by parametrized tests.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 12:34:47 -05:00
Trey T
dcab30f862 P1 Stream A: design tokens — verify color parity with iOS + typography
11 themes x 9 colors x 2 modes (198 values) now parametrized-tested against
docs/ios-parity/colors.json as ground truth. Typography scale matches iOS
dynamic-type defaults.

118 of 198 color values were off before — mostly off-by-one RGB rounding
errors introduced during a prior hand-copy from iOS. Default TextSecondary
(light+dark) also lost its 0x99 alpha channel — now restored via
Color(0xAARRGGBB) packed literals. Added SansSerif fontFamily and source
citations on every Typography size so the iOS dynamic-type mapping is
explicit.

Tests: ThemeColorsTest (4), TypographyTest (5), SpacingTest (1) — all
green. `everyColorMatchesIosGroundTruth` walks the embedded JSON and
asserts 198 hex values match exactly.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 12:32:52 -05:00