diff --git a/lib/main.dart b/lib/main.dart index 130c24e..2b09208 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -97,12 +97,12 @@ class ZapstoreApp extends HookConsumerWidget { // Check initial connectivity state connectivity.checkConnectivity().then((results) { - notifier.ensureConnected(); + notifier.connect(); }); // Listen to connectivity changes subscription = connectivity.onConnectivityChanged.listen((results) { - notifier.ensureConnected(); + notifier.connect(); }); return () => subscription?.cancel(); @@ -273,10 +273,7 @@ Future onSignInSuccess(Ref ref) async { unawaited( storage.query( RequestFilter(authors: {pubkey}).toRequest(), - source: const RemoteSource( - relays: 'bootstrap', - stream: false, - ), + source: const RemoteSource(relays: 'bootstrap', stream: false), ), ); } @@ -290,14 +287,15 @@ class _AppLifecycleObserver with WidgetsBindingObserver { @override void didChangeAppLifecycleState(AppLifecycleState state) { final downloadService = _ref.read(downloadServiceProvider.notifier); + final notifier = + _ref.read(storageNotifierProvider.notifier) + as PurplebaseStorageNotifier; if (state == AppLifecycleState.resumed) { - // Notify download service that app is in foreground - // This will process any pending installations + // Process any pending installations unawaited(downloadService.setAppForeground(true)); - // App regained focus - re-sync installed packages from Android system - // This will detect any apps installed/uninstalled outside of Zapstore + // Re-sync installed packages from Android system unawaited( _ref.read(packageManagerProvider.notifier).syncInstalledPackages(), ); @@ -306,16 +304,11 @@ class _AppLifecycleObserver with WidgetsBindingObserver { // Force immediate health check on storage/relay connections // This detects stale connections after system sleep and triggers reconnection - final notifier = - _ref.read(storageNotifierProvider.notifier) - as PurplebaseStorageNotifier; - notifier.ensureConnected(); - } else if (state == AppLifecycleState.paused || - state == AppLifecycleState.inactive || - state == AppLifecycleState.detached || - state == AppLifecycleState.hidden) { - // Notify download service that app is in background + notifier.connect(); + } else if (state == AppLifecycleState.paused) { + // Note: paused corresponds to Android's `onStop` unawaited(downloadService.setAppForeground(false)); + notifier.disconnect(); } } } diff --git a/lib/screens/profile_screen.dart b/lib/screens/profile_screen.dart index 62a6afb..27c8dd9 100644 --- a/lib/screens/profile_screen.dart +++ b/lib/screens/profile_screen.dart @@ -293,7 +293,6 @@ class _DebugMessagesSection extends HookConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { final poolState = ref.watch(poolStateProvider); - final isExpanded = useState(true); final selectedTab = useState(0); // 0=Subscriptions, 1=Logs final now = useState(DateTime.now()); final expandedSubs = useState>({}); @@ -308,45 +307,6 @@ class _DebugMessagesSection extends HookConsumerWidget { final subscriptions = poolState?.subscriptions ?? {}; final logs = poolState?.logs ?? const []; - // Aggregate relay status across all subscriptions - final allRelayUrls = []; - final relayDebugEntries = - < - ({ - String url, - String shortUrl, - RelaySubPhase phase, - String? lastError, - String subscriptionId, - }) - >[]; - final connectedRelayUrls = {}; - for (final subEntry in subscriptions.entries) { - final subscriptionId = subEntry.key; - final sub = subEntry.value; - for (final entry in sub.relays.entries) { - final url = entry.key; - final relay = entry.value; - final phase = relay.phase; - final shortUrl = url - .replaceAll('wss://', '') - .replaceAll('ws://', '') - .replaceAll(RegExp(r'/$'), ''); - allRelayUrls.add(url); - relayDebugEntries.add(( - url: url, - shortUrl: shortUrl, - phase: phase, - lastError: relay.lastError, - subscriptionId: subscriptionId, - )); - if (phase == RelaySubPhase.streaming || - phase == RelaySubPhase.loading) { - connectedRelayUrls.add(url); - } - } - } - void toggleSubscription(String id) { final next = {...expandedSubs.value}; if (!next.remove(id)) { @@ -362,64 +322,53 @@ class _DebugMessagesSection extends HookConsumerWidget { crossAxisAlignment: CrossAxisAlignment.start, children: [ // Header - InkWell( - onTap: () => isExpanded.value = !isExpanded.value, - child: Row( - children: [ - Icon( - Icons.bug_report, - color: Theme.of(context).colorScheme.primary, - ), - const SizedBox(width: 8), - Expanded( - child: Text( - 'Debug Info', - style: Theme.of(context).textTheme.titleMedium?.copyWith( - fontWeight: FontWeight.bold, - ), + Row( + children: [ + Icon( + Icons.bug_report, + color: Theme.of(context).colorScheme.primary, + ), + const SizedBox(width: 8), + Expanded( + child: Text( + 'Debug Info', + style: Theme.of(context).textTheme.titleMedium?.copyWith( + fontWeight: FontWeight.bold, ), ), - const SizedBox(width: 8), - Icon( - isExpanded.value ? Icons.expand_less : Icons.expand_more, - color: Theme.of(context).colorScheme.primary, - ), - ], - ), - ), - - if (isExpanded.value) ...[ - const SizedBox(height: 10), - - // Tab selector - Row( - children: [ - _TabButton( - label: 'Subscriptions (${subscriptions.length})', - isSelected: selectedTab.value == 0, - onTap: () => selectedTab.value = 0, - ), - const SizedBox(width: 8), - _TabButton( - label: 'Log (${logs.length})', - isSelected: selectedTab.value == 1, - onTap: () => selectedTab.value = 1, - ), - ], - ), - const SizedBox(height: 12), - - // Tab content - if (selectedTab.value == 0) - _buildSubscriptionsTab( - context, - subscriptions, - now.value, - expandedSubs.value, - toggleSubscription, ), - if (selectedTab.value == 1) _buildLogsTab(context, logs), - ], + ], + ), + const SizedBox(height: 10), + + // Tab selector + Row( + children: [ + _TabButton( + label: 'Subscriptions (${subscriptions.length})', + isSelected: selectedTab.value == 0, + onTap: () => selectedTab.value = 0, + ), + const SizedBox(width: 8), + _TabButton( + label: 'Log (${logs.length})', + isSelected: selectedTab.value == 1, + onTap: () => selectedTab.value = 1, + ), + ], + ), + const SizedBox(height: 12), + + // Tab content + if (selectedTab.value == 0) + _buildSubscriptionsTab( + context, + subscriptions, + now.value, + expandedSubs.value, + toggleSubscription, + ), + if (selectedTab.value == 1) _buildLogsTab(context, logs), ], ), ), @@ -428,7 +377,7 @@ class _DebugMessagesSection extends HookConsumerWidget { Widget _buildSubscriptionsTab( BuildContext context, - Map subscriptions, + Map subscriptions, DateTime now, Set expandedSubs, void Function(String id) onToggleSub, @@ -481,7 +430,7 @@ class _DebugMessagesSection extends HookConsumerWidget { size: 16, color: allEose ? Colors.green - : Theme.of(context).colorScheme.primary, + : Colors.amber.shade700, ), const SizedBox(width: 6), Expanded( @@ -495,6 +444,19 @@ class _DebugMessagesSection extends HookConsumerWidget { overflow: TextOverflow.ellipsis, ), ), + const SizedBox(width: 8), + _StatusChip( + icon: Icons.event, + label: '${sub.eventCount}', + color: Theme.of(context).colorScheme.primary, + ), + const SizedBox(width: 6), + _StatusChip( + icon: Icons.cloud_done, + label: '$activeRelays/$totalRelays', + color: allEose ? Colors.green : Colors.amber.shade700, + ), + const SizedBox(width: 6), Icon( isExpanded ? Icons.expand_less : Icons.expand_more, size: 16, @@ -504,30 +466,6 @@ class _DebugMessagesSection extends HookConsumerWidget { ), ], ), - const SizedBox(height: 6), - Wrap( - spacing: 8, - runSpacing: 6, - children: [ - _StatusChip( - icon: Icons.cloud_done, - label: '$activeRelays/$totalRelays', - color: allEose ? Colors.green : Colors.blue, - ), - if (allEose) - _StatusChip( - icon: Icons.check_circle, - label: 'EOSE', - color: Colors.green, - ), - if (sub.stream) - _StatusChip( - icon: Icons.wifi_tethering, - label: 'Streaming', - color: Theme.of(context).colorScheme.primary, - ), - ], - ), if (relayEntries.isNotEmpty) ...[ const SizedBox(height: 10), Container( @@ -792,7 +730,7 @@ class _DebugMessagesSection extends HookConsumerWidget { return hours > 0 ? '${days}d ${hours}h' : '${days}d'; } - Widget _buildRequestView(BuildContext context, Subscription sub) { + Widget _buildRequestView(BuildContext context, RelaySubscription sub) { final req = _formatReq(sub); return Container( margin: const EdgeInsets.only(top: 10), @@ -858,7 +796,7 @@ class _DebugMessagesSection extends HookConsumerWidget { ); } - String _formatReq(Subscription sub) { + String _formatReq(RelaySubscription sub) { final payload = ['REQ', sub.id, ...sub.request.toMaps()]; try { return const JsonEncoder.withIndent(' ').convert(payload);