Designing an expo react-native app to return a value to Collect

Thank you for following up on this LN

I found a lot of limitations using react native's intent options, and took a different route.
I'm using expo's option to create a native module, and that way I've been able to consume ODK Collect's API more directly using Kotlin.

Here are some examples (I'm new to Kotlin so there might be issues with this):

package expo.modules.odksync

import expo.modules.kotlin.modules.Module
import expo.modules.kotlin.modules.ModuleDefinition
import expo.modules.odksync.OdkSyncView
import android.content.Intent
import android.net.Uri
import android.provider.BaseColumns
import android.app.Activity
import expo.modules.kotlin.exception.CodedException


class OdkSyncModule : Module() {
  override fun definition() = ModuleDefinition {
    // Defines a JavaScript synchronous function that runs the native code on the JavaScript thread.
    Function("selectParcela") { datos: Map<String, Any> ->
      return@Function returnMultipleData(datos)
    }

    Function("getInstances") { 
       return@Function getInstances()
    }

      Function("openOdkForms") { 
       return@Function openOdkForms()
    }
  }

  private val context
  get() = requireNotNull(appContext.reactContext)

  private val currentActivity
  get() = appContext.activityProvider?.currentActivity ?: throw CodedException("Activity which was provided during module initialization is no longer available")

  private fun openOdkForms() {
      val myIntent = Intent(Intent.ACTION_VIEW)
      myIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
      myIntent.setType("vnd.android.cursor.dir/vnd.odk.form")
      context.startActivity(myIntent)
  }

  private fun getInstances(): List<Map<String, Any>> {

      val odkUrl = "content://org.odk.collect.android.provider.odk.instances/instances"
      val uri: Uri = Uri.parse(odkUrl)
        var cursor = context.contentResolver.query( uri, null, null, null, null)
        
        val odkFormData = mutableListOf<Map<String, Any>>()
        if (cursor != null) {
            try {
                while (cursor.moveToNext()) {
                    val dataMap = mutableMapOf<String, Any>()
                    var id = cursor.getInt(cursor.getColumnIndex(BaseColumns._ID))
                    dataMap["displayName"] = cursor.getString(cursor.getColumnIndex("displayName"))
                    dataMap["jrFormId"] = cursor.getString(cursor.getColumnIndex("jrFormId"))
                    dataMap["jrVersion"] = cursor.getString(cursor.getColumnIndex("jrVersion"))
                    dataMap["status"] = cursor.getString(cursor.getColumnIndex("status"))
                    odkFormData.add(dataMap)
                }
            } finally {
                cursor.close()
            }
            return odkFormData
        } else {
            val dataMap = mutableMapOf<String, Any>()
            dataMap["warning"] = "Unable to get forms"
            odkFormData.add(dataMap)
            return odkFormData
        }
        
  }

    private fun returnMultipleData(datos: Map<String, Any>) {
      if (currentActivity.getReferrer().toString() == "android-app://org.odk.collect.android") {
          val intent = Intent()

          val nomParcela = datos["nombre_parcela"]?.toString() ?: ""
          val uuidParcela = datos["uuid_parcela"]?.toString() ?: ""
          val idCoop = datos["id_cooperativa"]?.toString() ?: ""
          val nomCoop = datos["nombre_cooperativa"]?.toString() ?: ""

          intent.putExtra("id_parcela_nombre", nomParcela)
          intent.putExtra("id_parcela_uuid" , uuidParcela)
          intent.putExtra("id_cooperativa", idCoop)
          intent.putExtra("id_cooperativa_nombre", nomCoop)
          currentActivity.setResult(Activity.RESULT_OK, intent)
          currentActivity.finish()
      }
  }
}

With that I can now export functions to use in my react native code:

import OdkSyncModule from './src/OdkSyncModule';


export function selectParcela(data: Object): string {
  return OdkSyncModule.selectParcela(data);
}

export function getInstances(): Object {
  return OdkSyncModule.getInstances();
}


export function openOdkForms(): Object {
  return OdkSyncModule.openOdkForms();
}

export function getForms(): Object {
  return OdkSyncModule.getForms();
}
1 Like