Skip to content

Instantly share code, notes, and snippets.

@lukepighetti
Created March 4, 2024 02:08
Show Gist options
  • Save lukepighetti/344095c57c962cfa86af97f9115b8a4b to your computer and use it in GitHub Desktop.
Save lukepighetti/344095c57c962cfa86af97f9115b8a4b to your computer and use it in GitHub Desktop.
My way of showing a paywall every day for a few days, then every week, then every two weeks. Good for about a year.
import 'package:collection/collection.dart';
import 'package:shared_preferences/shared_preferences.dart';
import '/architecture/let.dart';
import '/membership/membership_state.dart';
import '/membership/membership_tasks.dart';
import '/telemetry/analytics.dart';
Future<void> appOpenAction() async {
$analytics.vglAppOpenActionRequested();
final prefs = await SharedPreferences.getInstance();
final now = DateTime.now();
final first = prefs.firstDate ??= now;
final last = prefs.lastDate ?? DateTime(2020);
final today = now.difference(first).inDays;
final lastDay = last.difference(first).inDays;
final nextDay = schedule.next(lastDay);
// We've completed the entire schedule!
if (nextDay == null || nextDay > today) {
$analytics.vglAppOpenActionSkip();
} else {
$analytics.vglAppOpenActionShown();
prefs.lastDate = now;
_handleAppOpenAction();
}
}
void _handleAppOpenAction() {
if (!$revenueCat.proOrGrandfathered) {
showPaywall(PaywallReferrer.appOpen);
}
}
Iterable<int> get schedule sync* {
var x = -1;
for (var i = 1; i < 30; i++) {
switch (i) {
case <= 4:
x += 1;
case <= 7:
x += 4;
case <= 14:
x += 7;
case _:
x += 14;
}
yield x;
}
}
extension on SharedPreferences {
DateTime? get firstDate => getString('la-fd')?.let(DateTime.tryParse);
set firstDate(DateTime? x) => setString('la-fd', x?.toIso8601String() ?? '');
DateTime? get lastDate => getString('la-ld')?.let(DateTime.tryParse);
set lastDate(DateTime? x) => setString('la-ld', x?.toIso8601String() ?? '');
Future<void> clearDates() async {
await remove('la-fd');
await remove('la-ld');
}
}
Future<void> clearAppOpenActionDates() =>
SharedPreferences.getInstance().then((x) => x.clearDates());
extension on Iterable<int> {
Iterable<(int, int)> get pairwise sync* {
for (var i = 0; i < length - 1; i++) {
yield (elementAt(i), elementAt(i + 1));
}
}
int? next(int needle) {
final s = sorted((a, z) => a - z);
for (final (i, (a, b)) in s.pairwise.indexed) {
if (i == 0 && needle < a) {
return a;
}
if (a <= needle && needle < b) {
return b;
}
}
return null;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment