feat: track end date on cancel subscription click and refresh page when end date changes (#5542)

This commit is contained in:
ggurdin 2026-01-30 14:54:18 -05:00 committed by GitHub
parent 74be947f0f
commit 0cd2d0d9c5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 66 additions and 6 deletions

View file

@ -5,6 +5,7 @@ class PLocalKey {
static const String dismissedPaywall = 'dismissedPaywall';
static const String paywallBackoff = 'paywallBackoff';
static const String clickedCancelSubscription = 'clickedCancelSubscription';
static const String subscriptionEndDate = 'subscriptionWillEnd';
static const String messagesSinceUpdate = 'messagesSinceLastUpdate';
static const String completedActivities = 'completedActivities';
static const String justInputtedCode = 'justInputtedCode';

View file

@ -1,5 +1,6 @@
import 'dart:async';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:url_launcher/url_launcher_string.dart';
@ -22,7 +23,8 @@ class SubscriptionManagement extends StatefulWidget {
SubscriptionManagementController();
}
class SubscriptionManagementController extends State<SubscriptionManagement> {
class SubscriptionManagementController extends State<SubscriptionManagement>
with WidgetsBindingObserver {
final SubscriptionController subscriptionController =
MatrixState.pangeaController.subscriptionController;
@ -31,6 +33,9 @@ class SubscriptionManagementController extends State<SubscriptionManagement> {
@override
void initState() {
WidgetsBinding.instance.addObserver(this);
_refreshSubscription();
if (!subscriptionController.initCompleter.isCompleted) {
subscriptionController.initialize().then((_) => setState(() {}));
}
@ -43,11 +48,20 @@ class SubscriptionManagementController extends State<SubscriptionManagement> {
@override
void dispose() {
WidgetsBinding.instance.removeObserver(this);
subscriptionController.subscriptionNotifier.removeListener(_onSubscribe);
subscriptionController.removeListener(_onSubscriptionUpdate);
super.dispose();
}
@override
void didChangeAppLifecycleState(AppLifecycleState state) {
if (state == AppLifecycleState.resumed) {
_refreshSubscription();
}
super.didChangeAppLifecycleState(state);
}
bool get subscriptionsAvailable =>
subscriptionController
.availableSubscriptionInfo?.availableSubscriptions.isNotEmpty ??
@ -103,6 +117,33 @@ class SubscriptionManagementController extends State<SubscriptionManagement> {
void _onSubscriptionUpdate() => setState(() {});
void _onSubscribe() => showSubscribedSnackbar(context);
Future<void> _refreshSubscription() async {
if (!kIsWeb) return;
// if the user previously clicked cancel, check if the subscription end date has changed
final prevEndDate = SubscriptionManagementRepo.getSubscriptionEndDate();
final clickedCancel =
SubscriptionManagementRepo.getClickedCancelSubscription();
if (clickedCancel == null) return;
await subscriptionController.reinitialize();
final newEndDate =
subscriptionController.currentSubscriptionInfo?.subscriptionEndDate;
if (prevEndDate != newEndDate) {
SubscriptionManagementRepo.removeClickedCancelSubscription();
SubscriptionManagementRepo.setSubscriptionEndDate(newEndDate);
if (mounted) setState(() {});
return;
}
// if more than 10 minutes have passed since the user clicked cancel, remove the click flag
if (DateTime.now().difference(clickedCancel).inMinutes >= 10) {
SubscriptionManagementRepo.removeClickedCancelSubscription();
if (mounted) setState(() {});
}
}
Future<void> submitChange(
SubscriptionDetails subscription, {
bool isPromo = false,
@ -130,6 +171,9 @@ class SubscriptionManagementController extends State<SubscriptionManagement> {
Future<void> onClickCancelSubscription() async {
await SubscriptionManagementRepo.setClickedCancelSubscription();
await SubscriptionManagementRepo.setSubscriptionEndDate(
subscriptionEndDate,
);
await launchMangementUrl(ManagementOption.cancel);
if (mounted) setState(() {});
}

View file

@ -16,6 +16,8 @@ class SettingsSubscriptionView extends StatelessWidget {
@override
Widget build(BuildContext context) {
final clickedCancelDate =
SubscriptionManagementRepo.getClickedCancelSubscription();
final List<Widget> managementButtons = [
if (controller.currentSubscriptionAvailable)
ListTile(
@ -70,7 +72,8 @@ class SettingsSubscriptionView extends StatelessWidget {
),
),
),
if (SubscriptionManagementRepo.getClickedCancelSubscription())
if (clickedCancelDate != null &&
DateTime.now().difference(clickedCancelDate).inMinutes < 10)
Padding(
padding: const EdgeInsets.all(16.0),
child: Row(

View file

@ -77,14 +77,26 @@ class SubscriptionManagementRepo {
);
}
static bool getClickedCancelSubscription() {
static DateTime? getClickedCancelSubscription() {
final entry = _cache.read(PLocalKey.clickedCancelSubscription);
if (entry == null) return false;
final val = DateTime.tryParse(entry);
return val != null && DateTime.now().difference(val).inSeconds < 60;
if (entry == null) return null;
return DateTime.tryParse(entry);
}
static Future<void> removeClickedCancelSubscription() async {
await _cache.remove(PLocalKey.clickedCancelSubscription);
}
static Future<void> setSubscriptionEndDate(DateTime? date) async {
await _cache.write(
PLocalKey.subscriptionEndDate,
date?.toIso8601String(),
);
}
static DateTime? getSubscriptionEndDate() {
final entry = _cache.read(PLocalKey.subscriptionEndDate);
if (entry == null) return null;
return DateTime.tryParse(entry);
}
}