Skip to content

Conversation

@hyochan
Copy link
Owner

@hyochan hyochan commented Feb 11, 2026

Summary

  • Fix ProductSubscriptionIOS.subscriptionOffers always being null
  • Add parsing logic for iOS subscriptionOffers from native data

Changes

  • Add _parseSubscriptionOffersIOS helper function in helpers.dart
  • Parse subscriptionOffers field when creating ProductSubscriptionIOS
  • Add unit test for subscriptionOffers parsing

Related

Test plan

  • dart format --set-exit-if-changed . passes
  • flutter analyze passes
  • flutter test passes (208 tests)

Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • iOS subscription products now surface subscription offers (Introductory and Promotional) including payment mode, price, period, period count, and localized price.
  • Bug Fixes

    • Fixed iOS parsing so subscription offers are correctly detected and returned when present.
  • Tests

    • Added unit tests validating parsing and exposure of iOS subscription offers and their fields.
  • Documentation

    • Added release notes describing the iOS subscription offers fix and example usage.

- Add _parseSubscriptionOffersIOS helper function
- Parse subscriptionOffers from native iOS data in ProductSubscriptionIOS
- Add unit test for subscriptionOffers parsing

Fixes #616

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 11, 2026

📝 Walkthrough

Walkthrough

Added numeric-coercion helpers and a new private _parseSubscriptionOffersIOS() to parse iOS subscriptionOffers into gentype.SubscriptionOffer objects; wired this into parseProductFromNative() for iOS subscription products. Also added unit tests and a release note documenting the fix.

Changes

Cohort / File(s) Summary
iOS Subscription Offers Parsing
lib/helpers.dart
Added _toDouble and _toInt helpers and _parseSubscriptionOffersIOS() to validate/normalize input, coerce numeric/string fields, map paymentMode and offer type fallbacks, parse period/unit/count, construct gentype.SubscriptionOffer objects, and integrated into parseProductFromNative() for iOS subscription products.
Unit Tests
test/helpers_unit_test.dart
Added test verifying parseProductFromNative() parses nested iOS subscriptionOffers into multiple SubscriptionOffer entries and asserts id, type, paymentMode, price coercion, period unit/value, numberOfPeriodsIOS, and localizedPriceIOS.
Docs / Release Notes
docs/blog/2026-02-12-8.2.7-subscription-offers-fix.md
Added release note describing the bugfix for iOS subscriptionOffers being null, usage examples, and related issue reference.

Sequence Diagram(s)

(omitted)

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Poem

🐰 A nibble of JSON in the night,
I hop through maps to set things right,
Prices rounded, offers found,
Intro, promo—parsed and sound,
🥕 — The Code Rabbit

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: adding parsing logic for iOS subscriptionOffers, which directly addresses the linked issue #616.
Linked Issues check ✅ Passed The PR implements the required fix for issue #616 by adding _parseSubscriptionOffersIOS helper and populating subscriptionOffers in ProductSubscriptionIOS instantiation within parseProductFromNative.
Out of Scope Changes check ✅ Passed All changes (parsing logic, unit tests, and documentation) are directly related to the subscriptionOffers parsing objective with no extraneous modifications.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/subscription-offers-ios

No actionable comments were generated in the recent review. 🎉

🧹 Recent nitpick comments
lib/helpers.dart (1)

469-481: LGTM — safe numeric parsing helpers.

Clean implementation that correctly handles both num and String inputs from platform channels.

Note: the local parsePrice closure on line 68 is functionally identical to _toDouble. Consider replacing it with a call to _toDouble to reduce duplication.

,


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@codecov
Copy link

codecov bot commented Feb 11, 2026

Codecov Report

❌ Patch coverage is 83.33333% with 7 lines in your changes missing coverage. Please review.
✅ Project coverage is 68.11%. Comparing base (ac6aff4) to head (b89ead2).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
lib/helpers.dart 83.33% 7 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #617      +/-   ##
==========================================
+ Coverage   67.68%   68.11%   +0.43%     
==========================================
  Files           7        7              
  Lines        1479     1521      +42     
==========================================
+ Hits         1001     1036      +35     
- Misses        478      485       +7     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @hyochan, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request addresses a critical bug where iOS subscription offers were not being correctly parsed and exposed in "ProductSubscriptionIOS" objects. By introducing a new helper function and integrating it into the product parsing flow, it ensures that all relevant details of introductory and promotional offers, including their payment modes, types, and periods, are now accurately extracted from native iOS data. This enhancement provides a more complete and reliable representation of subscription products for iOS.

Highlights

  • iOS Subscription Offers Parsing: Implemented new parsing logic to correctly extract "subscriptionOffers" from native iOS data, resolving an issue where this field was always null in "ProductSubscriptionIOS".
  • Robust Payment Mode and Offer Type Handling: Enhanced the parsing to include fallback mechanisms for various raw string formats of "paymentMode" and "type" fields, improving reliability and ensuring accurate representation of offer details.
  • Unit Test Coverage: Added a dedicated unit test to ensure the accurate parsing and exposure of iOS subscription offers, including their detailed properties like period, type, and payment mode.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Changelog
  • lib/helpers.dart
    • Integrated "_parseSubscriptionOffersIOS" into "parseProductFromNative" to populate the "subscriptionOffers" field for "ProductSubscriptionIOS".
    • Added "_parseSubscriptionOffersIOS" function to handle the parsing of a list of dynamic JSON objects into "SubscriptionOffer" objects, including robust parsing for "paymentMode", "type", and "period" fields with fallback logic for different string formats.
  • test/helpers_unit_test.dart
    • Added a new unit test case to verify that "parseProductFromNative" correctly parses "subscriptionOffers" for iOS subscription products, asserting the properties of introductory and promotional offers.
Activity
  • The pull request was generated with "Claude Code".
  • Release notes were auto-generated by "coderabbit.ai".
  • The author has confirmed that "dart format", "flutter analyze", and "flutter test" all pass.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request correctly implements the parsing of subscriptionOffers for iOS subscription products, which was previously missing. A new helper function, _parseSubscriptionOffersIOS, is introduced to handle this, and it's accompanied by a solid unit test. The parsing logic is robust, with good error handling for different data formats. I've suggested a couple of minor refactorings in the new helper to remove redundant logic in the fallback switch statements, which will improve code clarity and maintainability. Overall, this is a great fix.

hyochan and others added 2 commits February 12, 2026 00:18
Remove cases already handled by fromJson normalization.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@lib/helpers.dart`:
- Around line 713-728: The SubscriptionOffer builder uses direct `as num?` casts
for price, periodCount, timestampIOS, and numberOfPeriodsIOS which will throw if
the platform channel returns numeric values as strings; replace those casts by
calling the existing parse helper(s) (e.g., reuse parsePrice for double-valued
fields such as `price` and `timestampIOS`, and add/use a safe parseInt-like
helper for `periodCount` and `numberOfPeriodsIOS`) when constructing
gentype.SubscriptionOffer so both String and num inputs are handled; if those
helpers are local, hoist them to file-level private functions so they can be
reused in the SubscriptionOffer construction.
🧹 Nitpick comments (1)
lib/helpers.dart (1)

694-711: Nit: rename local value to periodValue for clarity.

value on Line 699 is a very generic name in a function that also processes other map[…] entries. A more descriptive name reduces cognitive load.

♻️ Suggested rename
-      final value = (periodMap['value'] as num?)?.toInt() ?? 1;
+      final periodValue = (periodMap['value'] as num?)?.toInt() ?? 1;
       gentype.SubscriptionPeriodUnit? unit;
       if (unitRaw != null) {
         try {
           unit = gentype.SubscriptionPeriodUnit.fromJson(unitRaw);
         } catch (_) {
           // ignore
         }
       }
       if (unit != null) {
-        period = gentype.SubscriptionPeriod(unit: unit, value: value);
+        period = gentype.SubscriptionPeriod(unit: unit, value: periodValue);
       }

Replace direct `as num?` casts with _toDouble/_toInt helpers
to handle both num and String inputs from platform channels.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@lib/helpers.dart`:
- Line 713: The cast on periodMap['value'] is unsafe for String inputs; replace
the explicit "(periodMap['value'] as num?)?.toInt() ?? 1" with a call to the
existing _toInt helper (e.g. "final value = _toInt(periodMap['value']) ?? 1") so
it handles numeric and string cases consistently with how
periodCount/numberOfPeriodsIOS are parsed.
🧹 Nitpick comments (1)
lib/helpers.dart (1)

687-706: WIN_BACK is silently mapped to Promotional — consider documenting or logging this lossy mapping.

iOS StoreKit 2 distinguishes win-back offers from promotional offers. Mapping WIN_BACK/WINBACK to Promotional loses that distinction. If the DiscountOfferType enum doesn't have a WinBack variant today, this is the best you can do, but a brief comment explaining why would help future maintainers.

Replace direct cast with _toInt helper for consistency.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@hyochan hyochan merged commit e4905a2 into main Feb 11, 2026
6 checks passed
@hyochan hyochan deleted the fix/subscription-offers-ios branch February 11, 2026 16:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ProductSubscriptionIOS.subscriptionOffers is always null

1 participant