package io.fullstack.firestack; import android.util.Log; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import com.facebook.react.bridge.ReactContext; import com.facebook.react.modules.core.DeviceEventManagerModule; import com.facebook.react.bridge.Arguments; import com.facebook.react.bridge.Callback; import com.facebook.react.bridge.WritableMap; import com.facebook.react.bridge.WritableArray; import com.facebook.react.bridge.ReadableMap; import com.facebook.react.bridge.ReadableArray; import com.facebook.react.bridge.ReadableMapKeySetIterator; import com.facebook.react.bridge.ReadableType; import com.google.firebase.database.DataSnapshot; public class FirestackUtils { private static final String TAG = "FirestackUtils"; // TODO NOTE public static void todoNote(final String tag, final String name, final Callback callback) { Log.e(tag, "The method " + name + " has not yet been implemented."); Log.e(tag, "Feel free to contribute to finish the method in the source."); WritableMap errorMap = Arguments.createMap(); errorMap.putString("error", "unimplemented"); callback.invoke(null, errorMap); } /** * send a JS event **/ public static void sendEvent(final ReactContext context, final String eventName, final WritableMap params) { if (context.hasActiveCatalystInstance()) { context .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class) .emit(eventName, params); } else { Log.d(TAG, "Waiting for CatalystInstance before sending event"); } } // snapshot public static WritableMap dataSnapshotToMap(String name, String path, DataSnapshot dataSnapshot) { WritableMap data = Arguments.createMap(); data.putString("key", dataSnapshot.getKey()); data.putBoolean("exists", dataSnapshot.exists()); data.putBoolean("hasChildren", dataSnapshot.hasChildren()); data.putDouble("childrenCount", dataSnapshot.getChildrenCount()); if (!dataSnapshot.hasChildren()) { Object value = dataSnapshot.getValue(); String type = value!=null ? value.getClass().getName() : ""; switch (type) { case "java.lang.Boolean": data.putBoolean("value", (Boolean)value); break; case "java.lang.Long": Long longVal = (Long) value; data.putDouble("value", (double)longVal); break; case "java.lang.Double": data.putDouble("value", (Double) value); break; case "java.lang.String": data.putString("value",(String) value); break; default: data.putString("value", null); } } else{ WritableMap valueMap = FirestackUtils.castSnapshotValue(dataSnapshot); data.putMap("value", valueMap); } // Child keys WritableArray childKeys = FirestackUtils.getChildKeys(dataSnapshot); data.putArray("childKeys", childKeys); Object priority = dataSnapshot.getPriority(); if (priority == null) { data.putString("priority", null); } else { data.putString("priority", priority.toString()); } WritableMap eventMap = Arguments.createMap(); eventMap.putString("eventName", name); eventMap.putMap("snapshot", data); eventMap.putString("path", path); return eventMap; } public static <Any> Any castSnapshotValue(DataSnapshot snapshot) { if (snapshot.hasChildren()) { WritableMap data = Arguments.createMap(); for (DataSnapshot child : snapshot.getChildren()) { Any castedChild = castSnapshotValue(child); switch (castedChild.getClass().getName()) { case "java.lang.Boolean": data.putBoolean(child.getKey(), (Boolean) castedChild); break; case "java.lang.Long": Long longVal = (Long) castedChild; data.putDouble(child.getKey(), (double)longVal); break; case "java.lang.Double": data.putDouble(child.getKey(), (Double) castedChild); break; case "java.lang.String": data.putString(child.getKey(), (String) castedChild); break; case "com.facebook.react.bridge.WritableNativeMap": data.putMap(child.getKey(), (WritableMap) castedChild); break; default: Log.w(TAG, "Invalid type: " + castedChild.getClass().getName()); break; } } return (Any) data; } else { if (snapshot.getValue() != null) { String type = snapshot.getValue().getClass().getName(); switch (type) { case "java.lang.Boolean": return (Any)(snapshot.getValue()); case "java.lang.Long": return (Any)(snapshot.getValue()); case "java.lang.Double": return (Any)(snapshot.getValue()); case "java.lang.String": return (Any)(snapshot.getValue()); default: Log.w(TAG, "Invalid type: "+type); return (Any) null; } } return (Any) null; } } public static WritableArray getChildKeys(DataSnapshot snapshot) { WritableArray childKeys = Arguments.createArray(); if (snapshot.hasChildren()) { for (DataSnapshot child : snapshot.getChildren()) { childKeys.pushString(child.getKey()); } } return childKeys; } public static Map<String, Object> recursivelyDeconstructReadableMap(ReadableMap readableMap) { ReadableMapKeySetIterator iterator = readableMap.keySetIterator(); Map<String, Object> deconstructedMap = new HashMap<>(); while (iterator.hasNextKey()) { String key = iterator.nextKey(); ReadableType type = readableMap.getType(key); switch (type) { case Null: deconstructedMap.put(key, null); break; case Boolean: deconstructedMap.put(key, readableMap.getBoolean(key)); break; case Number: deconstructedMap.put(key, readableMap.getDouble(key)); break; case String: deconstructedMap.put(key, readableMap.getString(key)); break; case Map: deconstructedMap.put(key, FirestackUtils.recursivelyDeconstructReadableMap(readableMap.getMap(key))); break; case Array: deconstructedMap.put(key, FirestackUtils.recursivelyDeconstructReadableArray(readableMap.getArray(key))); break; default: throw new IllegalArgumentException("Could not convert object with key: " + key + "."); } } return deconstructedMap; } public static List<Object> recursivelyDeconstructReadableArray(ReadableArray readableArray) { List<Object> deconstructedList = new ArrayList<>(readableArray.size()); for (int i = 0; i < readableArray.size(); i++) { ReadableType indexType = readableArray.getType(i); switch(indexType) { case Null: deconstructedList.add(i, null); break; case Boolean: deconstructedList.add(i, readableArray.getBoolean(i)); break; case Number: deconstructedList.add(i, readableArray.getDouble(i)); break; case String: deconstructedList.add(i, readableArray.getString(i)); break; case Map: deconstructedList.add(i, FirestackUtils.recursivelyDeconstructReadableMap(readableArray.getMap(i))); break; case Array: deconstructedList.add(i, FirestackUtils.recursivelyDeconstructReadableArray(readableArray.getArray(i))); break; default: throw new IllegalArgumentException("Could not convert object at index " + i + "."); } } return deconstructedList; } }