update one signal

This commit is contained in:
Phuoc Nguyen
2025-12-10 17:14:03 +07:00
parent 4cfe000172
commit f130820131
4 changed files with 106 additions and 3 deletions

View File

@@ -0,0 +1,92 @@
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:
/// - Setting external user ID after login (using phone number)
/// - Restoring external user ID on app startup
/// - Clearing external user ID on logout
///
/// Usage:
/// ```dart
/// // After successful login
/// await OneSignalService.login(phoneNumber);
///
/// // On logout
/// await OneSignalService.logout();
/// ```
class OneSignalService {
OneSignalService._();
/// 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<void> 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<void> 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<void> 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<void> setTags(Map<String, String> 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<void> 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;
}

View File

@@ -11,6 +11,7 @@ import 'package:riverpod_annotation/riverpod_annotation.dart';
import 'package:worker/core/constants/api_constants.dart'; import 'package:worker/core/constants/api_constants.dart';
import 'package:worker/core/network/dio_client.dart'; import 'package:worker/core/network/dio_client.dart';
import 'package:worker/core/services/frappe_auth_service.dart'; import 'package:worker/core/services/frappe_auth_service.dart';
import 'package:worker/core/services/onesignal_service.dart';
import 'package:worker/features/auth/data/datasources/auth_local_datasource.dart'; import 'package:worker/features/auth/data/datasources/auth_local_datasource.dart';
import 'package:worker/features/auth/data/datasources/auth_remote_datasource.dart'; import 'package:worker/features/auth/data/datasources/auth_remote_datasource.dart';
import 'package:worker/features/auth/domain/entities/user.dart'; import 'package:worker/features/auth/domain/entities/user.dart';
@@ -100,7 +101,11 @@ class Auth extends _$Auth {
final fullName = await secureStorage.read(key: 'frappe_full_name'); final fullName = await secureStorage.read(key: 'frappe_full_name');
if (sid != null && userId != null && userId != ApiConstants.frappePublicUserId) { if (sid != null && userId != null && userId != ApiConstants.frappePublicUserId) {
// User is logged in and wants to be remembered, create User entity // User is logged in and wants to be remembered
// Restore OneSignal external user ID for targeted notifications
await OneSignalService.login(userId);
// Create User entity
final now = DateTime.now(); final now = DateTime.now();
return User( return User(
userId: userId, userId: userId,
@@ -188,6 +193,9 @@ class Auth extends _$Auth {
// Log login event // Log login event
await AnalyticsService.logLogin(method: 'phone'); await AnalyticsService.logLogin(method: 'phone');
// Set OneSignal external user ID for targeted notifications
await OneSignalService.login(phoneNumber);
// Create and return User entity // Create and return User entity
final now = DateTime.now(); final now = DateTime.now();
return User( return User(
@@ -227,6 +235,9 @@ class Auth extends _$Auth {
// Clear user ID from analytics // Clear user ID from analytics
await AnalyticsService.setUserId(null); await AnalyticsService.setUserId(null);
// Clear OneSignal external user ID
await OneSignalService.logout();
// Clear saved session // Clear saved session
await _localDataSource.clearSession(); await _localDataSource.clearSession();
await frappeService.clearSession(); await frappeService.clearSession();

View File

@@ -272,7 +272,7 @@ final class AuthProvider extends $AsyncNotifierProvider<Auth, User?> {
Auth create() => Auth(); Auth create() => Auth();
} }
String _$authHash() => r'f1d856a9a8fc461da111699e3c7ca2af1f2ce7ca'; String _$authHash() => r'2aaad43ba390e824b5aa8d95bc14e514c421c8ef';
/// Authentication Provider /// Authentication Provider
/// ///

View File

@@ -16,7 +16,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
# In Windows, build-name is used as the major, minor, and patch parts # In Windows, build-name is used as the major, minor, and patch parts
# of the product and file versions while build-number is used as the build suffix. # of the product and file versions while build-number is used as the build suffix.
version: 1.0.1+26 version: 1.0.1+29
environment: environment:
sdk: ^3.10.0 sdk: ^3.10.0