A user whose payment Play is still processing now gets an explanation
instead of a screen that keeps selling them the upgrade they already
bought.
- New PendingPurchaseCard, rendered above the ownership/acquisition split
so it reaches every audience: the acquisition buyer, the owner switching
products, and the grace user (whose offers box is hidden entirely during
a young episode) — all three have their purchase actions locked and need
the same explanation.
- Loaded.hasPendingPurchase is SKU-agnostic: the subscription and the
one-time purchase are alternatives, so a pending payment for either one
disables both offers and the ownership switch button. Restore stays
enabled — re-checking with Play is the useful action here.
- Both purchase paths now run the same pre-purchase gate
(verifyPurchaseStateNow, bounded): a pending payment answers with the
informational PurchasePending dialog instead of launching a flow Play
would reject. The subscription path previously launched unverified, and
its gate also blocks on an owned upgrade (RestoreSucceeded) and on a
still-renewing subscription (SubscriptionStillRenewing), so a stale
screen can't sell Pro to someone who already owns it.
- restorePurchase() reports a found-but-unpaid purchase as PurchasePending
rather than RestoreFailed, whose copy asserts a completed check and
steers toward multi-account troubleshooting and support.
- A PendingPurchaseBillingException from a launch maps to the same dialog.
- SubscriptionCheckFailed becomes PurchaseCheckFailed (both paths use it
now); its string is replaced by
upgrade_screen_purchase_check_failed_message and the translated entries
of the old key are removed, along with the already-orphaned
upgrade_screen_sub_check_failed_title, so ExtraTranslation lint stays
quiet.