[PM-39348] feat: Redesign Premium upgrade screen with benefit-led messaging#2884
[PM-39348] feat: Redesign Premium upgrade screen with benefit-led messaging#2884KatherineInCode wants to merge 15 commits into
Conversation
…saging Replace the generic "unlock advanced features" copy with a hero illustration, a benefit-oriented headline, and an expanded 8-item benefit list, matching the Android implementation and Figma design. Extends the shared IllustratedMessageView component (aspect-ratio-aware image sizing, optional message text, and baked-in accessibilityHidden on the illustration) rather than working around it, since none of its existing ~17 call sites hide their decorative image from VoiceOver today. Adds a new sibling PremiumUpgradeBenefitsList component instead of modifying the existing PremiumFeaturesList, since that component is also used by PremiumPlanView's unrelated canceled/expired-plan reminder.
Compose the price/cadence/cancel-anytime text from the existing generic XAmountPerCadence and a new XCancelAnytime string instead of concatenating separately-localized fragments with hardcoded spacing, so word order and spacing are translator-controlled. Left-align benefit rows that wrap to multiple lines (previously inherited center alignment from IllustratedMessageView). Remove the redundant corner clip on the card background and add bottom padding to match Figma.
The CTA button already reads "Upgrade to Premium"; repeating it in the nav title was redundant. Update both the push path's title (BillingCoordinator) and the modal path's title (PremiumUpgradeView's own navigationBar modifier), since they're set independently.
…ageView Stop reusing IllustratedMessageView for the hero card: its landscape side-by-side layout didn't read well here, and building it locally keeps this screen free to control alignment without touching a component shared by 19 other screens. The card is now a plain vertical stack in both orientations. Remove the now-unused .premiumHero style and its supporting constants from IllustratedMessageView; keep its other changes (aspect-ratio-aware image sizing, optional message, baked-in accessibilityHidden), since those still benefit its other call sites independent of this screen.
It's purely decorative, same treatment as the hero illustration.
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #2884 +/- ##
==========================================
- Coverage 81.25% 79.00% -2.26%
==========================================
Files 1028 1152 +124
Lines 66164 73521 +7357
==========================================
+ Hits 53761 58084 +4323
- Misses 12403 15437 +3034 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
Per design: VoiceOver should read "per month"/"per year" rather than the raw "/" character, and a comma instead of "·" before "Cancel anytime". Applies to both the Premium upgrade screen's price line and PremiumPlanView's billing amount row, since both use the same XAmountPerCadence pattern and had the identical gap. Adds PerMonthAccessibilityLabel/PerYearAccessibilityLabel and a PlanCadenceType.accessibilityLabel counterpart to the existing label property, plus XCancelAnytimeAccessibilityLabel for the upgrade screen's "Cancel anytime" suffix. billingRow gains an optional valueAccessibilityLabel parameter, defaulting to the existing behavior for its other three callers.
Localization keys are translator-facing, so name them for what they're for (VoiceOver) rather than the SwiftUI API that consumes them. The Swift-side property/parameter names (accessibilityLabel, priceCancelAnytimeAccessibilityLabel, valueAccessibilityLabel) stay as-is, since those are programmer-facing and match the .accessibilityLabel() API they call.
One line each, describing placement or translation constraints where they exist. Checked against the clients repo and existing iOS strings before adding any constraint claims: dropped notes on "2FA" and "24/7" since neither has real precedent either way and both are self-evident enough not to need one; kept the "Send" note since that feature name reliably goes uncommented elsewhere only in contexts where it's a more obvious proper noun (e.g. "About Send") than it is here.
PremiumPlanState.totalLabel uses the same XAmountPerCadence pattern as billingAmount, so it had the identical "/" pronunciation gap. Adds totalLabelAccessibilityLabel following the same pattern.
… tests Rolled back the aspect-ratio sizing and optional message parameter since the Premium upgrade screen no longer uses this component, keeping only the accessibilityHidden(true) fix on the illustration image. Also added coverage for the image, title, and message rendering.
…utoFill/AppExtension views
🤖 Bitwarden Claude Code ReviewOverall Assessment: APPROVE Reviewed the Premium upgrade screen redesign ( Code Review DetailsNo blocking findings. Notes verified during review:
|
🎟️ Tracking
PM-39348
📔 Objective
Redesigns the Premium upgrade screen with benefit-led messaging, matching the Figma design and the Android implementation (PM-39349): a hero illustration, a benefit-oriented headline ("Unlock advanced protection"), an expanded 8-item benefit checklist, and updated CTA/price copy. This is a content-only redesign — no changes to presentation, navigation, or the underlying upgrade flow.
Also fixes a VoiceOver gap on this screen and in
PremiumPlanView: price/cadence text like "$1.65 / month" was being read literally (e.g. "dollar sign 1.65 slash month") instead of naturally. Adds VoiceOver-specific localization strings for these cases, separate from the displayed text.📸 Screenshots