Skip to content

[design-qa][P2] Buttons, fields, counters and selection controls exist as duplicated private copies #174

Description

@cestercian

Part of the Sep-2026 designer's-eye QA of the 138 "Artistant iOS Light" screens (theme T12b, category consistency; epic #161). Full report with evidence and per-screen coverage: docs/DESIGN_QA_2026-09.md; the per-section appendices under docs/design-qa/ carry the code excerpts.

Why it matters. Two private DestructiveButtons each documented as the only one, two ReasonRows, a pre-redesign field and chip still shipping in the press-kit panes, hand-rolled BasicTextFields that lose the focus state, and a secondary button whose height and label step disagree with the token sheet.

Fix direction. Promote the one good copy of each into designsystem/component/ and delete the rest.

Findings (22: P2 ×12, P3 ×10)

  • F-CC-03 (P3) — The token sheet and the secondary button disagree about its height
    • Screens: 57, 07, 94, 118, 25 and every EmptyState with two actions
    • Where: designsystem/component/PrimaryButton.kt:86 vs :142 (KDoc at :111-119); docs/REDESIGN_2026-09.md §2 Geometry. (The design-system auditor adds: PrimaryButton sets type.cta 16.5/700 while SecondaryButton sets type.rowTitle 14.5/600 — the label step differs too.)
    • Fix: Measure screen 57 in the export once and make §2 and the KDoc say the same number; one label step for both buttons.
  • F-GS-06 (P2) — LegalSegments duplicates the design-system SegmentedControl
    • Screens: 31, 114
    • Where: feature/signup/LegalScreen.kt:198-242; peer designsystem/component/SegmentedControl.kt:48-88
    • Fix: SegmentedControl(options = LegalDoc.entries, selected = selected, onSelect = …, label = { it.tab }) and delete LegalSegments.
  • F-GS-12 (P2) — The secondary action under the CTA is styled two ways on 118 and 13
    • Screens: 118, 13
    • Where: feature/signup/WelcomeScreen.kt:101-112; feature/signup/NotifPermissionScreen.kt:178-192
    • Fix: One TextAction (or SecondaryButton) used at both sites, rowMin-tall, accentInk.
  • F-GS-15 (P3) — Two controls for one action on 28 and 31/114; 28's footer tells the user to go back but offers no way
    • Screens: 28, 31, 114
    • Where: feature/signup/EmailSignUpScreen.kt:116-127, :139-145; feature/signup/LegalScreen.kt:134-141, :145-170
    • Fix: Drop the trailing "Cancel" and make the footer line an InlineLink("Back to Apple and Google", onCancel); on Legal keep the footer row and drop the header circle.
  • F-GS-25 (P3) — SignupScaffold's footer re-implements BottomActionBar
    • Screens: 27, 11, 119, 28, 29, 30, 31
    • Where: feature/signup/SignupChrome.kt:105-122; peer designsystem/component/BottomActionBar.kt:35-53
    • Fix: Have the footer slot render BottomActionBar(modifier = Modifier.imePadding()) { footer() } and let one component own the tailroom.
  • F-BC-21 (P3) — The counter amount well ignores the section's field recipe
    • Screens: 61
    • Where: feature/booking/CounterOfferScreen.kt:405-412 vs designsystem/component/AppTextField.kt:89-98 and RequestQuoteScreen.kt:323-325 (PickerField); KDoc :396 says 22sp, displaySmall is 19 (Type.kt:257-258)
    • Fix: surface2 fill, hairline rim, ink rim only while focused (track interactionSource), and correct the KDoc to 19sp.
  • F-BN-10 (P2) — Two private DestructiveButtons, each documented as the only one
    • Screens: 52, plus Delete account
    • Where: feature/booking/BookingDetailScreen.kt:1190-1213 vs feature/profile/DeleteAccountScreen.kt:576-605
    • Fix: promote one into designsystem/component/ with enabled, and use it in both places.
  • F-BN-11 (P2) — On screen 18 "Cancel" is the third of three identical grey buttons
    • Screens: 18
    • Where: feature/booking/BookingDetailScreen.kt:675-690, :1402-1417 (FlatAction)
    • Fix: pull it out of the row into its own full-width row with danger label text, and say "Cancel booking" to both sides.
  • F-MS-10 (P2) — ReasonRow is implemented twice, with different ring weights
    • Screens: 73
    • Where: feature/messages/ReportConversationSheet.kt:170-231 (esp. :203, :218); peer feature/artist/ArtistProfileSheets.kt:296-335 (esp. :322, :324)
    • Fix: promote one RadioRow to designsystem/component/, use it from both sheets, and make the selected mark ink-on-surface2 so the CTA keeps the accent.
  • F-WZ-05 (P2) — "Selected" is drawn three different ways inside one wizard
    • Screens: 37/38/43 (chips), 39 (tech), 40 (days)
    • Where: WizardFormSteps.kt:521-556 (CheckRow), :612-643 (DayStrip), :729-772 (WizardChipSection → designsystem/component/Chip.kt:54-62)
    • Fix: use ink2 for the unselected day letter and either give the tech presets the chip's accent fill or give the day strip the brandSoft+stroke treatment — two languages at most (grid-of-answers vs list-of-demands), not three.
  • F-WZ-12 (P3) — Two hand-rolled BasicTextFields lose the app's focus state
    • Screens: 43, 44
    • Where: WizardMediaSteps.kt:513-545 (bio), :652-661 (sample title); peer designsystem/component/AppTextField.kt:95-135
    • Fix: add minLines to AppTextField and use it for the bio; give the sample title the same field chrome (or an explicit edit affordance).
  • F-WZ-14 (P3) — Preview rows and progress tracks are one-offs where shared components exist
    • Screens: 45, 72, 44
    • Where: WizardPublishSteps.kt:186-215; WizardScaffold.kt:110-141; WizardMediaSteps.kt:789-810
    • Fix: build the preview rows from ListRow with a trailing Edit action, set the value line at subtitle, and give both progress tracks one token pair.
  • F-PK-05 (P2) — The panes still ship the pre-redesign field and chip
    • Screens: 23 (panes) vs 67, 68, 74
    • Where: feature/epk/EpkComponents.kt:108-186 (EpkField, 5 call sites in EpkPanes.kt), :196-239 (EpkChip, 5 call sites); peers EpkSheets.kt uses AppTextField ×4 and Chip ×2
    • Fix: swap the five EpkChip sites to Chip and the five EpkField sites to AppTextField, then delete EpkComponents.kt.
  • F-PK-12 (P3) — Two destructive styles inside one feature
    • Screens: 74 vs 23 (panes)
    • Where: feature/epk/EpkSheets.kt:679-701; feature/epk/EpkPanes.kt:410,511,715
    • Fix: pick one — the icon + danger label row — and use it for all four; colors.danger in both places.
  • F-AS-13 (P2) — Screen 106: the dock is hand-rolled and the reason Save vanished is at the bottom of a scroll
    • Screens: 106, 22
    • Where: ManageAvailabilityScreen.kt:298-312; error text at :285-288; copy at feature/availability/ManageAvailabilityViewModel.kt:141; peer dock at GigRequestDetailScreen.kt:231
    • Fix: .dockSurface().padding(gutter), keep "Save changes" present-but-disabled, and put the reason in a Banner(Failure, actionLabel = "Retry") immediately above the dock.
  • F-AC-06 (P2) — Two private copies of DestructiveButton, each documented as the only one
    • Screens: 48 (and BC's cancel stage)
    • Where: feature/profile/DeleteAccountScreen.kt:575-607; feature/booking/BookingDetailScreen.kt:1190-1213
    • Fix: promote one DestructiveButton (with the enabled state) into designsystem/component/, delete both copies, and pick one reason-row component for both flows.
  • F-AC-07 (P2) — The calendar picker is a hand-rolled single-select with a sub-44dp target
    • Screens: 47
    • Where: feature/profile/AccountScreen.kt:412-439
    • Fix: replace with CheckRow(state = if (selected) MarkState.Done else MarkState.Pending, onClick = …).
  • F-AC-19 (P3) — Profile hand-rolls the feedback line the section already exports
    • Screens: 26
    • Where: feature/profile/ProfileScreen.kt:217-229; component at feature/profile/AccountChrome.kt:211-228
    • Fix: AccountFeedbackLine(message, colors.danger, onDismissMessage, "profile.actionError").
  • F-SH-24 (P3) — The section's secondary action comes in three shapes
    • Screens: 121, 138, 63
    • Where: feature/system/RatePromptSheet.kt:171-177; feature/system/ServiceOutageScreen.kt:182-193; feature/system/HelpCentreScreen.kt:181-193
    • Fix: one SecondaryButton (54dp, surface2) for all three, and give the help card's pill defaultMinSize(minHeight = size.controlMin).
  • F-DSYS-13 (P2) — One shared Meter, used by one feature; four other bar geometries hand-rolled
    • Screens: —
    • Where: designsystem/component/Meter.kt:82-97; theme/Dimens.kt:505 (meterHeight 3), :563 (pressKit.meter 6), :565 (uploadMeter 5); consumers at feature/artisthome/ArtistHomeScreen.kt:668, feature/wizard/WizardMediaSteps.kt:799
    • Fix: give Meter a thickness parameter defaulted to one token (component.meter), route the five inline bars through it, and delete the three redundant Dimens entries.
  • F-DSYS-19 (P3) — OtpField draws a 1.5dp stroke at rest; every other input draws 1dp
    • Screens: —
    • Where: designsystem/component/OtpField.kt:137; designsystem/component/AppTextField.kt:117-125
    • Fix: mirror AppTextField — if (active || isError) focusStroke else size.hairline.
  • F-DSYS-12 (P2) — SampleRow is the one off-token component: raw 36/18dp and alpha-mixed greys
    • Screens: —
    • Where: designsystem/component/SampleRow.kt:184, :187, :201, :222, :228
    • Fix: add a component.playDisc (36) / reuse size.iconLg-family token for the glyph, and swap the two alpha mixes for surface2 / hairline and the aliases for accent / page.

Acceptance

  • Every finding above is closed on the cited lines (or refuted in a comment with the reason).
  • ./gradlew :app:assembleDebug, :app:testDebugUnitTest and :app:lintDevDebug green.
  • The screens listed above walked on the artistant AVD with the debug harness (RELEASE.md §10) and the fix confirmed visually — this audit was code-grounded, not device-walked.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions