-
Notifications
You must be signed in to change notification settings - Fork 179
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
Conversation
it looks like the lint error will go away once this gets rebased from #154, so we should be good |
There was a problem hiding this 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
lib/entitlement_info_wrapper.dart
Outdated
@@ -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 |
There was a problem hiding this comment.
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?) { |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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
nullableString?
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?) { |
There was a problem hiding this comment.
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
lib/purchases_flutter.dart
Outdated
@@ -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 |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
that makes sense 👍
lib/purchases_flutter.dart
Outdated
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 |
There was a problem hiding this comment.
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
?
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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
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. |
There was a problem hiding this 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!!!
lib/purchases_flutter.dart
Outdated
@@ -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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
that makes sense 👍
lib/purchases_flutter.dart
Outdated
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 |
There was a problem hiding this comment.
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
Sorry I missed that one @aboedo, I actually simplified oldSKU too. |
Changed the base. This is meant to be a pre release until the final Dart version is released. |
@vegaro the new Dart version with null-safety was just released 😍 So we can probably now release this 💪 |
I saw that! I am actually working on the new release now :) |
* migration ran * changes stable to beta * fixes tests and compilation * updates prorationMode and oldSKU
* migration ran * changes stable to beta * fixes tests and compilation * updates prorationMode and oldSKU
@IchordeDionysos Just released 3.0.0 |
Very cool 😍 Thanks for keeping the RevenueCat Flutter SDK always so up-to-date 💪 |
Let us know if you face any issue or have any suggestion. And thanks so much for reviewing this. We really appreciate it |
* 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)
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