package com.dxareactnative import android.content.Context import android.util.Log import com.dxareactnative.navigation.parseScreenChangePayload import com.facebook.react.bridge.Arguments import com.facebook.react.bridge.Promise import com.facebook.react.bridge.ReactApplicationContext import com.facebook.react.bridge.ReactMethod import com.facebook.react.bridge.ReadableArray import com.facebook.react.bridge.ReadableMap import com.facebook.react.bridge.WritableArray import com.facebook.react.bridge.WritableMap import com.qualtrics.dxa.DxaConfiguration import com.qualtrics.dxa.InitializationResult import com.qualtrics.dxa.LogTag import com.qualtrics.dxa.QualtricsSR import com.qualtrics.dxa.ReplaySessionInfo import com.qualtrics.dxa.SessionStartResult import com.qualtrics.dxa.SessionStopResult import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch class DxaReactNativeModule internal constructor(context: ReactApplicationContext) : DxaReactNativeSpec(context) { override fun getName(): String { return NAME } // TODO: DXM-1895 Address isBlockingSynchronousMethod @ReactMethod(isBlockingSynchronousMethod = true) override fun setLoggingTags(tags: ReadableArray): WritableArray { val logTags: MutableSet = mutableSetOf() val tagsArray = tags.toArrayList() tagsArray.forEach { tag -> try { // Attempt to convert the tag string to a LogTag enum value logTags.add(LogTag.valueOf(tag.toString())) } catch (e: IllegalArgumentException) { // Log an error if the tag string doesn't match any LogTag enum value Log.println(Log.ERROR, "$TAG, ${LogTag.LIFECYCLE}", "Invalid log tag: $tag") } } QualtricsSR.instance().allowedLoggingTags = logTags return Arguments.createArray().apply { logTags.forEach { logTag -> pushString(logTag.name) } } } // TODO: DXM-1895 Address isBlockingSynchronousMethod @ReactMethod(isBlockingSynchronousMethod = true) override fun initializeProject( brandID: String, projectID: String, sdkVersion: String, reactNativeVersion: String ): WritableMap { setClientInfo(reactApplicationContext, sdkVersion, reactNativeVersion) val currentActivity = reactApplicationContext.currentActivity if (currentActivity == null) { Log.println(Log.ERROR, "$TAG, ${LogTag.LIFECYCLE}", "No current activity") return createArgumentMap("No current activity") } val initializationResult: InitializationResult = QualtricsSR.instance().initializeProject(currentActivity, brandID, projectID) return createArgumentMap(initializationResult.name) } private fun setClientInfo(context: Context, sdkVersion: String, reactNativeVersion: String) { val preferences = context.getSharedPreferences("SharedPrefs", Context.MODE_PRIVATE) with(preferences.edit()) { putString("QualtricsClientType", "DXAMobileAndroidReactNative") putString("QualtricsClientRNSdkVersion", sdkVersion) putString("QualtricsClientRNVersion", reactNativeVersion) apply() } } @ReactMethod override fun startRecording( dxaConfiguration: ReadableMap?, promise: Promise ) { CoroutineScope(Dispatchers.Default).launch { val configuration = DxaConfiguration(navigationTrackingTypes = null) when (val result = QualtricsSR.instance().startRecording(configuration)) { is SessionStartResult.Success -> promise.resolve( createArgumentMap( result.name, message = result.message, sessionInfo = result.sessionInfo ) ) is SessionStartResult.Fail -> promise.resolve( createArgumentMap( result.name, error = result.error ) ) else -> promise.resolve( createArgumentMap(result.name) ) } } } @ReactMethod override fun stopRecording(promise: Promise) { CoroutineScope(Dispatchers.Default).launch { when (val result = QualtricsSR.instance().stopRecording()) { is SessionStopResult.Fail -> promise.resolve( createArgumentMap( result.name, error = result.error ) ) else -> promise.resolve( createArgumentMap( result.name, ) ) } } } @ReactMethod override fun pauseRecording(promise: Promise) { CoroutineScope(Dispatchers.Default).launch { val result = QualtricsSR.instance().pauseRecording() val argumentMap = createArgumentMap(result.name) promise.resolve(argumentMap) } } @ReactMethod override fun resumeRecording(promise: Promise) { CoroutineScope(Dispatchers.Default).launch { val result = QualtricsSR.instance().resumeRecording() val argumentMap = createArgumentMap(result.name) promise.resolve(argumentMap) } } // TODO: DXM-1895 Address isBlockingSynchronousMethod @ReactMethod(isBlockingSynchronousMethod = true) override fun logError(message: String?): WritableMap { QualtricsSR.instance().logError(message) return createArgumentMap("Success") } fun createArgumentMap( result: String, error: String? = null, message: String? = null, sessionInfo: ReplaySessionInfo? = null ): WritableMap { val map = Arguments.createMap() map.putString("result", result) if (error != null) { map.putString("error", error) } if (message != null) { map.putString("message", message) } if (sessionInfo != null) { map.putString("sessionId", sessionInfo.sessionId) map.putString("sessionStartTimeMillis", sessionInfo.sessionStartTimeMillis.toString()) } return map } @ReactMethod override fun reportScreenChangeOnNative(screenChangePayload: ReadableMap?) { val (screenHierarchy, changeType, detectionType) = parseScreenChangePayload( screenChangePayload ) ?: return QualtricsSR.instance().reportScreenChange(screenHierarchy, changeType, detectionType) } companion object { const val NAME = "DxaReactNative" const val TAG = "Q-DXA" } }