package com.vivocha.react import android.util.Log import com.facebook.react.bridge.ReadableArray import com.facebook.react.bridge.ReadableMap import com.facebook.react.bridge.ReadableType import com.facebook.react.bridge.WritableArray import com.facebook.react.bridge.WritableMap import com.facebook.react.bridge.WritableNativeArray import com.facebook.react.bridge.WritableNativeMap import com.vivocha.sdk.VivochaOptions import com.vivocha.sdk.internal.VivochaMedia import com.vivocha.sdk.model.VivochaConversation import com.vivocha.sdk.model.VivochaLocalization import com.vivocha.sdk.model.VivochaTheme import com.vivocha.sdk.model.chat.VivochaAgent import com.vivocha.sdk.model.chat.VivochaChatAck import com.vivocha.sdk.model.chat.VivochaMessage import com.vivocha.sdk.model.chat.VivochaPresence import com.vivocha.sdk.model.datacollection.VivochaDataCollection import com.vivocha.sdk.model.datacollection.VivochaDataCollectionField import com.vivocha.sdk.model.datacollection.VivochaDataCollectionForm import org.json.JSONArray import org.json.JSONObject import java.text.SimpleDateFormat import java.util.Date import java.util.Locale import java.util.TimeZone class Utils { companion object { private const val TAG = "VivochaUtils" fun jsonExport(json: Any?): Any? { return when { (json is JSONObject) -> jsonToMap(json) (json is JSONArray) -> jsonToArray(json) else -> null } } fun jsonToMap(json: JSONObject?): WritableMap? { if (json !is JSONObject) { return null } val map: WritableMap = WritableNativeMap() val iterator: Iterator = json.keys() while (iterator.hasNext()) { val key = iterator.next() when (val value: Any = json.get(key)) { is JSONObject -> map.putMap(key, jsonToMap(value)) is JSONArray -> map.putArray(key, jsonToArray(value)) is Boolean -> map.putBoolean(key, value) is Int -> map.putInt(key, value) is Double -> map.putDouble(key, value) is String -> map.putString(key, value) else -> map.putString(key, value.toString()) } } return map } fun jsonToArray(json: JSONArray): WritableArray { val array: WritableArray = WritableNativeArray() for (i in 0 until json.length()) { when (val value: Any = json.get(i)) { is JSONObject -> array.pushMap(jsonToMap(value)) is JSONArray -> array.pushArray(jsonToArray(value)) is Boolean -> array.pushBoolean(value) is Int -> array.pushInt(value) is Double -> array.pushDouble(value) is String -> array.pushString(value) else -> array.pushString(value.toString()) } } return array } fun mapToJson(readableMap: ReadableMap?): JSONObject? { if (readableMap !is ReadableMap) { return null } val obj = JSONObject() val iterator = readableMap.keySetIterator() while (iterator.hasNextKey()) { val key = iterator.nextKey() when (readableMap.getType(key)) { ReadableType.Null -> obj.put(key, JSONObject.NULL) ReadableType.Boolean -> obj.put(key, readableMap.getBoolean(key)) ReadableType.Number -> obj.put(key, readableMap.getDouble(key)) ReadableType.String -> obj.put(key, readableMap.getString(key)) ReadableType.Map -> obj.put(key, mapToJson(readableMap.getMap(key))) ReadableType.Array -> obj.put(key, readableMap.getArray(key)?.let { arrayToJson(it) }) } } return obj } fun arrayToJson(readableArray: ReadableArray?): JSONArray? { if (readableArray !is ReadableArray) { return null } val array = JSONArray() for (i in 0 until readableArray.size()) { when (readableArray.getType(i)) { ReadableType.Null -> {} ReadableType.Boolean -> array.put(readableArray.getBoolean(i)) ReadableType.Number -> array.put(readableArray.getDouble(i)) ReadableType.String -> array.put(readableArray.getString(i)) ReadableType.Map -> array.put(mapToJson(readableArray.getMap(i))) ReadableType.Array -> array.put(arrayToJson(readableArray.getArray(i))) } } return array } fun objToJson(obj: Any?): Any? { return when { (obj is ReadableArray) -> arrayToJson(obj) (obj is ReadableMap) -> mapToJson(obj) else -> null } } fun mapToOptions(options: ReadableMap?): VivochaOptions { val optionsBuilder = VivochaOptions.Builder() if (options is ReadableMap) { if (options.hasKey("blockSideTab")) { optionsBuilder.putBoolean(VivochaOptions.Keys.BLOCK_SIDE_TAB_BUTTON, options.getBoolean("blockSideTab")) } if (options.hasKey("audioVideo")) { optionsBuilder.putBoolean(VivochaOptions.Keys.DISABLE_AUDIO_VIDEO_FEATURE, !options.getBoolean("audioVideo")) } if (options.hasKey("cannedQuestion")) { optionsBuilder.putBoolean(VivochaOptions.Keys.DISABLE_CANNED_QUESTION_FEATURE, !options.getBoolean("cannedQuestion")) } if (options.hasKey("autoRestoreChatView")) { optionsBuilder.putBoolean(VivochaOptions.Keys.DISABLE_CHAT_VIEW_AUTO_RESTORING_ON_APP_KILL, !options.getBoolean("autoRestoreChatView")) } if (options.hasKey("fileTransfer")) { optionsBuilder.putBoolean(VivochaOptions.Keys.DISABLE_FILE_TRANSFER_FEATURE, !options.getBoolean("fileTransfer")) } if (options.hasKey("location")) { optionsBuilder.putBoolean(VivochaOptions.Keys.DISABLE_LOCATION_FEATURE, !options.getBoolean("location")) } if (options.hasKey("screenshot")) { optionsBuilder.putBoolean(VivochaOptions.Keys.DISABLE_SCREENSHOT_FEATURE, !options.getBoolean("screenshot")) } if (options.hasKey("developerMode")) { optionsBuilder.putBoolean(VivochaOptions.Keys.ENABLE_DEVELOPER_MODE, options.getBoolean("developerMode")) } if (options.hasKey("server")) { optionsBuilder.putString(VivochaOptions.Keys.SERVER_URL, options.getString("server")) } if (options.hasKey("waitToken")) { optionsBuilder.putBoolean(VivochaOptions.Keys.WAIT_FOR_TOKEN, options.getBoolean("waitToken")) } } return optionsBuilder.build() } fun dataCollectionToArray(dataCollection: VivochaDataCollection): WritableArray { val ret: WritableArray = WritableNativeArray() for (collectionForm in dataCollection.data) { val form: WritableMap = WritableNativeMap() form.putString("name", collectionForm.name) form.putString("desc", collectionForm.description) val data: WritableArray = WritableNativeArray() for (collectionField in collectionForm.fields) { val field: WritableMap = WritableNativeMap() field.putString("name", collectionField.name) field.putString("type", collectionField.type) field.putString("value", collectionField.value) field.putString("desc", collectionField.description) field.putBoolean("visible", collectionField.visible) field.putBoolean("checked", collectionField.checked) field.putBoolean("secure", collectionField.secure) data.pushMap(field) } form.putArray("data", data) ret.pushMap(form) } return ret } fun arrayToDataCollection(data: ReadableArray?): VivochaDataCollection? { if (data !is ReadableArray) { return null } val dataCollection: VivochaDataCollection = VivochaDataCollection() for (i in 0 until data.size()) { if (data.getType(i) != ReadableType.Map) { throw Exception("Invalid data") } val form = data.getMap(i) Log.d(TAG, "Form: $form") if (form == null) continue val dataForm: VivochaDataCollectionForm = VivochaDataCollectionForm() if (form.hasKey("name")) { if (form.getType("name") != ReadableType.String) { throw Exception("Invalid data") } dataForm.name = form.getString("name") } if (form.hasKey("desc")) { if (form.getType("desc") != ReadableType.String) { throw Exception("Invalid data") } dataForm.description = form.getString("desc") } if (!form.hasKey("data") || form.getType("data") != ReadableType.Array) { throw Exception("Invalid data") } val fields: ReadableArray? = form.getArray("data") if (fields != null) { for (j in 0 until fields.size()) { if (fields.getType(j) != ReadableType.Map) { throw Exception("Invalid data") } val field: ReadableMap? = fields.getMap(j) Log.d(TAG, "Field: $field") if (field == null) continue val dataField: VivochaDataCollectionField = VivochaDataCollectionField() if (field.hasKey("name")) { if (field.getType("name") != ReadableType.String) { throw Exception("Invalid data") } dataField.name = field.getString("name") } if (field.hasKey("type")) { if (field.getType("type") != ReadableType.String) { throw Exception("Invalid data") } dataField.type = field.getString("type") } if (field.hasKey("value")) { if (field.getType("value") != ReadableType.String) { throw Exception("Invalid data") } dataField.value = field.getString("value") } if (field.hasKey("desc")) { if (field.getType("desc") != ReadableType.String) { throw Exception("Invalid data") } dataField.description = field.getString("desc") } if (field.hasKey("visible")) { if (field.getType("visible") != ReadableType.Boolean) { throw Exception("Invalid data") } dataField.visible = field.getBoolean("visible") } if (field.hasKey("secure")) { if (field.getType("secure") != ReadableType.Boolean) { throw Exception("Invalid data") } dataField.setSecure(field.getBoolean("secure")) } if (field.hasKey("checked")) { if (field.getType("checked") != ReadableType.Boolean) { throw Exception("Invalid data") } dataField.checked = field.getBoolean("checked") } dataForm.addField(dataField) } } dataCollection.addForm(dataForm) } return dataCollection } fun conversationToJson(conversation: VivochaConversation): JSONObject { val data: JSONObject = JSONObject() .put("campaignId", conversation.campaignID) .put("conversationId", conversation.conversationID) return data } fun agentToJson(agent: VivochaAgent): JSONObject { val data: JSONObject = JSONObject() .put("isBot", agent.isBot) .put("name", agent.name) .put("avatar", agent.avatarURL) return data } fun presenceToJson(presence: VivochaPresence): JSONObject { val data: JSONObject = JSONObject() .put("isOnline", presence.isOnline) .put("isOutgoing", presence.isOutgoing) .put("isReceived", presence.isReceived) .put("isRead", presence.isRead) .put("type", presence.type) .put("agent", agentToJson(presence.agent)) return data } fun messageToJson(message: VivochaMessage): JSONObject { val data: JSONObject = JSONObject() .put("messageText", message.messageText) .put("id", message.elementID) .put("remotePeer", message.remotePeer) return data } private fun dateToIso8601(date: Date): String { val df: SimpleDateFormat = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.getDefault()) df.timeZone = TimeZone.getTimeZone("UTC") return df.format(date) } fun ackToJson(ack: VivochaChatAck): JSONObject { val data: JSONObject = JSONObject() .put("messageId", ack.messageId) .put("timestamp", dateToIso8601(ack.timestamp)) .put("type", when(ack.type) { VivochaChatAck.VivochaChatAckType.READ -> "read" VivochaChatAck.VivochaChatAckType.RECEIVED -> "received" else -> "" }) return data } fun mapToLocalization(language: String, localization: ReadableMap): VivochaLocalization { val loc: VivochaLocalization = VivochaLocalization(language) for (entry in localization.entryIterator) { loc.setTranslatedString(entry.key, entry.value.toString()) } return loc } fun themeToMap(theme: VivochaTheme?): WritableMap? { if (theme !is VivochaTheme) { return null } val map: WritableMap = WritableNativeMap() map.putString("chatBackgroundColor", theme.chatBackgroundColor) map.putString ("chatBackgroundName", theme.chatBackgroundName) map.putDouble("chatBubbleCornerRadius", theme.chatBubbleCornerRadius.toDouble()) map.putString("chatBubbleIncomingColor", theme.chatBubbleIncomingColor) map.putString("chatBubbleIncomingTextColor", theme.chatBubbleIncomingTextColor) map.putString("chatBubbleOutgoingColor", theme.chatBubbleOutgoingColor) map.putString("chatBubbleOutgoingTextColor", theme.chatBubbleOutgoingTextColor) map.putString("chatInputViewBackgroundColor", theme.chatInputViewBackgroundColor) map.putString("chatInputViewTextColor", theme.chatInputViewTextColor) map.putString("chatLoadingBackgroundColor", theme.chatLoadingBackgroundColor) map.putString("chatLoadingSpinnerColor", theme.chatLoadingSpinnerColor) map.putString("chatLoadingTextColor", theme.chatLoadingTextColor) map.putString("chatSendButtonBackgroundColor", theme.chatSendButtonBackgroundColor) map.putString("chatSendButtonTextColor", theme.chatSendButtonTextColor) map.putString("chatStatusTextColor", theme.chatStatusTextColor) map.putString("chatTopViewBackgroundColor", theme.chatTopViewBackgroundColor) map.putString("chatTopViewButtonTextColor", theme.chatTopViewButtonTextColor) map.putString("showReadReceiptOnChatBubble", theme.showReadReceiptOnChatBubble) map.putString("showReceiptsOnChatBubble", theme.showReceiptsOnChatBubble) map.putString("sideButtonBackgroundColor", theme.sideButtonBackgroundColor) map.putInt("sideButtonPosition", theme.sideButtonPosition) map.putInt("sideButtonSide", theme.sideButtonSide) map.putString("sideButtonTextColor", theme.sideButtonTextColor) return map } fun mapToTheme(map: ReadableMap): VivochaTheme { val theme: VivochaTheme = VivochaTheme() if (map.hasKey("chatBackgroundColor")) theme.chatBackgroundColor = map.getString("chatBackgroundColor") if (map.hasKey("chatBackgroundName")) theme.chatBackgroundName = map.getString("chatBackgroundName") if (map.hasKey("chatBubbleCornerRadius")) theme.chatBubbleCornerRadius = map.getDouble("chatBubbleCornerRadius").toFloat() if (map.hasKey("chatBubbleIncomingColor")) theme.chatBubbleIncomingColor = map.getString("chatBubbleIncomingColor") if (map.hasKey("chatBubbleIncomingTextColor")) theme.chatBubbleIncomingTextColor = map.getString("chatBubbleIncomingTextColor") if (map.hasKey("chatBubbleOutgoingColor")) theme.chatBubbleOutgoingColor = map.getString("chatBubbleOutgoingColor") if (map.hasKey("chatBubbleOutgoingTextColor")) theme.chatBubbleOutgoingTextColor = map.getString("chatBubbleOutgoingTextColor") if (map.hasKey("chatInputViewBackgroundColor")) theme.chatInputViewBackgroundColor = map.getString("chatInputViewBackgroundColor") if (map.hasKey("chatInputViewTextColor")) theme.chatInputViewTextColor = map.getString("chatInputViewTextColor") if (map.hasKey("chatLoadingBackgroundColor")) theme.chatLoadingBackgroundColor = map.getString("chatLoadingBackgroundColor") if (map.hasKey("chatLoadingSpinnerColor")) theme.chatLoadingSpinnerColor = map.getString("chatLoadingSpinnerColor") if (map.hasKey("chatLoadingTextColor")) theme.chatLoadingTextColor = map.getString("chatLoadingTextColor") if (map.hasKey("chatSendButtonBackgroundColor")) theme.chatSendButtonBackgroundColor = map.getString("chatSendButtonBackgroundColor") if (map.hasKey("chatSendButtonTextColor")) theme.chatSendButtonTextColor = map.getString("chatSendButtonTextColor") if (map.hasKey("chatStatusTextColor")) theme.chatStatusTextColor = map.getString("chatStatusTextColor") if (map.hasKey("chatTopViewBackgroundColor")) theme.chatTopViewBackgroundColor = map.getString("chatTopViewBackgroundColor") if (map.hasKey("chatTopViewButtonTextColor")) theme.chatTopViewButtonTextColor = map.getString("chatTopViewButtonTextColor") if (map.hasKey("showReadReceiptOnChatBubble")) theme.showReadReceiptOnChatBubble = map.getString("showReadReceiptOnChatBubble") if (map.hasKey("showReceiptsOnChatBubble")) theme.showReceiptsOnChatBubble = map.getString("showReceiptsOnChatBubble") if (map.hasKey("sideButtonBackgroundColor")) theme.sideButtonBackgroundColor = map.getString("sideButtonBackgroundColor") if (map.hasKey("sideButtonPosition")) theme.sideButtonPosition = map.getInt("sideButtonPosition") if (map.hasKey("sideButtonSide")) theme.sideButtonSide = map.getInt("sideButtonSide") if (map.hasKey("sideButtonTextColor")) theme.sideButtonTextColor = map.getString("sideButtonTextColor") return theme } fun mediaToMap(media: VivochaMedia): WritableMap { val map: WritableMap = WritableNativeMap() map.putBoolean("isLocalAudioEnabled", media.isLocalAudioEnabled) map.putBoolean("isLocalVideoEnabled", media.isLocalVideoEnabled) map.putBoolean("isRemoteAudioEnabled", media.isRemoteAudioEnabled) map.putBoolean("isRemoteVideoEnabled", media.isRemoteVideoEnabled) return(map) } } }