import 'package:flutter/foundation.dart'; import 'package:onesignal_flutter/onesignal_flutter.dart'; /// OneSignal service for managing push notifications and external user ID. /// /// This service handles: /// - Initializing OneSignal SDK /// - Setting external user ID after login (using phone number) /// - Restoring external user ID on app startup /// - Clearing external user ID on logout /// /// Usage: /// ```dart /// // Initialize in main.dart /// await OneSignalService.init(appId: 'your-app-id'); /// /// // After successful login /// await OneSignalService.login(phoneNumber); /// /// // On logout /// await OneSignalService.logout(); /// ``` class OneSignalService { OneSignalService._(); /// OneSignal App ID - Replace with your actual App ID from OneSignal dashboard static const String _defaultAppId = '778ca22d-c719-4ec8-86cb-a6b911166066'; /// Initialize OneSignal SDK /// /// Must be called before using any other OneSignal methods. /// Sets up push subscription observers and requests notification permission. /// /// [appId] - Optional App ID override (uses default if not provided) /// [requestPermission] - Whether to request notification permission (default: true) static Future init({ String? appId, bool requestPermission = true, }) async { try { // Set debug log level (verbose in debug, none in release) OneSignal.Debug.setLogLevel(kDebugMode ? OSLogLevel.verbose : OSLogLevel.none); // Initialize with App ID OneSignal.initialize(appId ?? _defaultAppId); debugPrint('🔔 OneSignal initialized'); // Add push subscription observer to track subscription state changes OneSignal.User.pushSubscription.addObserver((state) { debugPrint('🔔 Push subscription state changed:'); debugPrint(' Previous - optedIn: ${state.previous.optedIn}, id: ${state.previous.id}'); debugPrint(' Current - optedIn: ${state.current.optedIn}, id: ${state.current.id}'); debugPrint(' Subscription ID: ${state.current.id}'); debugPrint(' Push Token: ${state.current.token}'); if (state.current.id != null) { debugPrint('🔔 ✅ Device successfully subscribed!'); } }); // Add notification permission observer OneSignal.Notifications.addPermissionObserver((isGranted) { debugPrint('🔔 Notification permission changed: $isGranted'); }); // Request permission if enabled if (requestPermission) { final accepted = await OneSignal.Notifications.requestPermission(true); debugPrint('🔔 Permission request result: $accepted'); } // Give OneSignal SDK time to complete initialization and server registration await Future.delayed(const Duration(seconds: 2)); // Log current subscription status _logSubscriptionStatus(); } catch (e) { debugPrint('🔔 OneSignal error: Failed to initialize - $e'); } } /// Log current subscription status for debugging static void _logSubscriptionStatus() { final optedIn = OneSignal.User.pushSubscription.optedIn; final id = OneSignal.User.pushSubscription.id; final token = OneSignal.User.pushSubscription.token; debugPrint('🔔 Current subscription status:'); debugPrint(' Opted In: $optedIn'); debugPrint(' Subscription ID: $id'); debugPrint(' Push Token: $token'); if (id == null) { debugPrint('🔔 ⚠️ Subscription ID is null - check device connectivity and OneSignal app ID'); } } /// Login user to OneSignal by setting external user ID. /// /// This associates the device with the user's phone number, /// allowing targeted push notifications to specific users. /// /// [phoneNumber] - The user's phone number (used as external ID) static Future login(String phoneNumber) async { try { // Set external user ID for targeting await OneSignal.login(phoneNumber); debugPrint('🔔 OneSignal: login - external_id set to $phoneNumber'); } catch (e) { debugPrint('🔔 OneSignal error: Failed to set external user ID - $e'); } } /// Logout user from OneSignal by removing external user ID. /// /// This disassociates the device from the user, /// so notifications won't be sent to this specific user anymore. static Future logout() async { try { await OneSignal.logout(); debugPrint('🔔 OneSignal: logout - external_id cleared'); } catch (e) { debugPrint('🔔 OneSignal error: Failed to clear external user ID - $e'); } } /// Add a tag to the user for segmentation. /// /// Tags can be used to segment users for targeted notifications. /// Example: tier = "diamond", role = "contractor" static Future setTag(String key, String value) async { try { await OneSignal.User.addTagWithKey(key, value); debugPrint('🔔 OneSignal: tag set - $key: $value'); } catch (e) { debugPrint('🔔 OneSignal error: Failed to set tag - $e'); } } /// Add multiple tags at once. static Future setTags(Map tags) async { try { await OneSignal.User.addTags(tags); debugPrint('🔔 OneSignal: tags set - $tags'); } catch (e) { debugPrint('🔔 OneSignal error: Failed to set tags - $e'); } } /// Remove a tag from the user. static Future removeTag(String key) async { try { await OneSignal.User.removeTag(key); debugPrint('🔔 OneSignal: tag removed - $key'); } catch (e) { debugPrint('🔔 OneSignal error: Failed to remove tag - $e'); } } /// Get the OneSignal subscription ID (player ID). /// /// This is the device-specific ID used by OneSignal. static String? get subscriptionId => OneSignal.User.pushSubscription.id; /// Check if push notifications are enabled. static bool get isPushEnabled => OneSignal.User.pushSubscription.optedIn ?? false; }