Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Migrates Flutter to null safety #155

Merged
merged 4 commits into from
Mar 3, 2021
Merged

Migrates Flutter to null safety #155

merged 4 commits into from
Mar 3, 2021

Conversation

vegaro
Copy link
Contributor

@vegaro vegaro commented Feb 23, 2021

I followed the steps in https://dart.dev/null-safety/migration-guide#step3-analyze and this PR is the result of the automatic migration.

We can publish this as version 3.0.0 of the SDK and it will show as a preview until dart 2.12.0 is out of beta.

Depends on #154

@vegaro vegaro linked an issue Feb 23, 2021 that may be closed by this pull request
@vegaro vegaro requested a review from aboedo February 23, 2021 01:15
@aboedo aboedo changed the base branch from develop to removes_all_analyze_warnings February 23, 2021 14:17
@aboedo aboedo changed the base branch from removes_all_analyze_warnings to develop February 23, 2021 14:17
@aboedo
Copy link
Member

aboedo commented Feb 23, 2021

it looks like the lint error will go away once this gets rebased from #154, so we should be good

Copy link
Member

@aboedo aboedo left a comment

Choose a reason for hiding this comment

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

looking great! left a couple of questions

@@ -38,13 +38,13 @@ class EntitlementInfo {
/// The date an unsubscribe was detected. Can be `null`.
/// @note: Entitlement may still be active even if user has unsubscribed.
/// Check the `isActive` property.
final String unsubscribeDetectedAt;
final String? unsubscribeDetectedAt;

/// The date a billing issue was detected. Can be `nil` if there is no
Copy link
Member

Choose a reason for hiding this comment

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

we should probably update the end of this line to "can be null if there is no"

var periodType;
switch (json["periodType"] as String) {
late var periodType;
switch (json["periodType"] as String?) {
Copy link
Member

Choose a reason for hiding this comment

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

what does this switch do if periodType is null? do we need to add a case to handle it?

Copy link

@IchordeDionysos IchordeDionysos Feb 23, 2021

Choose a reason for hiding this comment

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

If periodType is null then no case will match and periodType will still NOT be initialized.

And when it‘s then passed to EntitlementInfo() constructor as it‘s expected to be non-null it will crash.

There are three options:

  • Leave it as it is and let it crash.
  • Add a case null: ... to handle the null case.
  • Make periodType nullable String? and be explicit that it may be null and handle it apprioriately.

I personally would prefer the last as it‘s the most transparent. So doing this:

String? periodType;

And then later:

EntitlementInfo(
  ...,
  periodType!,
  ...
  // Maybe this for the store (?!)
  store ?? Store.unknownStore,
);

I think you are better suited to judge what consequences would be acceptable.
Completely, preventing any errors while parsing is probably never possible.

var store;
switch (json["store"] as String) {
late var store;
switch (json["store"] as String?) {
Copy link
Member

Choose a reason for hiding this comment

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

same question regarding switching on null

@@ -175,13 +175,13 @@ class Purchases {
/// [upgradeInfo] Android only. Optional UpgradeInfo you wish to upgrade from
/// containing the oldSKU and the optional prorationMode.
static Future<PurchaserInfo> purchasePackage(Package packageToPurchase,
{UpgradeInfo upgradeInfo}) async {
{UpgradeInfo? upgradeInfo}) async {
var response = await _channel.invokeMethod('purchasePackage', {
'packageIdentifier': packageToPurchase.identifier,
'offeringIdentifier': packageToPurchase.offeringIdentifier,
'oldSKU': upgradeInfo != null ? upgradeInfo.oldSKU : null,
'prorationMode': upgradeInfo != null && upgradeInfo.prorationMode != null
Copy link
Member

Choose a reason for hiding this comment

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

do we need to be doing upgradeInfo!.prorationMode here?

Choose a reason for hiding this comment

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

It's not needed here as upgradeInfo is a function parameter and thus the analyzer can statically make sure that it's never null.

Unwrapping would cause a compilation error.

Choose a reason for hiding this comment

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

More information about this one:
dart-lang/sdk#42626

Copy link
Member

Choose a reason for hiding this comment

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

that makes sense 👍

var response = await _channel.invokeMethod('purchasePackage', {
'packageIdentifier': packageToPurchase.identifier,
'offeringIdentifier': packageToPurchase.offeringIdentifier,
'oldSKU': upgradeInfo != null ? upgradeInfo.oldSKU : null,
'prorationMode': upgradeInfo != null && upgradeInfo.prorationMode != null
? upgradeInfo.prorationMode.index
? upgradeInfo.prorationMode!.index
Copy link
Member

Choose a reason for hiding this comment

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

same question here, does this need to also be unwrapping upgradeInfo?

Copy link

@IchordeDionysos IchordeDionysos Feb 23, 2021

Choose a reason for hiding this comment

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

Here we do need unwrapping as prorationMode could be implemented like this:

String? get prorationMode {
  if (random() < 0.5) return null;
  return 'RevenueCat';
}

And the analyzer can't be sure that every time upgradeInfo.prorationMode is called that the value is always null.

What I would suggest to do instead is this:

final prorationMode = upgradeInfo?.prorationMode;

prorationMode != null ? prorationMode.index : null

With that we don't need to unwrap prorationMode as the analyzer knows that it can never be null.

As the analyzer can be sure that the local variable is never re-assigned to a null value after checking that it is not-null.

Copy link
Member

Choose a reason for hiding this comment

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

agreed. @vegaro we should do the updates here, even if we're safe for now since we know the current implementation of upgradeInfo won't change values for prorationMode in between calls

@vegaro
Copy link
Contributor Author

vegaro commented Feb 27, 2021

Added a couple tests for the store and purchaseType null when creating entitlement info, and fixed some casts that were changed by the migration tool, but that we actually don't need.

@vegaro vegaro requested a review from aboedo February 27, 2021 01:58
Copy link
Member

@aboedo aboedo left a comment

Choose a reason for hiding this comment

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

@vegaro looks great! good to go once we improve safety on the changed calls to proprationMode. Thanks so much @IchordeDionysos for the detailed responses to my questions!!!

@@ -175,13 +175,13 @@ class Purchases {
/// [upgradeInfo] Android only. Optional UpgradeInfo you wish to upgrade from
/// containing the oldSKU and the optional prorationMode.
static Future<PurchaserInfo> purchasePackage(Package packageToPurchase,
{UpgradeInfo upgradeInfo}) async {
{UpgradeInfo? upgradeInfo}) async {
var response = await _channel.invokeMethod('purchasePackage', {
'packageIdentifier': packageToPurchase.identifier,
'offeringIdentifier': packageToPurchase.offeringIdentifier,
'oldSKU': upgradeInfo != null ? upgradeInfo.oldSKU : null,
'prorationMode': upgradeInfo != null && upgradeInfo.prorationMode != null
Copy link
Member

Choose a reason for hiding this comment

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

that makes sense 👍

var response = await _channel.invokeMethod('purchasePackage', {
'packageIdentifier': packageToPurchase.identifier,
'offeringIdentifier': packageToPurchase.offeringIdentifier,
'oldSKU': upgradeInfo != null ? upgradeInfo.oldSKU : null,
'prorationMode': upgradeInfo != null && upgradeInfo.prorationMode != null
? upgradeInfo.prorationMode.index
? upgradeInfo.prorationMode!.index
Copy link
Member

Choose a reason for hiding this comment

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

agreed. @vegaro we should do the updates here, even if we're safe for now since we know the current implementation of upgradeInfo won't change values for prorationMode in between calls

@vegaro
Copy link
Contributor Author

vegaro commented Mar 2, 2021

Sorry I missed that one @aboedo, I actually simplified oldSKU too.

@vegaro vegaro changed the base branch from develop to 3.x.x-release March 3, 2021 01:26
@vegaro
Copy link
Contributor Author

vegaro commented Mar 3, 2021

Changed the base. This is meant to be a pre release until the final Dart version is released.

@vegaro vegaro merged commit e8a18f1 into 3.x.x-release Mar 3, 2021
@vegaro vegaro deleted the null_safety branch March 3, 2021 01:31
@IchordeDionysos
Copy link

@vegaro the new Dart version with null-safety was just released 😍
https://medium.com/dartlang/announcing-dart-2-12-499a6e689c87

So we can probably now release this 💪

@vegaro
Copy link
Contributor Author

vegaro commented Mar 3, 2021

I saw that! I am actually working on the new release now :)

vegaro added a commit that referenced this pull request Mar 3, 2021
* migration ran

* changes stable to beta

* fixes tests and compilation

* updates prorationMode and oldSKU
vegaro added a commit that referenced this pull request Mar 3, 2021
* migration ran

* changes stable to beta

* fixes tests and compilation

* updates prorationMode and oldSKU
vegaro added a commit that referenced this pull request Mar 3, 2021
* Migrates Flutter to null safety (#155)

* migration ran

* changes stable to beta

* fixes tests and compilation

* updates prorationMode and oldSKU

* prepares for version 3.0.0 (#159)
@vegaro
Copy link
Contributor Author

vegaro commented Mar 3, 2021

@IchordeDionysos Just released 3.0.0

@IchordeDionysos
Copy link

Very cool 😍 Thanks for keeping the RevenueCat Flutter SDK always so up-to-date 💪

@vegaro
Copy link
Contributor Author

vegaro commented Mar 4, 2021

Let us know if you face any issue or have any suggestion. And thanks so much for reviewing this. We really appreciate it

Jethro87 pushed a commit to Jethro87/purchases-flutter that referenced this pull request Jan 4, 2025
* Migrates Flutter to null safety (RevenueCat#155)

* migration ran

* changes stable to beta

* fixes tests and compilation

* updates prorationMode and oldSKU

* prepares for version 3.0.0 (RevenueCat#159)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add null safety support for upcoming Flutter version
3 participants