package ai.sirrus.reactnativesdk import android.Manifest import android.app.Activity import android.app.NotificationChannel import android.app.NotificationManager import android.content.Context import android.content.Intent import android.content.pm.PackageManager import android.os.Build import androidx.core.app.NotificationManagerCompat import androidx.core.content.ContextCompat import com.facebook.react.bridge.ActivityEventListener import com.facebook.react.bridge.Arguments import com.facebook.react.bridge.Promise import com.facebook.react.bridge.ReactApplicationContext import com.facebook.react.bridge.ReactContextBaseJavaModule import com.facebook.react.bridge.ReactMethod import com.facebook.react.bridge.ReadableArray import com.facebook.react.bridge.ReadableMap import com.facebook.react.modules.core.PermissionAwareActivity import com.facebook.react.modules.core.PermissionListener import com.google.firebase.messaging.FirebaseMessaging import java.util.concurrent.Executors import kotlin.math.abs class SirrusReactNativeSdkModule( reactContext: ReactApplicationContext ) : ReactContextBaseJavaModule(reactContext), ActivityEventListener { private val executor = Executors.newCachedThreadPool() private var permissionPromise: Promise? = null init { reactContext.addActivityEventListener(this) SirrusNotificationEventDispatcher.attachReactContext(reactContext) } override fun getName(): String = "SirrusReactNativeSdk" @ReactMethod fun requestPermission(promise: Promise) { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) { promise.resolve(permissionResultMap(true, "granted")) return } val activity = reactApplicationContext.currentActivity if (activity == null || activity !is PermissionAwareActivity) { promise.resolve( permissionResultMap( ContextCompat.checkSelfPermission( reactApplicationContext, Manifest.permission.POST_NOTIFICATIONS ) == PackageManager.PERMISSION_GRANTED, "unavailable" ) ) return } val granted = ContextCompat.checkSelfPermission( reactApplicationContext, Manifest.permission.POST_NOTIFICATIONS ) == PackageManager.PERMISSION_GRANTED if (granted) { promise.resolve(permissionResultMap(true, "granted")) return } permissionPromise = promise activity.requestPermissions( arrayOf(Manifest.permission.POST_NOTIFICATIONS), 9103, PermissionListener { requestCode, _, grantResults -> if (requestCode != 9103) { return@PermissionListener false } val isGranted = grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED permissionPromise?.resolve( permissionResultMap( isGranted, if (isGranted) "granted" else "denied" ) ) permissionPromise = null true } ) } @ReactMethod fun registerAndroidChannels(channels: ReadableArray, promise: Promise) { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) { promise.resolve(null) return } val manager = reactApplicationContext.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager for (index in 0 until channels.size()) { val channelMap = channels.getMap(index) ?: continue val channelId = channelMap.getString("id") ?: continue val channel = NotificationChannel( channelId, channelMap.getString("name") ?: channelId, SirrusNotificationRenderer.parseImportance(channelMap.getString("importance")) ) channel.description = channelMap.getString("description") channel.enableVibration(channelMap.getBooleanOrDefault("enableVibration", true)) manager.createNotificationChannel(channel) } promise.resolve(null) } @ReactMethod fun registerIOSCategories(categories: ReadableArray, promise: Promise) { promise.resolve(null) } @ReactMethod fun showLocalNotification(payload: ReadableMap, promise: Promise) { executor.execute { try { val context = reactApplicationContext SirrusNotificationRenderer.show( context, SirrusNotificationDataParser.fromReadableMap(payload) ) promise.resolve(null) } catch (error: Throwable) { promise.reject("SIRRUS_SHOW_NOTIFICATION_ERROR", error) } } } @ReactMethod fun cancelNotification(notificationId: String, promise: Promise) { NotificationManagerCompat.from(reactApplicationContext) .cancel(abs(notificationId.hashCode())) promise.resolve(null) } @ReactMethod fun cancelAllNotifications(promise: Promise) { NotificationManagerCompat.from(reactApplicationContext).cancelAll() promise.resolve(null) } @ReactMethod fun setBadgeCount(count: Double, promise: Promise) { promise.resolve(null) } @ReactMethod fun consumeInitialNotificationEvent(promise: Promise) { val event = SirrusNotificationEventDispatcher.consumeActivityLaunchEvent( reactApplicationContext, reactApplicationContext.currentActivity ) ?: SirrusNotificationEventDispatcher.consumeStoredEvent(reactApplicationContext) promise.resolve(event) } @ReactMethod fun consumeLatestNativePushToken(promise: Promise) { val token = SirrusNotificationEventDispatcher.consumeLatestPushToken(reactApplicationContext) if (token != null) { promise.resolve(token) return } FirebaseMessaging.getInstance().token .addOnSuccessListener { fcmToken -> SirrusNotificationEventDispatcher.storeLatestPushToken( reactApplicationContext, fcmToken, "fcm" ) promise.resolve(Arguments.createMap().apply { putString("token", fcmToken) putString("provider", "fcm") }) } .addOnFailureListener { error -> promise.reject("SIRRUS_FCM_TOKEN_ERROR", error) } } @ReactMethod fun addListener(eventName: String) = Unit @ReactMethod fun removeListeners(count: Double) = Unit private fun permissionResultMap(granted: Boolean, status: String) = Arguments.createMap().apply { putBoolean("granted", granted) putString("status", status) } override fun onActivityResult(activity: Activity, requestCode: Int, resultCode: Int, data: Intent?) = Unit override fun onNewIntent(intent: Intent) { SirrusNotificationEventDispatcher.emitOrStoreFromIntent( reactApplicationContext, intent ) } }