diff --git a/android/build.gradle b/android/build.gradle index 68dae367..bfd8398c 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -96,7 +96,7 @@ dependencies { // noinspection GradleDynamicVersion implementation "com.facebook.react:react-native:+" implementation "org.jetbrains.kotlin:kotlin-stdlib:${ReactNative.ext.getVersion("android", "kotlin")}" - implementation("com.sendbird.sdk:sendbird-calls:1.12.1") + implementation("com.sendbird.sdk:sendbird-calls:1.12.3") } ReactNative.shared.applyPackageVersion() diff --git a/android/src/main/java/com/sendbird/calls/reactnative/module/CallsCommonModule.kt b/android/src/main/java/com/sendbird/calls/reactnative/module/CallsCommonModule.kt index 62a4bcd1..22358cf7 100644 --- a/android/src/main/java/com/sendbird/calls/reactnative/module/CallsCommonModule.kt +++ b/android/src/main/java/com/sendbird/calls/reactnative/module/CallsCommonModule.kt @@ -1,8 +1,11 @@ package com.sendbird.calls.reactnative.module import com.facebook.react.bridge.Promise +import com.facebook.react.bridge.ReadableArray import com.facebook.react.bridge.ReadableMap +import com.facebook.react.bridge.WritableNativeMap import com.sendbird.calls.* +import com.sendbird.calls.internal.PushTokenType import com.sendbird.calls.reactnative.RNCallsInternalError import com.sendbird.calls.reactnative.extension.rejectCalls import com.sendbird.calls.reactnative.module.listener.CallsDirectCallListener @@ -104,7 +107,7 @@ class CallsCommonModule(private val root: CallsModule): CommonModule { override fun registerPushToken(token: String, unique: Boolean, promise: Promise) { RNCallsLogger.d("[CommonModule] registerPushToken()") - SendBirdCall.registerPushToken(token, unique) { error -> + SendBirdCall.registerPushToken(token, PushTokenType.FCM_VOIP, unique) { error -> error ?.let { promise.rejectCalls(it) @@ -117,7 +120,7 @@ class CallsCommonModule(private val root: CallsModule): CommonModule { override fun unregisterPushToken(token: String, promise: Promise) { RNCallsLogger.d("[CommonModule] unregisterPushToken()") - SendBirdCall.unregisterPushToken(token) { error -> + SendBirdCall.unregisterPushToken(token, PushTokenType.FCM_VOIP) { error -> error ?.let { promise.rejectCalls(it) @@ -219,4 +222,50 @@ class CallsCommonModule(private val root: CallsModule): CommonModule { promise.resolve(null) } } + + override fun updateCustomItems(callId: String, customItems: ReadableMap, promise: Promise) { + RNCallsLogger.d("[CommonModule] updateCustomItems($callId)") + val items = CallsUtils.convertMapToHashMap(customItems) + + SendBirdCall.updateCustomItems(callId, items) { updatedItems, affectedKeys, error -> + error?.let { + promise.rejectCalls(it) + } ?: run { + val result = WritableNativeMap() + result.putMap("updatedItems", CallsUtils.convertToJsMap(updatedItems as? Map<*, *> ?: emptyMap())) + result.putArray("affectedKeys", CallsUtils.convertToJsArray(affectedKeys as? List<*> ?: emptyList())) + promise.resolve(result) + } + } + } + + override fun deleteCustomItems(callId: String, customItemKeys: ReadableArray, promise: Promise) { + RNCallsLogger.d("[CommonModule] deleteCustomItems($callId)") + val keys = CallsUtils.convertArrayToSet(customItemKeys) + + SendBirdCall.deleteCustomItems(callId, keys) { updatedItems, affectedKeys, error -> + error?.let { + promise.rejectCalls(it) + } ?: run { + val result = WritableNativeMap() + result.putMap("updatedItems", CallsUtils.convertToJsMap(updatedItems as? Map<*, *> ?: emptyMap())) + result.putArray("affectedKeys", CallsUtils.convertToJsArray(affectedKeys as? List<*> ?: emptyList())) + promise.resolve(result) + } + } + } + + override fun deleteAllCustomItems(callId: String, promise: Promise) { + RNCallsLogger.d("[CommonModule] deleteAllCustomItems($callId)") + SendBirdCall.deleteAllCustomItems(callId) { updatedItems, affectedKeys, error -> + error?.let { + promise.rejectCalls(it) + } ?: run { + val result = WritableNativeMap() + result.putMap("updatedItems", CallsUtils.convertToJsMap(updatedItems as? Map<*, *> ?: emptyMap())) + result.putArray("affectedKeys", CallsUtils.convertToJsArray(affectedKeys as? List<*> ?: emptyList())) + promise.resolve(result) + } + } + } } diff --git a/android/src/main/java/com/sendbird/calls/reactnative/module/CallsDirectCallModule.kt b/android/src/main/java/com/sendbird/calls/reactnative/module/CallsDirectCallModule.kt index f461e181..b35a75a0 100644 --- a/android/src/main/java/com/sendbird/calls/reactnative/module/CallsDirectCallModule.kt +++ b/android/src/main/java/com/sendbird/calls/reactnative/module/CallsDirectCallModule.kt @@ -1,6 +1,7 @@ package com.sendbird.calls.reactnative.module import com.facebook.react.bridge.Promise +import com.facebook.react.bridge.ReadableArray import com.facebook.react.bridge.ReadableMap import com.sendbird.calls.AcceptParams import com.sendbird.calls.AudioDevice @@ -83,7 +84,7 @@ class CallsDirectCallModule(private val root: CallsModule): DirectCallModule { call.setRemoteVideoView(view.getSurface()) } } - + override fun muteMicrophone(type: String, identifier: String) { val from = "directCall/muteMicrophone" RNCallsLogger.d("[DirectCallModule] $from ($identifier)") @@ -200,4 +201,69 @@ class CallsDirectCallModule(private val root: CallsModule): DirectCallModule { CallsUtils.findDirectCall(identifier, from).resumeAudioTrack() } } + + override fun directCallUpdateCustomItems(callId: String, customItems: ReadableMap, promise: Promise) { + val from = "directCall/updateCustomItems" + RNCallsLogger.d("[DirectCallModule] $from ($callId)") + + CallsUtils.safeRun(promise) { + val call = CallsUtils.findDirectCall(callId, from) + val items = CallsUtils.convertMapToHashMap(customItems) + + call.updateCustomItems(items) { updatedItems, affectedKeys, error -> + if (error != null) { + promise.rejectCalls(error) + } else { + val result = CallsUtils.createMap().apply { + putMap("updatedItems", CallsUtils.convertHashMapToMap(updatedItems ?: hashMapOf())) + putArray("affectedKeys", CallsUtils.convertListToArray(affectedKeys ?: listOf())) + } + promise.resolve(result) + } + } + } + } + + override fun directCallDeleteCustomItems(callId: String, customItemKeys: ReadableArray, promise: Promise) { + val from = "directCall/deleteCustomItems" + RNCallsLogger.d("[DirectCallModule] $from ($callId)") + + CallsUtils.safeRun(promise) { + val call = CallsUtils.findDirectCall(callId, from) + val keys = CallsUtils.convertArrayToSet(customItemKeys) + + call.deleteCustomItems(keys) { updatedItems, affectedKeys, error -> + if (error != null) { + promise.rejectCalls(error) + } else { + val result = CallsUtils.createMap().apply { + putMap("updatedItems", CallsUtils.convertHashMapToMap(updatedItems ?: hashMapOf())) + putArray("affectedKeys", CallsUtils.convertListToArray(affectedKeys ?: listOf())) + } + promise.resolve(result) + } + } + } + } + + override fun directCallDeleteAllCustomItems(callId: String, promise: Promise) { + val from = "directCall/deleteAllCustomItems" + RNCallsLogger.d("[DirectCallModule] $from ($callId)") + + CallsUtils.safeRun(promise) { + val call = CallsUtils.findDirectCall(callId, from) + + call.deleteAllCustomItems { updatedItems, affectedKeys, error -> + if (error != null) { + promise.rejectCalls(error) + } else { + val result = CallsUtils.createMap().apply { + putMap("updatedItems", CallsUtils.convertHashMapToMap(updatedItems ?: hashMapOf())) + putArray("affectedKeys", CallsUtils.convertListToArray(affectedKeys ?: listOf())) + } + promise.resolve(result) + } + } + } + } } diff --git a/android/src/main/java/com/sendbird/calls/reactnative/module/CallsGroupCallModule.kt b/android/src/main/java/com/sendbird/calls/reactnative/module/CallsGroupCallModule.kt index 40a77cbc..3e3f96ba 100644 --- a/android/src/main/java/com/sendbird/calls/reactnative/module/CallsGroupCallModule.kt +++ b/android/src/main/java/com/sendbird/calls/reactnative/module/CallsGroupCallModule.kt @@ -1,6 +1,7 @@ package com.sendbird.calls.reactnative.module import com.facebook.react.bridge.Promise +import com.facebook.react.bridge.ReadableArray import com.facebook.react.bridge.ReadableMap import com.sendbird.calls.* import com.sendbird.calls.reactnative.RNCallsInternalError @@ -147,4 +148,69 @@ class CallsGroupCallModule: GroupCallModule { CallsUtils.findRoom(identifier, from).localParticipant?.resumeAudioTrack() } } + + override fun groupCallUpdateCustomItems(roomId: String, customItems: ReadableMap, promise: Promise) { + val from = "groupCall/updateCustomItems" + RNCallsLogger.d("[GroupCallModule] $from ($roomId)") + + CallsUtils.safeRun(promise) { + val room = CallsUtils.findRoom(roomId, from) + val items = CallsUtils.convertMapToHashMap(customItems) + + room.updateCustomItems(items) { updatedItems, affectedKeys, error -> + if (error != null) { + promise.rejectCalls(error) + } else { + val result = CallsUtils.createMap().apply { + putMap("updatedItems", CallsUtils.convertHashMapToMap(updatedItems ?: hashMapOf())) + putArray("affectedKeys", CallsUtils.convertListToArray(affectedKeys ?: listOf())) + } + promise.resolve(result) + } + } + } + } + + override fun groupCallDeleteCustomItems(roomId: String, customItemKeys: ReadableArray, promise: Promise) { + val from = "groupCall/deleteCustomItems" + RNCallsLogger.d("[GroupCallModule] $from ($roomId)") + + CallsUtils.safeRun(promise) { + val room = CallsUtils.findRoom(roomId, from) + val keys = CallsUtils.convertArrayToSet(customItemKeys) + + room.deleteCustomItems(keys) { updatedItems, affectedKeys, error -> + if (error != null) { + promise.rejectCalls(error) + } else { + val result = CallsUtils.createMap().apply { + putMap("updatedItems", CallsUtils.convertHashMapToMap(updatedItems ?: hashMapOf())) + putArray("affectedKeys", CallsUtils.convertListToArray(affectedKeys ?: listOf())) + } + promise.resolve(result) + } + } + } + } + + override fun groupCallDeleteAllCustomItems(roomId: String, promise: Promise) { + val from = "groupCall/deleteAllCustomItems" + RNCallsLogger.d("[GroupCallModule] $from ($roomId)") + + CallsUtils.safeRun(promise) { + val room = CallsUtils.findRoom(roomId, from) + // There is no deleteAllCustomItems API in Android native, so handled with deleteCustomItems. + room.deleteCustomItems(null) { updatedItems, affectedKeys, error -> + if (error != null) { + promise.rejectCalls(error) + } else { + val result = CallsUtils.createMap().apply { + putMap("updatedItems", CallsUtils.convertHashMapToMap(updatedItems ?: emptyMap())) + putArray("affectedKeys", CallsUtils.convertListToArray(affectedKeys ?: listOf())) + } + promise.resolve(result) + } + } + } + } } diff --git a/android/src/main/java/com/sendbird/calls/reactnative/module/CallsModule.kt b/android/src/main/java/com/sendbird/calls/reactnative/module/CallsModule.kt index b6b03c44..6bb56f6c 100644 --- a/android/src/main/java/com/sendbird/calls/reactnative/module/CallsModule.kt +++ b/android/src/main/java/com/sendbird/calls/reactnative/module/CallsModule.kt @@ -2,6 +2,7 @@ package com.sendbird.calls.reactnative.module import com.facebook.react.bridge.Promise import com.facebook.react.bridge.ReactApplicationContext +import com.facebook.react.bridge.ReadableArray import com.facebook.react.bridge.ReadableMap import com.sendbird.calls.DirectCall import com.sendbird.calls.RoomInvitation @@ -76,6 +77,9 @@ class CallsModule(val reactContext: ReactApplicationContext) : CallsModuleStruct override fun createRoom(params: ReadableMap, promise: Promise) = commonModule.createRoom(params, promise) override fun fetchRoomById(roomId: String, promise: Promise) = commonModule.fetchRoomById(roomId, promise) override fun getCachedRoomById(roomId: String, promise: Promise) = commonModule.getCachedRoomById(roomId, promise) + override fun updateCustomItems(callId: String, customItems: ReadableMap, promise: Promise) = commonModule.updateCustomItems(callId, customItems, promise) + override fun deleteCustomItems(callId: String, customItemKeys: ReadableArray, promise: Promise) = commonModule.deleteCustomItems(callId, customItemKeys, promise) + override fun deleteAllCustomItems(callId: String, promise: Promise) = commonModule.deleteAllCustomItems(callId, promise) /** Media Device control interface **/ override fun stopVideo(type: String, identifier: String) = getControllableModule(type).stopVideo(type, identifier) @@ -93,10 +97,16 @@ class CallsModule(val reactContext: ReactApplicationContext) : CallsModuleStruct override fun end(callId: String, promise: Promise)= directCallModule.end(callId, promise) override fun updateLocalVideoView(callId: String, videoViewId: Int)= directCallModule.updateLocalVideoView(callId, videoViewId) override fun updateRemoteVideoView(callId: String, videoViewId: Int)= directCallModule.updateRemoteVideoView(callId, videoViewId) + override fun directCallUpdateCustomItems(callId: String, customItems: ReadableMap, promise: Promise) = directCallModule.directCallUpdateCustomItems(callId, customItems, promise) + override fun directCallDeleteCustomItems(callId: String, customItemKeys: ReadableArray, promise: Promise) = directCallModule.directCallDeleteCustomItems(callId, customItemKeys, promise) + override fun directCallDeleteAllCustomItems(callId: String, promise: Promise) = directCallModule.directCallDeleteAllCustomItems(callId, promise) /** GroupCall module interface**/ override fun enter(roomId: String, options: ReadableMap, promise: Promise) = groupCallModule.enter(roomId, options, promise) override fun exit(roomId: String) = groupCallModule.exit(roomId) + override fun groupCallUpdateCustomItems(roomId: String, customItems: ReadableMap, promise: Promise) = groupCallModule.groupCallUpdateCustomItems(roomId, customItems, promise) + override fun groupCallDeleteCustomItems(roomId: String, customItemKeys: ReadableArray, promise: Promise) = groupCallModule.groupCallDeleteCustomItems(roomId, customItemKeys, promise) + override fun groupCallDeleteAllCustomItems(roomId: String, promise: Promise) = groupCallModule.groupCallDeleteAllCustomItems(roomId, promise) /** Queries **/ fun createDirectCallLogListQuery(params: ReadableMap, promise: Promise) = queries.createDirectCallLogListQuery(params, promise) diff --git a/android/src/main/java/com/sendbird/calls/reactnative/module/CallsModuleStruct.kt b/android/src/main/java/com/sendbird/calls/reactnative/module/CallsModuleStruct.kt index 9f6c26f2..665e9038 100644 --- a/android/src/main/java/com/sendbird/calls/reactnative/module/CallsModuleStruct.kt +++ b/android/src/main/java/com/sendbird/calls/reactnative/module/CallsModuleStruct.kt @@ -1,6 +1,7 @@ package com.sendbird.calls.reactnative.module import com.facebook.react.bridge.Promise +import com.facebook.react.bridge.ReadableArray import com.facebook.react.bridge.ReadableMap interface CallsModuleStruct: CommonModule, DirectCallModule, GroupCallModule { } @@ -29,6 +30,10 @@ interface CommonModule { fun createRoom(params: ReadableMap, promise: Promise) fun fetchRoomById(roomId: String, promise: Promise) fun getCachedRoomById(roomId: String, promise: Promise) + + fun updateCustomItems(callId: String, customItems: ReadableMap, promise: Promise) + fun deleteCustomItems(callId: String, customItemKeys: ReadableArray, promise: Promise) + fun deleteAllCustomItems(callId: String, promise: Promise) } interface DirectCallModule: MediaDeviceControl { @@ -36,11 +41,17 @@ interface DirectCallModule: MediaDeviceControl { fun end(callId: String, promise: Promise) fun updateLocalVideoView(callId: String, videoViewId: Int) fun updateRemoteVideoView(callId: String, videoViewId: Int) + fun directCallUpdateCustomItems(callId: String, customItems: ReadableMap, promise: Promise) + fun directCallDeleteCustomItems(callId: String, customItemKeys: ReadableArray, promise: Promise) + fun directCallDeleteAllCustomItems(callId: String, promise: Promise) } interface GroupCallModule: MediaDeviceControl { fun enter(roomId: String, options: ReadableMap, promise: Promise) fun exit(roomId: String) + fun groupCallUpdateCustomItems(roomId: String, customItems: ReadableMap, promise: Promise) + fun groupCallDeleteCustomItems(roomId: String, customItemKeys: ReadableArray, promise: Promise) + fun groupCallDeleteAllCustomItems(roomId: String, promise: Promise) } enum class ControllableModuleType { @@ -58,4 +69,4 @@ interface MediaDeviceControl { fun selectVideoDevice(type: String, identifier: String, device: ReadableMap, promise: Promise) fun resumeVideoCapturer(type: String, identifier: String) fun resumeAudioTrack(type: String, identifier: String) -} \ No newline at end of file +} diff --git a/android/src/main/java/com/sendbird/calls/reactnative/utils/CallsUtils.kt b/android/src/main/java/com/sendbird/calls/reactnative/utils/CallsUtils.kt index f7a1a7f2..57edfd4a 100644 --- a/android/src/main/java/com/sendbird/calls/reactnative/utils/CallsUtils.kt +++ b/android/src/main/java/com/sendbird/calls/reactnative/utils/CallsUtils.kt @@ -252,4 +252,50 @@ object CallsUtils { return SendBirdCall.getCachedRoomById(roomId) ?: throw RNCallsInternalError(from, RNCallsInternalError.Type.NOT_FOUND_ROOM) } + fun createMap(): WritableNativeMap { + return WritableNativeMap() + } + + fun convertMapToHashMap(map: ReadableMap): HashMap { + val hashMap = HashMap() + val iterator = map.keySetIterator() + while (iterator.hasNextKey()) { + val key = iterator.nextKey() + hashMap[key] = map.getString(key) ?: "" + } + return hashMap + } + + fun convertHashMapToMap(hashMap: Map): WritableNativeMap { + val map = WritableNativeMap() + for ((key, value) in hashMap) { + map.putString(key, value) + } + return map + } + + fun convertArrayToSet(array: ReadableArray): Set { + val set = mutableSetOf() + for (i in 0 until array.size()) { + set.add(array.getString(i)) + } + return set + } + + fun convertArrayToList(array: ReadableArray): List { + val list = mutableListOf() + for (i in 0 until array.size()) { + list.add(array.getString(i)) + } + return list + } + + fun convertListToArray(list: List): WritableNativeArray { + val array = WritableNativeArray() + for (item in list) { + array.pushString(item) + } + return array + } + } diff --git a/android/src/oldarch/java/com/sendbird/calls/reactnative/RNSendbirdCallsModule.kt b/android/src/oldarch/java/com/sendbird/calls/reactnative/RNSendbirdCallsModule.kt index b0b7bd2f..31844dec 100644 --- a/android/src/oldarch/java/com/sendbird/calls/reactnative/RNSendbirdCallsModule.kt +++ b/android/src/oldarch/java/com/sendbird/calls/reactnative/RNSendbirdCallsModule.kt @@ -75,6 +75,12 @@ class RNSendbirdCallsModule(private val reactContext: ReactApplicationContext) : override fun fetchRoomById(roomId: String, promise: Promise) = module.fetchRoomById(roomId, promise) @ReactMethod override fun getCachedRoomById(roomId: String, promise: Promise) = module.getCachedRoomById(roomId, promise) + @ReactMethod + override fun updateCustomItems(callId: String, customItems: ReadableMap, promise: Promise) = module.updateCustomItems(callId, customItems, promise) + @ReactMethod + override fun deleteCustomItems(callId: String, customItemKeys: ReadableArray, promise: Promise) = module.deleteCustomItems(callId, customItemKeys, promise) + @ReactMethod + override fun deleteAllCustomItems(callId: String, promise: Promise) = module.deleteAllCustomItems(callId, promise) /** MediaDevice Control **/ @ReactMethod @@ -106,12 +112,26 @@ class RNSendbirdCallsModule(private val reactContext: ReactApplicationContext) : @ReactMethod override fun updateRemoteVideoView(callId: String, videoViewId: Int) = module.updateRemoteVideoView(callId, videoViewId) + @ReactMethod + override fun directCallUpdateCustomItems(callId: String, customItems: ReadableMap, promise: Promise) = module.directCallUpdateCustomItems(callId, customItems, promise) + @ReactMethod + override fun directCallDeleteCustomItems(callId: String, customItemKeys: ReadableArray, promise: Promise) = module.directCallDeleteCustomItems(callId, customItemKeys, promise) + @ReactMethod + override fun directCallDeleteAllCustomItems(callId: String, promise: Promise) = module.directCallDeleteAllCustomItems(callId, promise) + /** GroupCall - Room **/ @ReactMethod override fun enter(roomId: String, options: ReadableMap, promise: Promise) = module.enter(roomId, options, promise) @ReactMethod override fun exit(roomId: String) = module.exit(roomId) + @ReactMethod + override fun groupCallUpdateCustomItems(roomId: String, customItems: ReadableMap, promise: Promise) = module.groupCallUpdateCustomItems(roomId, customItems, promise) + @ReactMethod + override fun groupCallDeleteCustomItems(roomId: String, customItemKeys: ReadableArray, promise: Promise) = module.groupCallDeleteCustomItems(roomId, customItemKeys, promise) + @ReactMethod + override fun groupCallDeleteAllCustomItems(roomId: String, promise: Promise) = module.groupCallDeleteAllCustomItems(roomId, promise) + /** Queries **/ @ReactMethod fun createDirectCallLogListQuery(params: ReadableMap, promise: Promise) = module.createDirectCallLogListQuery(params, promise) diff --git a/ios/Modules/CallsModule+Common.swift b/ios/Modules/CallsModule+Common.swift index 3fc4ab17..e5187948 100644 --- a/ios/Modules/CallsModule+Common.swift +++ b/ios/Modules/CallsModule+Common.swift @@ -37,6 +37,10 @@ protocol CallsCommonModuleProtocol { func fetchRoomById(_ roomId: String, _ promise: Promise) func getCachedRoomById(_ roomId: String, _ promise: Promise) func createRoom(_ params: [String: Any], _ promise: Promise) + + func updateCustomItems(_ callId: String, _ customItems: [String: String], _ promise: Promise) + func deleteCustomItems(_ callId: String, _ customItemKeys: [String], _ promise: Promise) + func deleteAllCustomItems(_ callId: String, _ promise: Promise) } class CallsCommonModule: CallsBaseModule, CallsCommonModuleProtocol { @@ -227,4 +231,46 @@ class CallsCommonModule: CallsBaseModule, CallsCommonModuleProtocol { } } } + + func updateCustomItems(_ callId: String, _ customItems: [String: String], _ promise: Promise) { + SendBirdCall.updateCustomItems(callId: callId, customItems: customItems) { result, affectedKeys, error in + if let error = error { + promise.reject(error) + } else { + let customItemsResult: [String: Any] = [ + "updatedItems": result ?? [:], + "affectedKeys": affectedKeys ?? [] + ] + promise.resolve(customItemsResult) + } + } + } + + func deleteCustomItems(_ callId: String, _ customItemKeys: [String], _ promise: Promise) { + SendBirdCall.deleteCustomItems(callId: callId, customItemKeys: customItemKeys) { result, affectedKeys, error in + if let error = error { + promise.reject(error) + } else { + let customItemsResult: [String: Any] = [ + "updatedItems": result ?? [:], + "affectedKeys": affectedKeys ?? [] + ] + promise.resolve(customItemsResult) + } + } + } + + func deleteAllCustomItems(_ callId: String, _ promise: Promise) { + SendBirdCall.deleteAllCustomItems(callId: callId) { result, affectedKeys, error in + if let error = error { + promise.reject(error) + } else { + let customItemsResult: [String: Any] = [ + "updatedItems": result ?? [:], + "affectedKeys": affectedKeys ?? [] + ] + promise.resolve(customItemsResult) + } + } + } } diff --git a/ios/Modules/CallsModule+DirectCall.swift b/ios/Modules/CallsModule+DirectCall.swift index a0adf9a3..8aedf303 100644 --- a/ios/Modules/CallsModule+DirectCall.swift +++ b/ios/Modules/CallsModule+DirectCall.swift @@ -16,6 +16,9 @@ protocol CallsDirectCallModuleProtocol: MediaDeviceControlProtocol { func end(_ callId: String, _ promise: Promise) func updateLocalVideoView(_ callId: String, _ videoViewId: NSNumber) func updateRemoteVideoView(_ callId: String, _ videoViewId: NSNumber) + func directCallUpdateCustomItems(_ callId: String, _ customItems: [String: String], _ promise: Promise) + func directCallDeleteCustomItems(_ callId: String, _ customItemKeys: [String], _ promise: Promise) + func directCallDeleteAllCustomItems(_ callId: String, _ promise: Promise) } // MARK: DirectCallMethods @@ -57,6 +60,60 @@ class CallsDirectCallModule: CallsBaseModule, CallsDirectCallModuleProtocol { directCall.updateRemoteVideoView(videoView.surface) } } + + func directCallUpdateCustomItems(_ callId: String, _ customItems: [String: String], _ promise: Promise) { + if let directCall = try? CallsUtils.findDirectCallBy(callId) { + directCall.updateCustomItems(customItems: customItems) { updatedItems, affectedKeys, error in + if let error = error { + promise.reject(error) + } else { + let result: [String: Any] = [ + "updatedItems": updatedItems ?? [:], + "affectedKeys": affectedKeys ?? [] + ] + promise.resolve(result) + } + } + } else { + promise.reject(RNCallsInternalError.notFoundDirectCall("directCall/updateCustomItems")) + } + } + + func directCallDeleteCustomItems(_ callId: String, _ customItemKeys: [String], _ promise: Promise) { + if let directCall = try? CallsUtils.findDirectCallBy(callId) { + directCall.deleteCustomItems(customItemKeys: customItemKeys) { updatedItems, affectedKeys, error in + if let error = error { + promise.reject(error) + } else { + let result: [String: Any] = [ + "updatedItems": updatedItems ?? [:], + "affectedKeys": affectedKeys ?? [] + ] + promise.resolve(result) + } + } + } else { + promise.reject(RNCallsInternalError.notFoundDirectCall("directCall/deleteCustomItems")) + } + } + + func directCallDeleteAllCustomItems(_ callId: String, _ promise: Promise) { + if let directCall = try? CallsUtils.findDirectCallBy(callId) { + directCall.deleteAllCustomItems { updatedItems, affectedKeys, error in + if let error = error { + promise.reject(error) + } else { + let result: [String: Any] = [ + "updatedItems": updatedItems ?? [:], + "affectedKeys": affectedKeys ?? [] + ] + promise.resolve(result) + } + } + } else { + promise.reject(RNCallsInternalError.notFoundDirectCall("directCall/deleteAllCustomItems")) + } + } } // MARK: DirectCall MediaDeviceControl diff --git a/ios/Modules/CallsModule+GroupCall.swift b/ios/Modules/CallsModule+GroupCall.swift index 688b9595..66d0db09 100644 --- a/ios/Modules/CallsModule+GroupCall.swift +++ b/ios/Modules/CallsModule+GroupCall.swift @@ -13,6 +13,9 @@ import CallKit protocol CallsGroupCallModuleProtocol: MediaDeviceControlProtocol { func enter(_ roomId: String, _ options: [String: Any?], _ promise: Promise) func exit(_ roomId: String) + func groupCallUpdateCustomItems(_ roomId: String, _ customItems: [String: String], _ promise: Promise) + func groupCallDeleteCustomItems(_ roomId: String, _ customItemKeys: [String], _ promise: Promise) + func groupCallDeleteAllCustomItems(_ roomId: String, _ promise: Promise) } // MARK: GroupCallMethods @@ -21,12 +24,12 @@ class CallsGroupCallModule: CallsBaseModule, CallsGroupCallModuleProtocol { if let room = try? CallsUtils.findRoom(roomId) { var isAudioEnabled = true var isVideoEnabled = true - + if let audioEnabled = options["audioEnabled"] as? Bool { isAudioEnabled = audioEnabled } if let videoEnabled = options["videoEnabled"] as? Bool { isVideoEnabled = videoEnabled } - + let params = Room.EnterParams(isVideoEnabled: isVideoEnabled, isAudioEnabled: isAudioEnabled) - + room.enter(with: params) { error in if let error = error { promise.reject(error) @@ -38,12 +41,63 @@ class CallsGroupCallModule: CallsBaseModule, CallsGroupCallModuleProtocol { promise.reject(RNCallsInternalError.notFoundRoom("groupCall/enter")) } } - + func exit(_ roomId: String) { CallsUtils.safeRun { try CallsUtils.findRoom(roomId).exit() } } + + func groupCallUpdateCustomItems(_ roomId: String, _ customItems: [String: String], _ promise: Promise) { + CallsUtils.safeRun { + let room = try CallsUtils.findRoom(roomId) + room.updateCustomItems(customItems: customItems) { customItems, affectedKeys, error in + if let error = error { + promise.reject(error) + } else { + let result = [ + "updatedItems": customItems ?? [:], + "affectedKeys": affectedKeys ?? [] + ] as [String : Any] + promise.resolve(result) + } + } + } + } + + func groupCallDeleteCustomItems(_ roomId: String, _ customItemKeys: [String], _ promise: Promise) { + CallsUtils.safeRun { + let room = try CallsUtils.findRoom(roomId) + room.deleteCustomItems(customItemKeys: customItemKeys.compactMap { $0 }) { customItems, affectedKeys, error in + if let error = error { + promise.reject(error) + } else { + let result = [ + "updatedItems": customItems ?? [:], + "affectedKeys": affectedKeys ?? [] + ] as [String : Any] + promise.resolve(result) + } + } + } + } + + func groupCallDeleteAllCustomItems(_ roomId: String, _ promise: Promise) { + CallsUtils.safeRun { + let room = try CallsUtils.findRoom(roomId) + room.deleteAllCustomItems { customItems, affectedKeys, error in + if let error = error { + promise.reject(error) + } else { + let result = [ + "updatedItems": customItems ?? [:], + "affectedKeys": affectedKeys ?? [] + ] as [String : Any] + promise.resolve(result) + } + } + } + } } // MARK: GroupCall MediaDeviceControl @@ -60,37 +114,38 @@ extension CallsGroupCallModule { } } } - + func startVideo(_ type: String, _ roomId: String) { CallsUtils.safeRun { let room = try CallsUtils.findRoom(roomId) room.localParticipant?.startVideo() } } - + func stopVideo(_ type: String, _ roomId: String) { CallsUtils.safeRun { let room = try CallsUtils.findRoom(roomId) room.localParticipant?.stopVideo() } } - + func muteMicrophone(_ type: String, _ roomId: String) { CallsUtils.safeRun { let room = try CallsUtils.findRoom(roomId) room.localParticipant?.muteMicrophone() } } - + func unmuteMicrophone(_ type: String, _ roomId: String) { CallsUtils.safeRun { let room = try CallsUtils.findRoom(roomId) room.localParticipant?.unmuteMicrophone() } } - + func selectVideoDevice(_ type: String, _ roomId: String, _ device: [String: String], _ promise: Promise) { // NOOP promise.resolve() } } + diff --git a/ios/Modules/CallsModule.swift b/ios/Modules/CallsModule.swift index 63e90ee1..4eed729d 100644 --- a/ios/Modules/CallsModule.swift +++ b/ios/Modules/CallsModule.swift @@ -20,35 +20,35 @@ class CallsBaseModule: NSObject { class CallsModule: SendBirdCallDelegate { internal var queries = CallsQueries() - + internal lazy var commonModule: CallsCommonModule = { CallsCommonModule(root: self) }() - + internal lazy var directCallModule: CallsDirectCallModule = { CallsDirectCallModule(root: self) }() - + internal lazy var groupCallModule: CallsGroupCallModule = { CallsGroupCallModule(root: self) }() - + internal var initialized: Bool { get { return SendBirdCall.appId != nil } } - + init() { SendBirdCall.addDelegate(self, identifier: "sendbird.call.listener") } - + func invalidate() { SendBirdCall.removeDirectCallSound(forType: .ringing) SendBirdCall.removeDirectCallSound(forType: .dialing) SendBirdCall.removeDirectCallSound(forType: .reconnected) SendBirdCall.removeDirectCallSound(forType: .reconnecting) - + if(initialized){ SendBirdCall.deauthenticate(completionHandler: nil) SendBirdCall.removeAllDelegates() @@ -57,7 +57,7 @@ class CallsModule: SendBirdCallDelegate { GroupCallDelegate.invalidate() } } - + func didStartRinging(_ call: DirectCall) { DispatchQueue.main.async { CallsEvents.shared.sendEvent(.default(.onRinging), CallsUtils.convertDirectCallToDict(call)) @@ -71,74 +71,86 @@ extension CallsModule: CallsCommonModuleProtocol { func setLoggerLevel(_ level: String) { commonModule.setLoggerLevel(level) } - + func addDirectCallSound(_ type: String, _ fileName: String) { commonModule.addDirectCallSound(type, fileName) } - + func removeDirectCallSound(_ type: String) { commonModule.removeDirectCallSound(type) } - + func setDirectCallDialingSoundOnWhenSilentOrVibrateMode(_ enabled: Bool) { commonModule.setDirectCallDialingSoundOnWhenSilentOrVibrateMode(enabled) } - + func getCurrentUser(_ promise: Promise) { commonModule.getCurrentUser(promise) } - + func getOngoingCalls(_ promise: Promise) { commonModule.getOngoingCalls(promise) } - + func getDirectCall(_ callIdOrUUID: String, _ promise: Promise) { commonModule.getDirectCall(callIdOrUUID, promise) } - + func initialize(_ appId: String) -> Bool { return commonModule.initialize(appId) } - + func authenticate(_ authParams: [String: Any?], _ promise: Promise) { commonModule.authenticate(authParams, promise) } - + func deauthenticate(_ promise: Promise) { commonModule.deauthenticate(promise) } - + func registerPushToken(_ token: String, _ unique: Bool, _ promise: Promise) { commonModule.registerPushToken(token, unique, promise) } - + func unregisterPushToken(_ token: String, _ promise: Promise) { commonModule.unregisterPushToken(token, promise) } - + func registerVoIPPushToken(_ token: String, _ unique: Bool, _ promise: Promise) { commonModule.registerVoIPPushToken(token, unique, promise) } - + func unregisterVoIPPushToken(_ token: String, _ promise: Promise) { commonModule.unregisterVoIPPushToken(token, promise) } - + func dial(_ calleeId: String, _ isVideoCall: Bool, _ options: [String: Any?], _ promise: Promise) { commonModule.dial(calleeId, isVideoCall, options, promise) } - + func fetchRoomById(_ roomId: String, _ promise: Promise) { commonModule.fetchRoomById(roomId, promise) } - + func getCachedRoomById(_ roomId: String, _ promise: Promise) { commonModule.getCachedRoomById(roomId, promise) } - + func createRoom(_ params: [String: Any], _ promise: Promise) { commonModule.createRoom(params, promise) } + + func updateCustomItems(_ callId: String, _ customItems: [String: String], _ promise: Promise) { + commonModule.updateCustomItems(callId, customItems, promise) + } + + func deleteCustomItems(_ callId: String, _ customItemKeys: [String], _ promise: Promise) { + commonModule.deleteCustomItems(callId, customItemKeys, promise) + } + + func deleteAllCustomItems(_ callId: String, _ promise: Promise) { + commonModule.deleteAllCustomItems(callId, promise) + } } // MARK: MediaDeviceControl extension @@ -146,30 +158,30 @@ extension CallsModule { func switchCamera(_ type: String, _ identifier: String, _ promise: Promise) { getControllableModule(type)?.switchCamera(type, identifier, promise) } - + func startVideo(_ type: String, _ identifier: String) { getControllableModule(type)?.startVideo(type, identifier) } - + func stopVideo(_ type: String, _ identifier: String) { getControllableModule(type)?.stopVideo(type, identifier) } - + func muteMicrophone(_ type: String, _ identifier: String) { getControllableModule(type)?.muteMicrophone(type, identifier) } - + func unmuteMicrophone(_ type: String, _ identifier: String) { getControllableModule(type)?.unmuteMicrophone(type, identifier) } - + func selectVideoDevice(_ type: String, _ identifier: String, _ device: [String: String], _ promise: Promise) { getControllableModule(type)?.selectVideoDevice(type, identifier, device, promise) } - + private func getControllableModule(_ type: String) -> MediaDeviceControlProtocol? { guard let type = ControllableModuleType(fromString: type) else { return nil } - + switch(type) { case .directCall: return directCallModule @@ -184,18 +196,30 @@ extension CallsModule: CallsDirectCallModuleProtocol { func accept(_ callId: String, _ options: [String : Any?], _ holdActiveCall: Bool, _ promise: Promise) { directCallModule.accept(callId, options, holdActiveCall, promise) } - + func end(_ callId: String, _ promise: Promise) { directCallModule.end(callId, promise) } - + func updateLocalVideoView(_ callId: String, _ videoViewId: NSNumber) { directCallModule.updateLocalVideoView(callId, videoViewId) } - + func updateRemoteVideoView(_ callId: String, _ videoViewId: NSNumber) { directCallModule.updateRemoteVideoView(callId, videoViewId) } + + func directCallUpdateCustomItems(_ callId: String, _ customItems: [String: String], _ promise: Promise) { + directCallModule.directCallUpdateCustomItems(callId, customItems, promise) + } + + func directCallDeleteCustomItems(_ callId: String, _ customItemKeys: [String], _ promise: Promise) { + directCallModule.directCallDeleteCustomItems(callId, customItemKeys, promise) + } + + func directCallDeleteAllCustomItems(_ callId: String, _ promise: Promise) { + directCallModule.directCallDeleteAllCustomItems(callId, promise) + } } // MARK: GroupCallModule extension @@ -203,10 +227,22 @@ extension CallsModule: CallsGroupCallModuleProtocol { func enter(_ roomId: String, _ options: [String : Any?], _ promise: Promise) { groupCallModule.enter(roomId, options, promise) } - + func exit(_ roomId: String) { groupCallModule.exit(roomId) } + + func groupCallUpdateCustomItems(_ roomId: String, _ customItems: [String: String], _ promise: Promise) { + groupCallModule.groupCallUpdateCustomItems(roomId, customItems, promise) + } + + func groupCallDeleteCustomItems(_ roomId: String, _ customItemKeys: [String], _ promise: Promise) { + groupCallModule.groupCallDeleteCustomItems(roomId, customItemKeys, promise) + } + + func groupCallDeleteAllCustomItems(_ roomId: String, _ promise: Promise) { + groupCallModule.groupCallDeleteAllCustomItems(roomId, promise) + } } // MARK: Queries extension diff --git a/ios/RNSendbirdCalls.m b/ios/RNSendbirdCalls.m index c713dd8e..b08bf975 100644 --- a/ios/RNSendbirdCalls.m +++ b/ios/RNSendbirdCalls.m @@ -126,6 +126,23 @@ @interface RCT_EXTERN_MODULE(RNSendbirdCalls, NSObject) : (RCTPromiseResolveBlock)resolve : (RCTPromiseRejectBlock)reject) +RCT_EXTERN_METHOD(updateCustomItems + : (NSString *)callId + : (NSDictionary *)customItems + : (RCTPromiseResolveBlock)resolve + : (RCTPromiseRejectBlock)reject) + +RCT_EXTERN_METHOD(deleteCustomItems + : (NSString *)callId + : (NSArray *)customItemKeys + : (RCTPromiseResolveBlock)resolve + : (RCTPromiseRejectBlock)reject) + +RCT_EXTERN_METHOD(deleteAllCustomItems + : (NSString *)callId + : (RCTPromiseResolveBlock)resolve + : (RCTPromiseRejectBlock)reject) + // MARK: - SendbirdCalls: DirectCall RCT_EXTERN_METHOD(accept : (NSString *)callId @@ -147,6 +164,23 @@ @interface RCT_EXTERN_MODULE(RNSendbirdCalls, NSObject) : (NSString *)callId : (nonnull NSNumber *)videoViewId) +RCT_EXTERN_METHOD(directCallUpdateCustomItems + : (NSString *)callId + : (NSDictionary *)customItems + : (RCTPromiseResolveBlock)resolve + : (RCTPromiseRejectBlock)reject) + +RCT_EXTERN_METHOD(directCallDeleteCustomItems + : (NSString *)callId + : (NSArray *)customItemKeys + : (RCTPromiseResolveBlock)resolve + : (RCTPromiseRejectBlock)reject) + +RCT_EXTERN_METHOD(directCallDeleteAllCustomItems + : (NSString *)callId + : (RCTPromiseResolveBlock)resolve + : (RCTPromiseRejectBlock)reject) + // MARK: - SendbirdCalls: GroupCall RCT_EXTERN_METHOD(enter : (NSString *)roomId @@ -157,6 +191,23 @@ @interface RCT_EXTERN_MODULE(RNSendbirdCalls, NSObject) RCT_EXTERN_METHOD(exit : (NSString *)roomId) +RCT_EXTERN_METHOD(groupCallUpdateCustomItems + : (NSString *)roomId + : (NSDictionary *)customItems + : (RCTPromiseResolveBlock)resolve + : (RCTPromiseRejectBlock)reject) + +RCT_EXTERN_METHOD(groupCallDeleteCustomItems + : (NSString *)roomId + : (NSArray *)customItemKeys + : (RCTPromiseResolveBlock)resolve + : (RCTPromiseRejectBlock)reject) + +RCT_EXTERN_METHOD(groupCallDeleteAllCustomItems + : (NSString *)roomId + : (RCTPromiseResolveBlock)resolve + : (RCTPromiseRejectBlock)reject) + // MARK: - SendbirdCalls: MediaDeviceControl RCT_EXTERN_METHOD(switchCamera : (NSString *)type diff --git a/ios/RNSendbirdCalls.swift b/ios/RNSendbirdCalls.swift index b0103c30..0f2d626f 100644 --- a/ios/RNSendbirdCalls.swift +++ b/ios/RNSendbirdCalls.swift @@ -159,6 +159,18 @@ extension RNSendbirdCalls { @objc func createRoom(_ params: [String: Any], _ resolve: @escaping RCTPromiseResolveBlock, _ reject: @escaping RCTPromiseRejectBlock) { module.createRoom(params, Promise(resolve, reject)) } + + @objc func updateCustomItems(_ callId: String, _ customItems: [String: String], _ resolve: @escaping RCTPromiseResolveBlock, _ reject: @escaping RCTPromiseRejectBlock) { + module.updateCustomItems(callId, customItems, Promise(resolve, reject)) + } + + @objc func deleteCustomItems(_ callId: String, _ customItemKeys: [String], _ resolve: @escaping RCTPromiseResolveBlock, _ reject: @escaping RCTPromiseRejectBlock) { + module.deleteCustomItems(callId, customItemKeys, Promise(resolve, reject)) + } + + @objc func deleteAllCustomItems(_ callId: String, _ resolve: @escaping RCTPromiseResolveBlock, _ reject: @escaping RCTPromiseRejectBlock) { + module.deleteAllCustomItems(callId, Promise(resolve, reject)) + } } // MARK: DirectCall @@ -178,6 +190,18 @@ extension RNSendbirdCalls { @objc func updateRemoteVideoView(_ callId: String, _ videoViewId: NSNumber) { module.updateRemoteVideoView(callId, videoViewId) } + + @objc func directCallUpdateCustomItems(_ callId: String, _ customItems: [String: String], _ resolve: @escaping RCTPromiseResolveBlock, _ reject: @escaping RCTPromiseRejectBlock) { + module.directCallUpdateCustomItems(callId, customItems, Promise(resolve, reject)) + } + + @objc func directCallDeleteCustomItems(_ callId: String, _ customItemKeys: [String], _ resolve: @escaping RCTPromiseResolveBlock, _ reject: @escaping RCTPromiseRejectBlock) { + module.directCallDeleteCustomItems(callId, customItemKeys, Promise(resolve, reject)) + } + + @objc func directCallDeleteAllCustomItems(_ callId: String, _ resolve: @escaping RCTPromiseResolveBlock, _ reject: @escaping RCTPromiseRejectBlock) { + module.directCallDeleteAllCustomItems(callId, Promise(resolve, reject)) + } } // MARK: GroupCall @@ -185,10 +209,22 @@ extension RNSendbirdCalls { @objc func enter(_ roomId: String, _ options: [String: Any], _ resolve: @escaping RCTPromiseResolveBlock, _ reject: @escaping RCTPromiseRejectBlock) { module.enter(roomId, options, Promise(resolve, reject)) } - + @objc func exit(_ roomId: String) { module.exit(roomId) } + + @objc func groupCallUpdateCustomItems(_ roomId: String, _ customItems: [String: String], _ resolve: @escaping RCTPromiseResolveBlock, _ reject: @escaping RCTPromiseRejectBlock) { + module.groupCallUpdateCustomItems(roomId, customItems, Promise(resolve, reject)) + } + + @objc func groupCallDeleteCustomItems(_ roomId: String, _ customItemKeys: [String], _ resolve: @escaping RCTPromiseResolveBlock, _ reject: @escaping RCTPromiseRejectBlock) { + module.groupCallDeleteCustomItems(roomId, customItemKeys, Promise(resolve, reject)) + } + + @objc func groupCallDeleteAllCustomItems(_ roomId: String, _ resolve: @escaping RCTPromiseResolveBlock, _ reject: @escaping RCTPromiseRejectBlock) { + module.groupCallDeleteAllCustomItems(roomId, Promise(resolve, reject)) + } } // MARK: MediaDeviceControl diff --git a/src/libs/DirectCall.ts b/src/libs/DirectCall.ts index 1cc633e3..65dafa00 100644 --- a/src/libs/DirectCall.ts +++ b/src/libs/DirectCall.ts @@ -29,6 +29,14 @@ export class DirectCall implements DirectCallProperties, DirectCallMethods { return directCall._updateInternal(props); } + /** @internal **/ + public static updateCustomItems(callId: string, customItems: Record) { + const directCall = DirectCall.pool[callId]; + if (directCall) { + directCall._updateCustomItems(customItems); + } + } + constructor(binder: NativeBinder, props: DirectCallProperties) { this._binder = binder; this._props = props; @@ -54,7 +62,9 @@ export class DirectCall implements DirectCallProperties, DirectCallMethods { this._props = props; return this; } - + private _updateCustomItems(customItems: Record) { + this._props.customItems = customItems; + } public get ios_callUUID() { return this._props.ios_callUUID; } @@ -401,4 +411,48 @@ export class DirectCall implements DirectCallProperties, DirectCallMethods { public updateRemoteVideoView = (videoViewId: number) => { this._binder.nativeModule.updateRemoteVideoView(this.callId, videoViewId); }; + + /** + * Updates custom items for this call. + * + * @param customItems Custom items of [String: String] to be updated or inserted. + * @returns Promise that resolves with CustomItemUpdateResult containing updated items and affected keys. + * @since 1.1.9 + */ + public updateCustomItems = async (customItems: Record) => { + const result = await this._binder.nativeModule.directCallUpdateCustomItems(this.callId, customItems); + if (result && result.updatedItems) { + this._updateCustomItems(result.updatedItems); + } + return result; + }; + + /** + * Deletes custom items for this call. + * + * @param customItemKeys Custom item keys which you want to delete. + * @returns Promise that resolves with CustomItemUpdateResult containing updated items and affected keys. + * @since 1.1.9 + */ + public deleteCustomItems = async (customItemKeys: string[]) => { + const result = await this._binder.nativeModule.directCallDeleteCustomItems(this.callId, customItemKeys); + if (result && result.updatedItems) { + this._updateCustomItems(result.updatedItems); + } + return result; + }; + + /** + * Deletes all custom items for this call. + * + * @returns Promise that resolves with CustomItemUpdateResult containing updated items and affected keys. + * @since 1.1.9 + */ + public deleteAllCustomItems = async () => { + const result = await this._binder.nativeModule.directCallDeleteAllCustomItems(this.callId); + if (result && result.updatedItems) { + this._updateCustomItems(result.updatedItems); + } + return result; + }; } diff --git a/src/libs/Room.ts b/src/libs/Room.ts index 59f4c11f..526c5859 100644 --- a/src/libs/Room.ts +++ b/src/libs/Room.ts @@ -71,7 +71,9 @@ export class Room implements RoomProperties, GroupCallMethods { this._props = props; return this; } - + private _updateCustomItems(customItems: Record) { + this._props.customItems = customItems; + } public get roomId() { return this._props.roomId; } @@ -234,4 +236,49 @@ export class Room implements RoomProperties, GroupCallMethods { if (Platform.OS !== 'android') return; await this._binder.nativeModule.selectAudioDevice(ControllableModuleType.GROUP_CALL, this.roomId, device); }; + + /** + * Updates custom items for this room. + * Custom items are key-value pairs that can be stored with the room. + * + * @param customItems - Key-value pairs to update + * @returns Promise resolving to the update result with updated items and affected keys + * @since 1.1.9 + */ + public updateCustomItems = async (customItems: Record) => { + const result = await this._binder.nativeModule.groupCallUpdateCustomItems(this.roomId, customItems); + if (result && result.updatedItems) { + this._updateCustomItems(result.updatedItems); + } + return result; + }; + + /** + * Deletes custom items from this room. + * + * @param customItemKeys - Array of keys to delete + * @returns Promise resolving to the update result with updated items and affected keys + * @since 1.1.9 + */ + public deleteCustomItems = async (customItemKeys: string[]) => { + const result = await this._binder.nativeModule.groupCallDeleteCustomItems(this.roomId, customItemKeys); + if (result && result.updatedItems) { + this._updateCustomItems(result.updatedItems); + } + return result; + }; + + /** + * Deletes all custom items from this room. + * + * @returns Promise resolving to the update result with updated items and affected keys + * @since 1.1.9 + */ + public deleteAllCustomItems = async () => { + const result = await this._binder.nativeModule.groupCallDeleteAllCustomItems(this.roomId); + if (result && result.updatedItems) { + this._updateCustomItems(result.updatedItems); + } + return result; + }; } diff --git a/src/libs/SendbirdCallsModule.tsx b/src/libs/SendbirdCallsModule.tsx index 9a7ac9df..b8279892 100644 --- a/src/libs/SendbirdCallsModule.tsx +++ b/src/libs/SendbirdCallsModule.tsx @@ -415,4 +415,43 @@ export default class SendbirdCallsModule implements SendbirdCallsJavascriptSpec const queryKey = await this.binder.nativeModule.createRoomListQuery(params); return new RoomListQuery(queryKey, NativeQueryType.ROOM_LIST, this.binder); }; + + /** + * Updates custom items for a given call ID. + * + * @since 1.1.9 + */ + public updateCustomItems = async (callId: string, customItems: Record) => { + const result = await this.binder.nativeModule.updateCustomItems(callId, customItems); + if (result && result.updatedItems) { + DirectCall.updateCustomItems(callId, result.updatedItems); + } + return result; + }; + + /** + * Deletes custom items for a given call ID. + * + * @since 1.1.9 + */ + public deleteCustomItems = async (callId: string, customItemKeys: string[]) => { + const result = await this.binder.nativeModule.deleteCustomItems(callId, customItemKeys); + if (result && result.updatedItems) { + DirectCall.updateCustomItems(callId, result.updatedItems); + } + return result; + }; + + /** + * Deletes all custom items for a given call ID. + * + * @since 1.1.9 + */ + public deleteAllCustomItems = async (callId: string) => { + const result = await this.binder.nativeModule.deleteAllCustomItems(callId); + if (result && result.updatedItems) { + DirectCall.updateCustomItems(callId, result.updatedItems); + } + return result; + }; } diff --git a/src/types/Call.ts b/src/types/Call.ts index 142ee8f1..de6fd281 100644 --- a/src/types/Call.ts +++ b/src/types/Call.ts @@ -334,7 +334,12 @@ export interface DirectCallProperties { } /** DirectCall */ -type JSDirectCallModule = AsJSDirectCall; +type JSDirectCallModule = AsJSDirectCall< + Omit< + NativeDirectCallModule, + 'directCallUpdateCustomItems' | 'directCallDeleteCustomItems' | 'directCallDeleteAllCustomItems' + > +>; type JSDirectCallMediaDeviceControl = AsJSInterface< JSMediaDeviceControl, 'android', @@ -343,6 +348,9 @@ type JSDirectCallMediaDeviceControl = AsJSInterface< export interface DirectCallMethods extends JSDirectCallModule, JSDirectCallMediaDeviceControl { addListener(listener: Partial): () => void; + updateCustomItems(customItems: Record): Promise; + deleteCustomItems(customItemKeys: string[]): Promise; + deleteAllCustomItems(): Promise; } export interface DirectCallLog { diff --git a/src/types/NativeModule.ts b/src/types/NativeModule.ts index 454145a8..a5b929ce 100644 --- a/src/types/NativeModule.ts +++ b/src/types/NativeModule.ts @@ -1,7 +1,13 @@ import type { NativeModule, TurboModule } from 'react-native'; import { BridgedQuery } from '../libs/BridgedQuery'; -import type { CallOptions, DirectCallLog, DirectCallProperties, SendbirdCallListener } from './Call'; +import type { + CallOptions, + CustomItemUpdateResult, + DirectCallLog, + DirectCallProperties, + SendbirdCallListener, +} from './Call'; import type { AudioDevice, VideoDevice } from './Media'; import { SoundType } from './Media'; import { @@ -48,6 +54,10 @@ export interface NativeCommonModule { fetchRoomById(roomId: string): Promise; getCachedRoomById(roomId: string): Promise; + updateCustomItems(callId: string, customItems: Record): Promise; + deleteCustomItems(callId: string, customItemKeys: string[]): Promise; + deleteAllCustomItems(callId: string): Promise; + /** @platform Android **/ handleFirebaseMessageData(data: Record): void; @@ -93,15 +103,16 @@ export interface NativeDirectCallModule { updateLocalVideoView(callId: string, videoViewId: number): void; updateRemoteVideoView(callId: string, videoViewId: number): void; + directCallUpdateCustomItems(callId: string, customItems: Record): Promise; + directCallDeleteCustomItems(callId: string, customItemKeys: string[]): Promise; + directCallDeleteAllCustomItems(callId: string): Promise; + /** Not implemented yet belows **/ // hold(callId:string): Promise; // unhold(callId:string, force: boolean): Promise; // // captureLocalVideoView(callId:string): Promise; // capture -> tmp file path // captureRemoteVideoView(callId:string): Promise; - // updateCustomItems(callId:string, items: Record): Promise; - // deleteAllCustomItems(callId:string): Promise; - // deleteCustomItems(callId:string, key: string[]): Promise; // // startRecording(callId:string, options: RecordingOptions): Promise<{ recordingId: string }>; // stopRecording(callId:string, recordingId: string): void; @@ -113,6 +124,10 @@ export interface NativeDirectCallModule { export interface NativeGroupCallModule { enter(roomId: string, options: EnterParams): Promise; exit(roomId: string): void; + + groupCallUpdateCustomItems(roomId: string, customItems: Record): Promise; + groupCallDeleteCustomItems(roomId: string, customItemKeys: string[]): Promise; + groupCallDeleteAllCustomItems(roomId: string): Promise; } export interface NativeQueries { diff --git a/src/types/Room.ts b/src/types/Room.ts index e615565e..99b2ed6d 100644 --- a/src/types/Room.ts +++ b/src/types/Room.ts @@ -4,7 +4,7 @@ import type { AudioDevice, AudioDeviceChangedInfo } from './Media'; import type { NativeGroupCallModule } from './NativeModule'; import { JSMediaDeviceControl } from './NativeModule'; import type { ParticipantProperties } from './Participant'; -import type { AsJSGroupCall, AsJSInterface } from './index'; +import type { AsJSGroupCall, AsJSInterface, CustomItemUpdateResult } from './index'; export interface RoomListener { /** @@ -185,7 +185,12 @@ export interface RoomProperties { createdBy: string; } -type JSGroupCallModule = AsJSGroupCall; +type JSGroupCallModule = AsJSGroupCall< + Omit< + NativeGroupCallModule, + 'groupCallUpdateCustomItems' | 'groupCallDeleteCustomItems' | 'groupCallDeleteAllCustomItems' + > +>; type JSGroupCallMediaDeviceControl = AsJSInterface< Pick, 'android', @@ -194,6 +199,9 @@ type JSGroupCallMediaDeviceControl = AsJSInterface< export interface GroupCallMethods extends JSGroupCallModule, JSGroupCallMediaDeviceControl { addListener(listener: Partial): () => void; + updateCustomItems(customItems: Record): Promise; + deleteCustomItems(customItemKeys: string[]): Promise; + deleteAllCustomItems(): Promise; } export type RoomParams = {