-
Notifications
You must be signed in to change notification settings - Fork 5
Rate Reminder implementation #64
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
base: develop
Are you sure you want to change the base?
Conversation
pritam-bs
commented
May 13, 2024
- Both default and custom configuration strategies
- Documentation for Rate Reminder usage
- Example for Rate Reminder
- Some clean-up in Message and Version-Control
- Fix the template for enabling the test mode
- Both default and custom configuration strategies - Documentation for Rate Reminder usage - Example for Rate Reminder - Some clean-up in Message and Version-Control - Fix the template for enabling the test mode
final rateReminderResponse = await http.get( | ||
Uri.parse( | ||
'$_baseUrl/notify/rate_reminder_v2?guid=${appInfoData.guid}', | ||
), | ||
headers: mutableHeaders, | ||
); |
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.
I remember @BucekJiri said that we don't have to fetch anything from the API except for app open, @pritam-bs can't we get the info here from app open response since we already fetched this information?
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.
Open app API does not provide the rate reminder information.
https://nstack-io.github.io/docs/docs/features/rate-reminder.html?sidebarScroll=0
|
||
final result = json.decode(rateReminderResponse.body); | ||
|
||
if (rateReminderResponse.statusCode == 445) { |
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.
This is a very specific error code, are there any error codes we should handle?
Shouldn't all 4xx
status codes be handled?
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.
This log message mainly informs the developer how many points must be triggered before the app can show the rate reminder alert.
the other errors will be logged in the catch block.
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.
@pritam-bs can we then add a comment right in the code for future generations?
lib/src/sdk/nstack_features.dart
Outdated
@@ -8,6 +10,14 @@ typedef OnVersionUpdateNotification = void Function( | |||
NStackVersionUpdate? updateInfo, | |||
)?; | |||
|
|||
typedef OnRateReminder = void Function( | |||
NStackRateReminder? rateReminderInfo, |
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.
I don't think this should be nullable, when onRateReminder
we should expect the info to never be null.
Same for NStackRateReminderAnswer? rateReminderAnswer,
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.
Also the method in the type def itself should not be nullable, for example:
typedef OnRateReminderAnswered = void Function(
NStackRateReminderAnswer rateReminderAnswer,
);
Then in the class you can make it nullable:
final OnRateReminder? onRateReminder;
final OnRateReminderAnswered? onRateReminderAnswered;
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.
The NStackRateReminder
is nullable for the onRateReminder
callback when the points are less than the certain threshold set in the console, and the devs can make a conditional check if needed.
But NStackRateReminderAnswer
should not be nullable; I will fix that.
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.
@pritam-bs if we recieve null from BE should we display the reminder? If we should not display it then we should not call the callback in the first place and it can be nun nullable
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.
The intention was to enable developers to check the NStackRateReminder
value and decide whether to do anything when it is null. Anyway, change it to not nullable.
- Remane Localization for Rate Reminder - method in the type def made not nullable
lib/src/sdk/nstack_features.dart
Outdated
typedef OnRateReminder = void Function( | ||
NStackRateReminder? rateReminderInfo, | ||
); | ||
|
||
typedef OnRateReminderAnswered = void Function( | ||
NStackRateReminderAnswer rateReminderAnswer, | ||
); |
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.
On another topic for typedefs. There is no written naming convention available (based on a quick research I just did), but usually these callbacks must be named differently. Here are a few examples from the Flutter repo (see below).
I recommend to follow these rules:
typedef OnRateReminder = void Function( | |
NStackRateReminder? rateReminderInfo, | |
); | |
typedef OnRateReminderAnswered = void Function( | |
NStackRateReminderAnswer rateReminderAnswer, | |
); | |
typedef RateReminderCallback = void Function( | |
NStackRateReminder data, | |
); | |
typedef RateReminderAnswerCallback = void Function( | |
NStackRateReminderAnswer answer, | |
); |
Examples
(see more here)
typedef ValueGetter<T> = T Function();
/// Signature for callbacks that filter an iterable.
typedef IterableFilter<T> = Iterable<T> Function(Iterable<T> input);
/// Signature of callbacks that have no arguments and return no data, but that
/// return a [Future] to indicate when their work is complete.
///
/// See also:
///
/// * [VoidCallback], a synchronous version of this signature.
/// * [AsyncValueGetter], a signature for asynchronous getters.
/// * [AsyncValueSetter], a signature for asynchronous setters.
typedef AsyncCallback = Future<void> Function();
/// Signature for callbacks that report that a value has been set and return a
/// [Future] that completes when the value has been saved.
///
/// See also:
///
/// * [ValueSetter], a synchronous version of this signature.
/// * [AsyncValueGetter], the getter equivalent of this signature.
typedef AsyncValueSetter<T> = Future<void> Function(T value);
typedef GestureDragEndCallback = void Function(DragEndDetails details);
/// Signature for when the pointer that previously triggered a
/// [GestureDragDownCallback] did not complete.
///
/// Used by [DragGestureRecognizer.onCancel].
typedef GestureDragCancelCallback = void Function();
/// Signature for a function that builds a [VelocityTracker].
///
/// Used by [DragGestureRecognizer.velocityTrackerBuilder].
typedef GestureVelocityTrackerBuilder = VelocityTracker Function(PointerEvent event);
'If onRateReminder is null, then onAnswered must not be null.', | ||
); | ||
|
||
final Widget? child; |
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.
Put child
widgets last in the property list. Again, this is a convention that majority of Flutter widgets follow (and we do follow it as well). Same for the constructor parameter list
There's a related rule for this: https://dart.dev/tools/linter-rules/sort_child_properties_last
this.onAnswered, | ||
}) : assert( | ||
onRateReminder != null || onAnswered != null, | ||
'If onRateReminder is null, then onAnswered must not be 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.
'If onRateReminder is null, then onAnswered must not be null.', | |
'Either onRateReminder or onAnswered must be provided.', |
final void Function(NStackRateReminder?)? onRateReminder; | ||
final void Function(NStackRateReminderAnswer)? onAnswered; |
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.
Use our typedef
s here
WidgetsBinding.instance.addPostFrameCallback( | ||
(timeStamp) async { | ||
final rateReminderInfo = | ||
await context.nstack.rateReminders.getRateReminderInfo( | ||
defaultLocale: Localizations.localeOf(context), | ||
); | ||
_onRateReminder(rateReminderInfo); | ||
}, | ||
); |
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 don't need a post frame callback in didChangeDependencies
, it's only required in initState
.
Although are we sure this needs to be done in didChangeDependencies
? It might get executed quite frequently here
rateReminder.localization?.laterBtn ?? _laterButtonTitleFallback, | ||
); | ||
|
||
Future<void> buttonAction( |
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.
Let's move this out of the build
method
lib/templates/nstack_template.txt
Outdated
bool? testMode, | ||
}) : super( | ||
key: key, | ||
child: child, | ||
platformOverride: platformOverride, | ||
onComplete: onComplete, | ||
config: config, | ||
testMode: testMode ?? false, |
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.
bool? testMode, | |
}) : super( | |
key: key, | |
child: child, | |
platformOverride: platformOverride, | |
onComplete: onComplete, | |
config: config, | |
testMode: testMode ?? false, | |
bool testMode = false, | |
}) : super( | |
key: key, | |
child: child, | |
platformOverride: platformOverride, | |
onComplete: onComplete, | |
config: config, | |
testMode: testMode, |
State<StatefulWidget> createState() => _NStackRateReminderWidgetSate(); | ||
} | ||
|
||
class _NStackRateReminderWidgetSate extends State<NStackRateReminderWidget> { |
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.
State<StatefulWidget> createState() => _NStackRateReminderWidgetSate(); | |
} | |
class _NStackRateReminderWidgetSate extends State<NStackRateReminderWidget> { | |
State<StatefulWidget> createState() => _NStackRateReminderWidgetState(); | |
} | |
class _NStackRateReminderWidgetState extends State<NStackRateReminderWidget> { |