From 98e5695f9c77c594a103e9e81128798d41bae46a Mon Sep 17 00:00:00 2001
From: Matthias Nott <mnott@mnsoft.org>
Date: Wed, 01 Apr 2026 18:52:33 +0200
Subject: [PATCH] feat: StoreKit 2 IAP — free tier with 2 sessions and 15min message TTL
---
lib/screens/chat_screen.dart | 22 +++++++++++++++++++++-
1 files changed, 21 insertions(+), 1 deletions(-)
diff --git a/lib/screens/chat_screen.dart b/lib/screens/chat_screen.dart
index f51862a..e1aa9db 100644
--- a/lib/screens/chat_screen.dart
+++ b/lib/screens/chat_screen.dart
@@ -23,9 +23,11 @@
import '../services/navigate_notifier.dart';
import '../services/push_service.dart';
import '../theme/app_theme.dart';
+import '../services/purchase_service.dart';
import '../widgets/command_bar.dart';
import '../widgets/input_bar.dart';
import '../widgets/message_bubble.dart';
+import '../widgets/paywall_banner.dart';
import '../widgets/session_drawer.dart';
import '../widgets/status_dot.dart';
import '../widgets/toast_overlay.dart';
@@ -1332,6 +1334,11 @@
_sendCommand('create');
}
+ /// Called when the user taps an upgrade CTA in the drawer or paywall banner.
+ Future<void> _handleUpgrade() async {
+ await PurchaseService.instance.purchaseFullAccess();
+ }
+
void _handleSessionRename(Session session, String newName) {
_sendCommand('rename', {'sessionId': session.id, 'name': newName});
final sessions = ref.read(sessionsProvider);
@@ -1385,7 +1392,17 @@
@override
Widget build(BuildContext context) {
- final messages = ref.watch(messagesProvider);
+ final allMessages = ref.watch(messagesProvider);
+ final isPro = ref.watch(isProProvider);
+ // Free tier: filter out messages older than 15 minutes on display.
+ // Storage is unchanged — messages reappear if the user later upgrades.
+ final messages = isPro
+ ? allMessages
+ : allMessages.where((m) {
+ final ts = DateTime.fromMillisecondsSinceEpoch(m.timestamp);
+ final age = DateTime.now().difference(ts);
+ return age <= kFreeTierMessageTtl;
+ }).toList();
final wsStatus = ref.watch(wsStatusProvider);
final isTyping = ref.watch(isTypingProvider);
final connectionDetail = ref.watch(connectionDetailProvider);
@@ -1452,15 +1469,18 @@
sessions: sessions,
activeSessionId: activeSession?.id,
unreadCounts: unreadCounts,
+ isPro: ref.watch(isProProvider),
onSelect: (s) => _switchSession(s.id),
onRemove: _handleSessionRemove,
onRename: _handleSessionRename,
onReorder: _handleSessionReorder,
onNewSession: _handleNewSession,
onRefresh: _refreshSessions,
+ onUpgrade: _handleUpgrade,
),
body: Column(
children: [
+ const PaywallBanner(),
Expanded(
child: ListView.builder(
controller: _scrollController,
--
Gitblit v1.3.1