import 'dart:async'; import 'package:firebase_core/firebase_core.dart'; import 'package:flutter/material.dart'; import 'package:nexo_messaging/nexo_messaging.dart'; Future main() async { WidgetsFlutterBinding.ensureInitialized(); await _initializeFirebaseForHarness(); runApp(const MyApp()); } Future _initializeFirebaseForHarness() async { try { await Firebase.initializeApp(); } catch (error, stackTrace) { debugPrint('[NexoClient] Firebase initialization skipped: $error'); debugPrintStack(stackTrace: stackTrace); } } class MyApp extends StatefulWidget { const MyApp({super.key, this.initializePlugin = true}); final bool initializePlugin; @override State createState() => _MyAppState(); } class _MyAppState extends State { String? _deviceToken; String? _lastNotification; String? _lastOpened; String? _lastNavigation; NexoMessagingWebNotificationStatus? _webNotificationStatus; NexoMessagingWebNotificationDisplayResult? _lastWebDisplay; StreamSubscription>? _notificationSubscription; StreamSubscription? _openedSubscription; @override void initState() { super.initState(); final plugin = NexoMessagingPlugin.instance; plugin.onDeviceTokenReady = (token) { if (!mounted) return; setState(() => _deviceToken = token); }; plugin.onNavigateToChannel = (serverUrl, channelId) { if (!mounted) return; setState(() => _lastNavigation = 'channel:$serverUrl/$channelId'); }; plugin.onNavigateToThread = (serverUrl, rootId) { if (!mounted) return; setState(() => _lastNavigation = 'thread:$serverUrl/$rootId'); }; _notificationSubscription = plugin.onNotification.listen((event) { if (!mounted) return; setState(() => _lastNotification = _formatMap(event)); }); _openedSubscription = plugin.onNotificationOpened.listen((event) { if (!mounted) return; setState(() => _lastOpened = _formatOpened(event)); }); if (widget.initializePlugin) { unawaited(_initializePlugin(plugin)); } } Future _initializePlugin(NexoMessagingPlugin plugin) async { try { await _configureSmokeAuthToken(plugin); await plugin.initialize(); } catch (error, stackTrace) { debugPrint('[NexoClient] Failed to initialize messaging plugin: $error'); debugPrintStack(stackTrace: stackTrace); } } Future _configureSmokeAuthToken(NexoMessagingPlugin plugin) async { const serverUrl = String.fromEnvironment('NEXO_SMOKE_SERVER_URL'); const authToken = String.fromEnvironment('NEXO_SMOKE_AUTH_TOKEN'); const identifier = String.fromEnvironment('NEXO_SMOKE_SERVER_IDENTIFIER'); if (serverUrl.isEmpty || authToken.isEmpty) return; await plugin.setAuthToken( serverUrl, authToken, identifier: identifier.isEmpty ? null : identifier, ); debugPrint('[NexoClient] Smoke auth token configured'); } @override void dispose() { _notificationSubscription?.cancel(); _openedSubscription?.cancel(); final plugin = NexoMessagingPlugin.instance; plugin.onDeviceTokenReady = null; plugin.onNavigateToChannel = null; plugin.onNavigateToThread = null; super.dispose(); } String _formatMap(Map map) { return map.entries.map((e) => '${e.key}: ${e.value}').join(', '); } String _formatOpened(NotificationOpenedEvent event) { return 'server_url: ${event.serverUrl}, channel_id: ${event.channelId}, root_id: ${event.rootId}, is_crt_enabled: ${event.isCRTEnabled}'; } String _formatWebSupport() { if (_webNotificationStatus == null) return 'unknown'; return _webNotificationStatus!.isSupported ? 'yes' : 'no'; } String _formatWebPermission() { if (_webNotificationStatus == null) return 'unknown'; return _webNotificationStatus!.permission.name; } String _formatWebDisplay() { if (_lastWebDisplay == null) return 'none'; if (!_lastWebDisplay!.isSupported) return 'unsupported'; if (!_lastWebDisplay!.permissionGranted) return 'permission denied'; return _lastWebDisplay!.success ? 'shown' : 'failed'; } Future _refreshWebNotificationStatus(NexoMessagingPlugin plugin) async { try { final status = await plugin.getWebNotificationPermissionStatus(); if (!mounted) return; setState(() => _webNotificationStatus = status); } catch (e) { debugPrint('[NexoClient] Web permission refresh failed: $e'); } } Future _requestWebNotificationPermission( NexoMessagingPlugin plugin, ) async { try { final status = await plugin.requestWebNotificationPermission(); if (!mounted) return; setState(() => _webNotificationStatus = status); } catch (e) { debugPrint('[NexoClient] Web permission request failed: $e'); } } void _showWebSmokeNotification(NexoMessagingPlugin plugin) { final result = plugin.showWebForegroundNotification({ 'title': 'Nexo Smoke', 'body': 'Web notification smoke test', 'server_url': 'https://nexo.example.com', 'channel_id': 'smoke-channel', }); setState(() => _lastWebDisplay = result); } @override Widget build(BuildContext context) { final plugin = NexoMessagingPlugin.instance; return MaterialApp( home: Scaffold( appBar: AppBar(title: const Text('Nexo client')), body: ListView( padding: const EdgeInsets.all(16), children: [ Text('Device token: ${_deviceToken ?? 'pending'}'), Text('Last notification: ${_lastNotification ?? 'none'}'), Text('Last opened: ${_lastOpened ?? 'none'}'), Text('Last navigation: ${_lastNavigation ?? 'none'}'), Text('Web notification support: ${_formatWebSupport()}'), Text( 'Web notification permission: ${_formatWebPermission()}', key: const Key('web-permission-status'), ), Text( 'Last web display: ${_formatWebDisplay()}', key: const Key('web-display-status'), ), ElevatedButton( onPressed: () => unawaited(_refreshWebNotificationStatus(plugin)), child: const Text('Refresh web permission'), ), ElevatedButton( onPressed: () => unawaited(_requestWebNotificationPermission(plugin)), child: const Text('Request web permission'), ), ElevatedButton( onPressed: () => _showWebSmokeNotification(plugin), child: const Text('Show web smoke notification'), ), ], ), ), ); } }