From c504c7692d4f79616619f736ae22ad6c63951629 Mon Sep 17 00:00:00 2001 From: Vitalik Date: Tue, 19 Mar 2024 10:42:42 +0200 Subject: [PATCH] FEATURE | Voip notifications --- App.tsx | 14 +- android/app/build.gradle | 2 +- android/app/src/main/AndroidManifest.xml | 18 + ios/Podfile | 3 +- ios/Podfile.lock | 14 +- ios/taskme2.xcodeproj/project.pbxproj | 329 +++++++++++++++++- ios/taskme2/AppDelegate.mm | 66 ++++ ios/taskme2/Info.plist | 29 +- package-lock.json | 5 +- package.json | 2 + src/App.tsx | 12 +- src/api/notifications/requests.interfaces.ts | 5 +- src/modules/calls/screens/test-call/index.tsx | 146 -------- src/services/domain/auth.service.ts | 2 + src/services/system/callkeep.service.ts | 27 ++ src/services/system/index.ts | 18 +- .../system/voip-notification.service.ts | 85 +++++ 17 files changed, 588 insertions(+), 189 deletions(-) delete mode 100644 src/modules/calls/screens/test-call/index.tsx create mode 100644 src/services/system/callkeep.service.ts create mode 100644 src/services/system/voip-notification.service.ts diff --git a/App.tsx b/App.tsx index d0a8ddf..554e19d 100644 --- a/App.tsx +++ b/App.tsx @@ -1,5 +1,5 @@ import React from 'react' -import { SafeAreaView, Text } from 'react-native' +import { AppRegistry, Platform, SafeAreaView, Text } from 'react-native' function App(): JSX.Element { return ( @@ -10,3 +10,15 @@ function App(): JSX.Element { } export default App + +if (Platform.OS === 'android') { + AppRegistry.registerHeadlessTask( + 'RNCallKeepBackgroundMessage', + () => + ({ name, callUUID, handle }) => { + // Make your call here + console.log('something') + return Promise.resolve() + }, + ) +} diff --git a/android/app/build.gradle b/android/app/build.gradle index 8a719de..e300844 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -25,7 +25,7 @@ android { applicationId "com.app.task_me" minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion - versionCode 222 + versionCode 225 versionName "2.3" resValue "string", "build_config_package", "com.app.task_me" } diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 90639a2..ca1ba1b 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -27,6 +27,11 @@ + + + + + + + + + + + + + diff --git a/ios/Podfile b/ios/Podfile index 6f1a032..669985d 100644 --- a/ios/Podfile +++ b/ios/Podfile @@ -31,7 +31,8 @@ target 'taskme2' do pod 'react-native-sqlite-storage', :path => '../node_modules/react-native-sqlite-storage' pod 'react-native-config/Extension', :path => '../node_modules/react-native-config' - + pod 'RNCallKeep', :path => '../node_modules/react-native-callkeep' + # Flags change depending on the env values. flags = get_default_flags() diff --git a/ios/Podfile.lock b/ios/Podfile.lock index dc25a79..52f3fa2 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -564,6 +564,8 @@ PODS: - React-Core - RNAudioRecorderPlayer (3.6.6): - React-Core + - RNCallKeep (4.3.12): + - React - RNCAsyncStorage (1.22.1): - React-Core - RNCClipboard (1.5.1): @@ -619,6 +621,8 @@ PODS: - RNVectorIcons (10.0.3): - RCT-Folly (= 2021.07.22.00) - React-Core + - RNVoipPushNotification (3.3.2): + - React-Core - SDWebImage (5.11.1): - SDWebImage/Core (= 5.11.1) - SDWebImage/Core (5.11.1) @@ -718,6 +722,7 @@ DEPENDENCIES: - ReactNativeExceptionHandler (from `../node_modules/react-native-exception-handler`) - rn-fetch-blob (from `../node_modules/rn-fetch-blob`) - RNAudioRecorderPlayer (from `../node_modules/react-native-audio-recorder-player`) + - RNCallKeep (from `../node_modules/react-native-callkeep`) - "RNCAsyncStorage (from `../node_modules/@react-native-async-storage/async-storage`)" - "RNCClipboard (from `../node_modules/@react-native-community/clipboard`)" - "RNCPicker (from `../node_modules/@react-native-picker/picker`)" @@ -737,6 +742,7 @@ DEPENDENCIES: - "RNSoundLevel (from `../node_modules/@tomlangan/react-native-sound-level`)" - RNSVG (from `../node_modules/react-native-svg`) - RNVectorIcons (from `../node_modules/react-native-vector-icons`) + - RNVoipPushNotification (from `../node_modules/react-native-voip-push-notification`) - Yoga (from `../node_modules/react-native/ReactCommon/yoga`) SPEC REPOS: @@ -884,6 +890,8 @@ EXTERNAL SOURCES: :path: "../node_modules/rn-fetch-blob" RNAudioRecorderPlayer: :path: "../node_modules/react-native-audio-recorder-player" + RNCallKeep: + :path: "../node_modules/react-native-callkeep" RNCAsyncStorage: :path: "../node_modules/@react-native-async-storage/async-storage" RNCClipboard: @@ -922,6 +930,8 @@ EXTERNAL SOURCES: :path: "../node_modules/react-native-svg" RNVectorIcons: :path: "../node_modules/react-native-vector-icons" + RNVoipPushNotification: + :path: "../node_modules/react-native-voip-push-notification" Yoga: :path: "../node_modules/react-native/ReactCommon/yoga" @@ -1002,6 +1012,7 @@ SPEC CHECKSUMS: ReactNativeExceptionHandler: b11ff67c78802b2f62eed0e10e75cb1ef7947c60 rn-fetch-blob: f065bb7ab7fb48dd002629f8bdcb0336602d3cba RNAudioRecorderPlayer: f790fc1afb118552ae6285d60adde52ee6b5d9ef + RNCallKeep: aa9b1f9286f8f60d7b7d41ee5de47de564356aac RNCAsyncStorage: 7deab901e27d1f989a83e8be6ce91b673772c848 RNCClipboard: 41d8d918092ae8e676f18adada19104fa3e68495 RNCPicker: b18aaf30df596e9b1738e7c1f9ee55402a229dca @@ -1021,6 +1032,7 @@ SPEC CHECKSUMS: RNSoundLevel: c031ed233382b6aeabe44b3d5e895b906e69952f RNSVG: d00c8f91c3cbf6d476451313a18f04d220d4f396 RNVectorIcons: 64e6a523ac30a3241efa9baf1ffbcc5e76ff747a + RNVoipPushNotification: 543e18f83089134a35e7f1d2eba4c8b1f7776b08 SDWebImage: a7f831e1a65eb5e285e3fb046a23fcfbf08e696d SDWebImageWebPCoder: 908b83b6adda48effe7667cd2b7f78c897e5111d SocketRocket: f32cd54efbe0f095c4d7594881e52619cfe80b17 @@ -1028,6 +1040,6 @@ SPEC CHECKSUMS: Yoga: d0003f849d2b5224c072cef6568b540d8bb15cd3 YogaKit: f782866e155069a2cca2517aafea43200b01fd5a -PODFILE CHECKSUM: f9f0683c1738b3e88b8940a4c7885412b08fb771 +PODFILE CHECKSUM: cfc20c55adde2f7a0a48df5c2ebe42052a891ffa COCOAPODS: 1.15.2 diff --git a/ios/taskme2.xcodeproj/project.pbxproj b/ios/taskme2.xcodeproj/project.pbxproj index b8f6fdc..7926c7a 100644 --- a/ios/taskme2.xcodeproj/project.pbxproj +++ b/ios/taskme2.xcodeproj/project.pbxproj @@ -8,6 +8,8 @@ /* Begin PBXBuildFile section */ 00E356F31AD99517003FC87E /* taskme2Tests.m in Sources */ = {isa = PBXBuildFile; fileRef = 00E356F21AD99517003FC87E /* taskme2Tests.m */; }; + 0495CBE12BA221E800BF4228 /* CallKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0495CBE02BA221E800BF4228 /* CallKit.framework */; }; + 0495CBE32BA221EF00BF4228 /* Intents.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0495CBE22BA221EF00BF4228 /* Intents.framework */; settings = {ATTRIBUTES = (Weak, ); }; }; 04FBB34C2A84CD0D00436C19 /* NotificationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04FBB34B2A84CD0D00436C19 /* NotificationService.swift */; }; 04FBB3502A84CD0D00436C19 /* OneSignalNotificationServiceExtension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = 04FBB3492A84CD0D00436C19 /* OneSignalNotificationServiceExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; 13B07FBC1A68108700A75B9A /* AppDelegate.mm in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB01A68108700A75B9A /* AppDelegate.mm */; }; @@ -60,6 +62,8 @@ 00E356EE1AD99517003FC87E /* taskme2Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = taskme2Tests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 00E356F11AD99517003FC87E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 00E356F21AD99517003FC87E /* taskme2Tests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = taskme2Tests.m; sourceTree = ""; }; + 0495CBE02BA221E800BF4228 /* CallKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CallKit.framework; path = System/Library/Frameworks/CallKit.framework; sourceTree = SDKROOT; }; + 0495CBE22BA221EF00BF4228 /* Intents.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Intents.framework; path = System/Library/Frameworks/Intents.framework; sourceTree = SDKROOT; }; 04D8E49A2B0BA79200ACC6E2 /* OneSignalNotificationServiceExtensionStage.Release.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = OneSignalNotificationServiceExtensionStage.Release.entitlements; sourceTree = ""; }; 04D8E49B2B0BA7BA00ACC6E2 /* taskme2Stage.Release.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; name = taskme2Stage.Release.entitlements; path = taskme2/taskme2Stage.Release.entitlements; sourceTree = ""; }; 04FBB3442A84CC6700436C19 /* taskme2.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; name = taskme2.entitlements; path = taskme2/taskme2.entitlements; sourceTree = ""; }; @@ -117,6 +121,8 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 0495CBE32BA221EF00BF4228 /* Intents.framework in Frameworks */, + 0495CBE12BA221E800BF4228 /* CallKit.framework in Frameworks */, 331EB3F0DD322F0D1B2DA16C /* libPods-taskme2.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -182,6 +188,8 @@ 2D16E6871FA4F8E400B85C8A /* Frameworks */ = { isa = PBXGroup; children = ( + 0495CBE22BA221EF00BF4228 /* Intents.framework */, + 0495CBE02BA221E800BF4228 /* CallKit.framework */, ED297162215061F000B7C4FE /* JavaScriptCore.framework */, 0FD9FA6914F2DA8781CBD173 /* libPods-taskme2.a */, 527F61C1DD2E37B4CB3A2F5C /* libPods-taskme2-taskme2Tests.a */, @@ -710,10 +718,7 @@ "-DFOLLY_MOBILE=1", "-DFOLLY_USE_LIBCPP=1", ); - OTHER_LDFLAGS = ( - "$(inherited)", - " ", - ); + OTHER_LDFLAGS = "$(inherited) "; REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native"; SDKROOT = iphoneos; VALIDATE_PRODUCT = YES; @@ -729,8 +734,108 @@ ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = NO; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = taskme2/taskme2Stage.Release.entitlements; - CURRENT_PROJECT_VERSION = 19; + CURRENT_PROJECT_VERSION = 20; DEVELOPMENT_TEAM = HQ3J3TDPR2; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + "\"${PODS_ROOT}/Headers/Public\"", + "\"${PODS_ROOT}/Headers/Public/CocoaAsyncSocket\"", + "\"${PODS_ROOT}/Headers/Public/DoubleConversion\"", + "\"${PODS_ROOT}/Headers/Public/FBLazyVector\"", + "\"${PODS_ROOT}/Headers/Public/Flipper\"", + "\"${PODS_ROOT}/Headers/Public/Flipper-Fmt\"", + "\"${PODS_ROOT}/Headers/Public/Flipper-Folly\"", + "\"${PODS_ROOT}/Headers/Public/Flipper-PeerTalk\"", + "\"${PODS_ROOT}/Headers/Public/FlipperKit\"", + "\"${PODS_ROOT}/Headers/Public/RCT-Folly\"", + "\"${PODS_ROOT}/Headers/Public/RCTRequired\"", + "\"${PODS_ROOT}/Headers/Public/RCTTypeSafety\"", + "\"${PODS_ROOT}/Headers/Public/RNAudioRecorderPlayer\"", + "\"${PODS_ROOT}/Headers/Public/RNCAsyncStorage\"", + "\"${PODS_ROOT}/Headers/Public/RNCClipboard\"", + "\"${PODS_ROOT}/Headers/Public/RNCPicker\"", + "\"${PODS_ROOT}/Headers/Public/RNCallKeep\"", + "\"${PODS_ROOT}/Headers/Public/RNDateTimePicker\"", + "\"${PODS_ROOT}/Headers/Public/RNDeviceInfo\"", + "\"${PODS_ROOT}/Headers/Public/RNFS\"", + "\"${PODS_ROOT}/Headers/Public/RNFastImage\"", + "\"${PODS_ROOT}/Headers/Public/RNFileViewer\"", + "\"${PODS_ROOT}/Headers/Public/RNGestureHandler\"", + "\"${PODS_ROOT}/Headers/Public/RNImageCropPicker\"", + "\"${PODS_ROOT}/Headers/Public/RNNotifee\"", + "\"${PODS_ROOT}/Headers/Public/RNPDF\"", + "\"${PODS_ROOT}/Headers/Public/RNPermissions\"", + "\"${PODS_ROOT}/Headers/Public/RNReanimated\"", + "\"${PODS_ROOT}/Headers/Public/RNSVG\"", + "\"${PODS_ROOT}/Headers/Public/RNScreens\"", + "\"${PODS_ROOT}/Headers/Public/RNShare\"", + "\"${PODS_ROOT}/Headers/Public/RNSoundLevel\"", + "\"${PODS_ROOT}/Headers/Public/RNVectorIcons\"", + "\"${PODS_ROOT}/Headers/Public/React-Codegen\"", + "\"${PODS_ROOT}/Headers/Public/React-Core\"", + "\"${PODS_ROOT}/Headers/Public/React-NativeModulesApple\"", + "\"${PODS_ROOT}/Headers/Public/React-RCTAnimation\"", + "\"${PODS_ROOT}/Headers/Public/React-RCTAppDelegate\"", + "\"${PODS_ROOT}/Headers/Public/React-RCTBlob\"", + "\"${PODS_ROOT}/Headers/Public/React-RCTText\"", + "\"${PODS_ROOT}/Headers/Public/React-callinvoker\"", + "\"${PODS_ROOT}/Headers/Public/React-cxxreact\"", + "\"${PODS_ROOT}/Headers/Public/React-debug\"", + "\"${PODS_ROOT}/Headers/Public/React-hermes\"", + "\"${PODS_ROOT}/Headers/Public/React-jsi\"", + "\"${PODS_ROOT}/Headers/Public/React-jsiexecutor\"", + "\"${PODS_ROOT}/Headers/Public/React-jsinspector\"", + "\"${PODS_ROOT}/Headers/Public/React-logger\"", + "\"${PODS_ROOT}/Headers/Public/React-perflogger\"", + "\"${PODS_ROOT}/Headers/Public/React-runtimeexecutor\"", + "\"${PODS_ROOT}/Headers/Public/React-runtimescheduler\"", + "\"${PODS_ROOT}/Headers/Public/React-utils\"", + "\"${PODS_ROOT}/Headers/Public/ReactCommon\"", + "\"${PODS_ROOT}/Headers/Public/ReactNativeExceptionHandler\"", + "\"${PODS_ROOT}/Headers/Public/SDWebImage\"", + "\"${PODS_ROOT}/Headers/Public/SDWebImageWebPCoder\"", + "\"${PODS_ROOT}/Headers/Public/SocketRocket\"", + "\"${PODS_ROOT}/Headers/Public/TOCropViewController\"", + "\"${PODS_ROOT}/Headers/Public/Yoga\"", + "\"${PODS_ROOT}/Headers/Public/YogaKit\"", + "\"${PODS_ROOT}/Headers/Public/ffmpeg-kit-react-native\"", + "\"${PODS_ROOT}/Headers/Public/fmt\"", + "\"${PODS_ROOT}/Headers/Public/glog\"", + "\"${PODS_ROOT}/Headers/Public/hermes-engine\"", + "\"${PODS_ROOT}/Headers/Public/libevent\"", + "\"${PODS_ROOT}/Headers/Public/libwebp\"", + "\"${PODS_ROOT}/Headers/Public/react-native-cameraroll\"", + "\"${PODS_ROOT}/Headers/Public/react-native-config\"", + "\"${PODS_ROOT}/Headers/Public/react-native-date-picker\"", + "\"${PODS_ROOT}/Headers/Public/react-native-document-picker\"", + "\"${PODS_ROOT}/Headers/Public/react-native-html-to-pdf\"", + "\"${PODS_ROOT}/Headers/Public/react-native-image-picker\"", + "\"${PODS_ROOT}/Headers/Public/react-native-netinfo\"", + "\"${PODS_ROOT}/Headers/Public/react-native-onesignal\"", + "\"${PODS_ROOT}/Headers/Public/react-native-pager-view\"", + "\"${PODS_ROOT}/Headers/Public/react-native-print\"", + "\"${PODS_ROOT}/Headers/Public/react-native-receive-sharing-intent\"", + "\"${PODS_ROOT}/Headers/Public/react-native-restart\"", + "\"${PODS_ROOT}/Headers/Public/react-native-safe-area-context\"", + "\"${PODS_ROOT}/Headers/Public/react-native-splash-screen\"", + "\"${PODS_ROOT}/Headers/Public/react-native-sqlite-storage\"", + "\"${PODS_ROOT}/Headers/Public/react-native-video\"", + "\"${PODS_ROOT}/Headers/Public/react-native-webrtc\"", + "\"${PODS_ROOT}/Headers/Public/react-native-webview\"", + "\"${PODS_ROOT}/Headers/Public/rn-fetch-blob\"", + "\"$(PODS_ROOT)/DoubleConversion\"", + "\"$(PODS_ROOT)/boost\"", + "\"$(PODS_ROOT)/boost\"", + "\"$(PODS_ROOT)/boost-for-react-native\"", + "\"$(PODS_ROOT)/glog\"", + "\"$(PODS_ROOT)/RCT-Folly\"", + "\"$(PODS_ROOT)/Headers/Public/React-hermes\"", + "\"$(PODS_ROOT)/Headers/Public/hermes-engine\"", + "\"$(PODS_ROOT)/../../node_modules/react-native/ReactCommon\"", + "\"$(PODS_ROOT)/Headers/Private/React-Core\"", + "\"$(PODS_TARGET_SRCROOT)/include/\"", + "\"$(SRCROOT)/../node_modules/react-native-callkeep/ios/RNCallKeep\"", + ); INFOPLIST_FILE = taskme2/Info.plist; INFOPLIST_KEY_CFBundleDisplayName = "Task me ;)"; INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.productivity"; @@ -908,9 +1013,109 @@ ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = NO; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = taskme2/taskme2.entitlements; - CURRENT_PROJECT_VERSION = 19; + CURRENT_PROJECT_VERSION = 20; DEVELOPMENT_TEAM = HQ3J3TDPR2; ENABLE_BITCODE = NO; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + "\"${PODS_ROOT}/Headers/Public\"", + "\"${PODS_ROOT}/Headers/Public/CocoaAsyncSocket\"", + "\"${PODS_ROOT}/Headers/Public/DoubleConversion\"", + "\"${PODS_ROOT}/Headers/Public/FBLazyVector\"", + "\"${PODS_ROOT}/Headers/Public/Flipper\"", + "\"${PODS_ROOT}/Headers/Public/Flipper-Fmt\"", + "\"${PODS_ROOT}/Headers/Public/Flipper-Folly\"", + "\"${PODS_ROOT}/Headers/Public/Flipper-PeerTalk\"", + "\"${PODS_ROOT}/Headers/Public/FlipperKit\"", + "\"${PODS_ROOT}/Headers/Public/RCT-Folly\"", + "\"${PODS_ROOT}/Headers/Public/RCTRequired\"", + "\"${PODS_ROOT}/Headers/Public/RCTTypeSafety\"", + "\"${PODS_ROOT}/Headers/Public/RNAudioRecorderPlayer\"", + "\"${PODS_ROOT}/Headers/Public/RNCAsyncStorage\"", + "\"${PODS_ROOT}/Headers/Public/RNCClipboard\"", + "\"${PODS_ROOT}/Headers/Public/RNCPicker\"", + "\"${PODS_ROOT}/Headers/Public/RNCallKeep\"", + "\"${PODS_ROOT}/Headers/Public/RNDateTimePicker\"", + "\"${PODS_ROOT}/Headers/Public/RNDeviceInfo\"", + "\"${PODS_ROOT}/Headers/Public/RNFS\"", + "\"${PODS_ROOT}/Headers/Public/RNFastImage\"", + "\"${PODS_ROOT}/Headers/Public/RNFileViewer\"", + "\"${PODS_ROOT}/Headers/Public/RNGestureHandler\"", + "\"${PODS_ROOT}/Headers/Public/RNImageCropPicker\"", + "\"${PODS_ROOT}/Headers/Public/RNNotifee\"", + "\"${PODS_ROOT}/Headers/Public/RNPDF\"", + "\"${PODS_ROOT}/Headers/Public/RNPermissions\"", + "\"${PODS_ROOT}/Headers/Public/RNReanimated\"", + "\"${PODS_ROOT}/Headers/Public/RNSVG\"", + "\"${PODS_ROOT}/Headers/Public/RNScreens\"", + "\"${PODS_ROOT}/Headers/Public/RNShare\"", + "\"${PODS_ROOT}/Headers/Public/RNSoundLevel\"", + "\"${PODS_ROOT}/Headers/Public/RNVectorIcons\"", + "\"${PODS_ROOT}/Headers/Public/React-Codegen\"", + "\"${PODS_ROOT}/Headers/Public/React-Core\"", + "\"${PODS_ROOT}/Headers/Public/React-NativeModulesApple\"", + "\"${PODS_ROOT}/Headers/Public/React-RCTAnimation\"", + "\"${PODS_ROOT}/Headers/Public/React-RCTAppDelegate\"", + "\"${PODS_ROOT}/Headers/Public/React-RCTBlob\"", + "\"${PODS_ROOT}/Headers/Public/React-RCTText\"", + "\"${PODS_ROOT}/Headers/Public/React-callinvoker\"", + "\"${PODS_ROOT}/Headers/Public/React-cxxreact\"", + "\"${PODS_ROOT}/Headers/Public/React-debug\"", + "\"${PODS_ROOT}/Headers/Public/React-hermes\"", + "\"${PODS_ROOT}/Headers/Public/React-jsi\"", + "\"${PODS_ROOT}/Headers/Public/React-jsiexecutor\"", + "\"${PODS_ROOT}/Headers/Public/React-jsinspector\"", + "\"${PODS_ROOT}/Headers/Public/React-logger\"", + "\"${PODS_ROOT}/Headers/Public/React-perflogger\"", + "\"${PODS_ROOT}/Headers/Public/React-runtimeexecutor\"", + "\"${PODS_ROOT}/Headers/Public/React-runtimescheduler\"", + "\"${PODS_ROOT}/Headers/Public/React-utils\"", + "\"${PODS_ROOT}/Headers/Public/ReactCommon\"", + "\"${PODS_ROOT}/Headers/Public/ReactNativeExceptionHandler\"", + "\"${PODS_ROOT}/Headers/Public/SDWebImage\"", + "\"${PODS_ROOT}/Headers/Public/SDWebImageWebPCoder\"", + "\"${PODS_ROOT}/Headers/Public/SocketRocket\"", + "\"${PODS_ROOT}/Headers/Public/TOCropViewController\"", + "\"${PODS_ROOT}/Headers/Public/Yoga\"", + "\"${PODS_ROOT}/Headers/Public/YogaKit\"", + "\"${PODS_ROOT}/Headers/Public/ffmpeg-kit-react-native\"", + "\"${PODS_ROOT}/Headers/Public/fmt\"", + "\"${PODS_ROOT}/Headers/Public/glog\"", + "\"${PODS_ROOT}/Headers/Public/hermes-engine\"", + "\"${PODS_ROOT}/Headers/Public/libevent\"", + "\"${PODS_ROOT}/Headers/Public/libwebp\"", + "\"${PODS_ROOT}/Headers/Public/react-native-cameraroll\"", + "\"${PODS_ROOT}/Headers/Public/react-native-config\"", + "\"${PODS_ROOT}/Headers/Public/react-native-date-picker\"", + "\"${PODS_ROOT}/Headers/Public/react-native-document-picker\"", + "\"${PODS_ROOT}/Headers/Public/react-native-html-to-pdf\"", + "\"${PODS_ROOT}/Headers/Public/react-native-image-picker\"", + "\"${PODS_ROOT}/Headers/Public/react-native-netinfo\"", + "\"${PODS_ROOT}/Headers/Public/react-native-onesignal\"", + "\"${PODS_ROOT}/Headers/Public/react-native-pager-view\"", + "\"${PODS_ROOT}/Headers/Public/react-native-print\"", + "\"${PODS_ROOT}/Headers/Public/react-native-receive-sharing-intent\"", + "\"${PODS_ROOT}/Headers/Public/react-native-restart\"", + "\"${PODS_ROOT}/Headers/Public/react-native-safe-area-context\"", + "\"${PODS_ROOT}/Headers/Public/react-native-splash-screen\"", + "\"${PODS_ROOT}/Headers/Public/react-native-sqlite-storage\"", + "\"${PODS_ROOT}/Headers/Public/react-native-video\"", + "\"${PODS_ROOT}/Headers/Public/react-native-webrtc\"", + "\"${PODS_ROOT}/Headers/Public/react-native-webview\"", + "\"${PODS_ROOT}/Headers/Public/rn-fetch-blob\"", + "\"$(PODS_ROOT)/DoubleConversion\"", + "\"$(PODS_ROOT)/boost\"", + "\"$(PODS_ROOT)/boost\"", + "\"$(PODS_ROOT)/boost-for-react-native\"", + "\"$(PODS_ROOT)/glog\"", + "\"$(PODS_ROOT)/RCT-Folly\"", + "\"$(PODS_ROOT)/Headers/Public/React-hermes\"", + "\"$(PODS_ROOT)/Headers/Public/hermes-engine\"", + "\"$(PODS_ROOT)/../../node_modules/react-native/ReactCommon\"", + "\"$(PODS_ROOT)/Headers/Private/React-Core\"", + "\"$(PODS_TARGET_SRCROOT)/include/\"", + "\"$(SRCROOT)/../node_modules/react-native-callkeep/ios/RNCallKeep\"", + ); INFOPLIST_FILE = taskme2/Info.plist; INFOPLIST_KEY_CFBundleDisplayName = "Task me ;)"; INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.productivity"; @@ -945,8 +1150,108 @@ ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = NO; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = taskme2/taskme2.entitlements; - CURRENT_PROJECT_VERSION = 19; + CURRENT_PROJECT_VERSION = 20; DEVELOPMENT_TEAM = HQ3J3TDPR2; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + "\"${PODS_ROOT}/Headers/Public\"", + "\"${PODS_ROOT}/Headers/Public/CocoaAsyncSocket\"", + "\"${PODS_ROOT}/Headers/Public/DoubleConversion\"", + "\"${PODS_ROOT}/Headers/Public/FBLazyVector\"", + "\"${PODS_ROOT}/Headers/Public/Flipper\"", + "\"${PODS_ROOT}/Headers/Public/Flipper-Fmt\"", + "\"${PODS_ROOT}/Headers/Public/Flipper-Folly\"", + "\"${PODS_ROOT}/Headers/Public/Flipper-PeerTalk\"", + "\"${PODS_ROOT}/Headers/Public/FlipperKit\"", + "\"${PODS_ROOT}/Headers/Public/RCT-Folly\"", + "\"${PODS_ROOT}/Headers/Public/RCTRequired\"", + "\"${PODS_ROOT}/Headers/Public/RCTTypeSafety\"", + "\"${PODS_ROOT}/Headers/Public/RNAudioRecorderPlayer\"", + "\"${PODS_ROOT}/Headers/Public/RNCAsyncStorage\"", + "\"${PODS_ROOT}/Headers/Public/RNCClipboard\"", + "\"${PODS_ROOT}/Headers/Public/RNCPicker\"", + "\"${PODS_ROOT}/Headers/Public/RNCallKeep\"", + "\"${PODS_ROOT}/Headers/Public/RNDateTimePicker\"", + "\"${PODS_ROOT}/Headers/Public/RNDeviceInfo\"", + "\"${PODS_ROOT}/Headers/Public/RNFS\"", + "\"${PODS_ROOT}/Headers/Public/RNFastImage\"", + "\"${PODS_ROOT}/Headers/Public/RNFileViewer\"", + "\"${PODS_ROOT}/Headers/Public/RNGestureHandler\"", + "\"${PODS_ROOT}/Headers/Public/RNImageCropPicker\"", + "\"${PODS_ROOT}/Headers/Public/RNNotifee\"", + "\"${PODS_ROOT}/Headers/Public/RNPDF\"", + "\"${PODS_ROOT}/Headers/Public/RNPermissions\"", + "\"${PODS_ROOT}/Headers/Public/RNReanimated\"", + "\"${PODS_ROOT}/Headers/Public/RNSVG\"", + "\"${PODS_ROOT}/Headers/Public/RNScreens\"", + "\"${PODS_ROOT}/Headers/Public/RNShare\"", + "\"${PODS_ROOT}/Headers/Public/RNSoundLevel\"", + "\"${PODS_ROOT}/Headers/Public/RNVectorIcons\"", + "\"${PODS_ROOT}/Headers/Public/React-Codegen\"", + "\"${PODS_ROOT}/Headers/Public/React-Core\"", + "\"${PODS_ROOT}/Headers/Public/React-NativeModulesApple\"", + "\"${PODS_ROOT}/Headers/Public/React-RCTAnimation\"", + "\"${PODS_ROOT}/Headers/Public/React-RCTAppDelegate\"", + "\"${PODS_ROOT}/Headers/Public/React-RCTBlob\"", + "\"${PODS_ROOT}/Headers/Public/React-RCTText\"", + "\"${PODS_ROOT}/Headers/Public/React-callinvoker\"", + "\"${PODS_ROOT}/Headers/Public/React-cxxreact\"", + "\"${PODS_ROOT}/Headers/Public/React-debug\"", + "\"${PODS_ROOT}/Headers/Public/React-hermes\"", + "\"${PODS_ROOT}/Headers/Public/React-jsi\"", + "\"${PODS_ROOT}/Headers/Public/React-jsiexecutor\"", + "\"${PODS_ROOT}/Headers/Public/React-jsinspector\"", + "\"${PODS_ROOT}/Headers/Public/React-logger\"", + "\"${PODS_ROOT}/Headers/Public/React-perflogger\"", + "\"${PODS_ROOT}/Headers/Public/React-runtimeexecutor\"", + "\"${PODS_ROOT}/Headers/Public/React-runtimescheduler\"", + "\"${PODS_ROOT}/Headers/Public/React-utils\"", + "\"${PODS_ROOT}/Headers/Public/ReactCommon\"", + "\"${PODS_ROOT}/Headers/Public/ReactNativeExceptionHandler\"", + "\"${PODS_ROOT}/Headers/Public/SDWebImage\"", + "\"${PODS_ROOT}/Headers/Public/SDWebImageWebPCoder\"", + "\"${PODS_ROOT}/Headers/Public/SocketRocket\"", + "\"${PODS_ROOT}/Headers/Public/TOCropViewController\"", + "\"${PODS_ROOT}/Headers/Public/Yoga\"", + "\"${PODS_ROOT}/Headers/Public/YogaKit\"", + "\"${PODS_ROOT}/Headers/Public/ffmpeg-kit-react-native\"", + "\"${PODS_ROOT}/Headers/Public/fmt\"", + "\"${PODS_ROOT}/Headers/Public/glog\"", + "\"${PODS_ROOT}/Headers/Public/hermes-engine\"", + "\"${PODS_ROOT}/Headers/Public/libevent\"", + "\"${PODS_ROOT}/Headers/Public/libwebp\"", + "\"${PODS_ROOT}/Headers/Public/react-native-cameraroll\"", + "\"${PODS_ROOT}/Headers/Public/react-native-config\"", + "\"${PODS_ROOT}/Headers/Public/react-native-date-picker\"", + "\"${PODS_ROOT}/Headers/Public/react-native-document-picker\"", + "\"${PODS_ROOT}/Headers/Public/react-native-html-to-pdf\"", + "\"${PODS_ROOT}/Headers/Public/react-native-image-picker\"", + "\"${PODS_ROOT}/Headers/Public/react-native-netinfo\"", + "\"${PODS_ROOT}/Headers/Public/react-native-onesignal\"", + "\"${PODS_ROOT}/Headers/Public/react-native-pager-view\"", + "\"${PODS_ROOT}/Headers/Public/react-native-print\"", + "\"${PODS_ROOT}/Headers/Public/react-native-receive-sharing-intent\"", + "\"${PODS_ROOT}/Headers/Public/react-native-restart\"", + "\"${PODS_ROOT}/Headers/Public/react-native-safe-area-context\"", + "\"${PODS_ROOT}/Headers/Public/react-native-splash-screen\"", + "\"${PODS_ROOT}/Headers/Public/react-native-sqlite-storage\"", + "\"${PODS_ROOT}/Headers/Public/react-native-video\"", + "\"${PODS_ROOT}/Headers/Public/react-native-webrtc\"", + "\"${PODS_ROOT}/Headers/Public/react-native-webview\"", + "\"${PODS_ROOT}/Headers/Public/rn-fetch-blob\"", + "\"$(PODS_ROOT)/DoubleConversion\"", + "\"$(PODS_ROOT)/boost\"", + "\"$(PODS_ROOT)/boost\"", + "\"$(PODS_ROOT)/boost-for-react-native\"", + "\"$(PODS_ROOT)/glog\"", + "\"$(PODS_ROOT)/RCT-Folly\"", + "\"$(PODS_ROOT)/Headers/Public/React-hermes\"", + "\"$(PODS_ROOT)/Headers/Public/hermes-engine\"", + "\"$(PODS_ROOT)/../../node_modules/react-native/ReactCommon\"", + "\"$(PODS_ROOT)/Headers/Private/React-Core\"", + "\"$(PODS_TARGET_SRCROOT)/include/\"", + "\"$(SRCROOT)/../node_modules/react-native-callkeep/ios/RNCallKeep\"", + ); INFOPLIST_FILE = taskme2/Info.plist; INFOPLIST_KEY_CFBundleDisplayName = "Task me ;)"; INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.productivity"; @@ -1040,10 +1345,7 @@ "-DFOLLY_MOBILE=1", "-DFOLLY_USE_LIBCPP=1", ); - OTHER_LDFLAGS = ( - "$(inherited)", - " ", - ); + OTHER_LDFLAGS = "$(inherited) "; REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native"; SDKROOT = iphoneos; }; @@ -1113,10 +1415,7 @@ "-DFOLLY_MOBILE=1", "-DFOLLY_USE_LIBCPP=1", ); - OTHER_LDFLAGS = ( - "$(inherited)", - " ", - ); + OTHER_LDFLAGS = "$(inherited) "; REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native"; SDKROOT = iphoneos; VALIDATE_PRODUCT = YES; diff --git a/ios/taskme2/AppDelegate.mm b/ios/taskme2/AppDelegate.mm index 647cc79..7b1a43e 100644 --- a/ios/taskme2/AppDelegate.mm +++ b/ios/taskme2/AppDelegate.mm @@ -4,6 +4,10 @@ #import +#import +#import "RNVoipPushNotificationManager.h" +#import "RNCallKeep.h" + @implementation AppDelegate - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions @@ -13,6 +17,8 @@ // They will be passed down to the ViewController used by React Native. self.initialProps = @{}; +NSLog(@"setup testtttt"); + return [super application:application didFinishLaunchingWithOptions:launchOptions]; } @@ -32,4 +38,64 @@ return [RCTLinkingManager application:application openURL:url options:options]; } +/* Add PushKit delegate method */ + +// --- Handle updated push credentials +- (void)pushRegistry:(PKPushRegistry *)registry didUpdatePushCredentials:(PKPushCredentials *)credentials forType:(PKPushType)type { + // Register VoIP push token (a property of PKPushCredentials) with server + NSString *token = [credentials.token description]; + token = [token stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@"<>"]]; + token = [token stringByReplacingOccurrencesOfString:@" " withString:@""]; + + NSLog(@"VoIP token: %@", token); + + NSDictionary *params = @{@"token": token}; + + [[NSNotificationCenter defaultCenter] postNotificationName:@"VoipTokenReceived" object:nil userInfo:params]; + + [RNVoipPushNotificationManager didUpdatePushCredentials:credentials forType:(NSString *)type]; +} + +- (void)pushRegistry:(PKPushRegistry *)registry didInvalidatePushTokenForType:(PKPushType)type +{ + // --- The system calls this method when a previously provided push token is no longer valid for use. No action is necessary on your part to reregister the push type. Instead, use this method to notify your server not to send push notifications using the matching push token. +} + +// --- Handle incoming pushes +- (void)pushRegistry:(PKPushRegistry *)registry didReceiveIncomingPushWithPayload:(PKPushPayload *)payload forType:(PKPushType)type withCompletionHandler:(void (^)(void))completion { + + + // --- NOTE: apple forced us to invoke callkit ASAP when we receive voip push + // --- see: react-native-callkeep + + // --- Retrieve information from your voip push payload + NSString *uuid = payload.dictionaryPayload[@"uuid"]; + NSString *callerName = [NSString stringWithFormat:@"%@ (Connecting...)", payload.dictionaryPayload[@"callerName"]]; + NSString *handle = payload.dictionaryPayload[@"handle"]; + + // --- this is optional, only required if you want to call `completion()` on the js side + [RNVoipPushNotificationManager addCompletionHandler:uuid completionHandler:completion]; + + // --- Process the received push + [RNVoipPushNotificationManager didReceiveIncomingPushWithPayload:payload forType:(NSString *)type]; + + // --- You should make sure to report to callkit BEFORE execute `completion()` + [RNCallKeep reportNewIncomingCall: uuid + handle: handle + handleType: @"generic" + hasVideo: NO + localizedCallerName: callerName + supportsHolding: YES + supportsDTMF: YES + supportsGrouping: YES + supportsUngrouping: YES + fromPushKit: YES + payload: nil + withCompletionHandler: completion]; + + // --- You don't need to call it if you stored `completion()` and will call it on the js side. + completion(); +} + + @end diff --git a/ios/taskme2/Info.plist b/ios/taskme2/Info.plist index 35878ac..c522729 100644 --- a/ios/taskme2/Info.plist +++ b/ios/taskme2/Info.plist @@ -26,8 +26,22 @@ $(MARKETING_VERSION) CFBundleSignature ???? + CFBundleURLTypes + + + CFBundleTypeRole + Editor + CFBundleURLSchemes + + ShareMediaTaskme + + + + CFBundleVersion $(CURRENT_PROJECT_VERSION) + ITSAppUsesNonExemptEncryption + LSRequiresIPhoneOS NSAppTransportSecurity @@ -66,6 +80,7 @@ UIBackgroundModes remote-notification + voip UILaunchStoryboardName LaunchScreen.storyboard @@ -86,19 +101,5 @@ UIViewControllerBasedStatusBarAppearance - ITSAppUsesNonExemptEncryption - - CFBundleURLTypes - - - CFBundleTypeRole - Editor - CFBundleURLSchemes - - ShareMediaTaskme - - - - diff --git a/package-lock.json b/package-lock.json index 7b99a3f..7a3d1d7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -44,6 +44,7 @@ "react-native-audio-recorder-player": "^3.6.6", "react-native-autolink": "^4.1.0", "react-native-calendars": "^1.1298.0", + "react-native-callkeep": "^4.3.12", "react-native-config": "^1.5.1", "react-native-controlled-mentions": "^2.2.5", "react-native-country-flag": "^2.0.2", @@ -87,6 +88,7 @@ "react-native-video": "^5.2.1", "react-native-video-controls": "^2.8.1", "react-native-view-pdf": "^0.14.0", + "react-native-voip-push-notification": "^3.3.2", "react-native-webrtc": "^118.0.2", "react-native-webview": "^13.8.1", "react-native-wheel-pick": "^1.2.2", @@ -22372,7 +22374,8 @@ "requires": {} }, "react-native-voip-push-notification": { - "version": "https://registry.npmjs.org/react-native-voip-push-notification/-/react-native-voip-push-notification-3.3.2.tgz", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/react-native-voip-push-notification/-/react-native-voip-push-notification-3.3.2.tgz", "integrity": "sha512-O5oNRmlL4iEAYr9os1PJZPetIxZ5j4qy9xLzF/A3/6x94gRmXihIT9o26jtGnuJfijUm5aM8GvNqcLnOAwtjXA==", "requires": {} }, diff --git a/package.json b/package.json index 5d6d0cc..5d96ad1 100644 --- a/package.json +++ b/package.json @@ -54,6 +54,7 @@ "react-native-audio-recorder-player": "^3.6.6", "react-native-autolink": "^4.1.0", "react-native-calendars": "^1.1298.0", + "react-native-callkeep": "^4.3.12", "react-native-config": "^1.5.1", "react-native-controlled-mentions": "^2.2.5", "react-native-country-flag": "^2.0.2", @@ -97,6 +98,7 @@ "react-native-video": "^5.2.1", "react-native-video-controls": "^2.8.1", "react-native-view-pdf": "^0.14.0", + "react-native-voip-push-notification": "^3.3.2", "react-native-webrtc": "^118.0.2", "react-native-webview": "^13.8.1", "react-native-wheel-pick": "^1.2.2", diff --git a/src/App.tsx b/src/App.tsx index 767e970..2f479c7 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -8,7 +8,7 @@ if (__DEV__) { import { ThemeProvider } from './shared/themes' // import Orientation from 'react-native-orientation-locker' -import { AppState, LogBox } from 'react-native' +import { AppState, LogBox, Platform } from 'react-native' import { appService } from './services/app.service' import 'react-native-gesture-handler' import { BottomSheetModalProvider } from '@gorhom/bottom-sheet' @@ -18,6 +18,9 @@ import { GestureHandlerRootView } from 'react-native-gesture-handler' import { appEvents } from './shared' import Toast from 'react-native-toast-message' import { toastConfig } from './config/toast.config' +import './services/system/callkeep.service' + +import { VoipNotificationsService } from './services/system' LogBox.ignoreLogs(['Warning: ...', 'Require cycle: ...']) // Ignore log notification by message LogBox.ignoreAllLogs() //Ignore all log notifications @@ -45,6 +48,13 @@ const App: FC = () => { } }, []) + useEffect(() => { + if (Platform.OS === 'ios') { + VoipNotificationsService.getInstance().initListeners() + return VoipNotificationsService.getInstance().removeListeners + } + }, []) + return ( <> diff --git a/src/api/notifications/requests.interfaces.ts b/src/api/notifications/requests.interfaces.ts index 957662e..cfc73db 100644 --- a/src/api/notifications/requests.interfaces.ts +++ b/src/api/notifications/requests.interfaces.ts @@ -1,4 +1,5 @@ export interface ISaveDevicePayload { - deviceUuid: string, - notificationUserId: string + deviceUuid: string + notificationUserId: string + isVoip?: boolean } diff --git a/src/modules/calls/screens/test-call/index.tsx b/src/modules/calls/screens/test-call/index.tsx deleted file mode 100644 index e96362a..0000000 --- a/src/modules/calls/screens/test-call/index.tsx +++ /dev/null @@ -1,146 +0,0 @@ -import React, { FC, useRef, useState } from 'react' -import { $size, Button, IRouteParams, ScreenLayout, Txt } from '@/shared' -import { - MediaStream, - RTCPeerConnection, - RTCView, - mediaDevices, -} from 'react-native-webrtc' -import { StyleSheet } from 'react-native' - -interface IProps extends IRouteParams {} - -const servers = { - iceServers: [ - { - urls: [ - 'stun:stun1.l.google.com:19302', - 'stun:stun2.l.google.com:19302', - ], - }, - ], - iceCandidatePoolSize: 10, -} - -export const TestCallScreen: FC = ({ navigation }) => { - const [remoteStream, setRemoteStream] = useState(null) - const [localStream, setLocalStream] = useState(null) - const [webcamStarted, setWebcamStarted] = useState(false) - const [channelId, setChannelId] = useState(null) - const pc = useRef(null) - - const startWebcam = async () => { - pc.current = new RTCPeerConnection(servers) - - console.log('pc.current', pc.current) - - const local = await mediaDevices.getUserMedia({ - video: true, - audio: true, - }) - console.log('local', local) - - setLocalStream(local) - - const remote = new MediaStream({}) - setRemoteStream(remote) - - // // Push tracks from local stream to peer connection - // local.getTracks().forEach(track => { - // pc.current.getLocalStreams()[0].addTrack(track) - // }) - - // // Pull tracks from peer connection, add to remote video stream - // pc.current.ontrack = event => { - // event.streams[0].getTracks().forEach(track => { - // remote.addTrack(track) - // }) - // } - - // pc.current.onaddstream = event => { - // setRemoteStream(event.stream) - // } - } - - // const startCall = async () => { - // pc.current.onicecandidate = async event => { - // if (event.candidate) { - // console.log( - // 'event.candidate.toJSON()', - // event.candidate.toJSON(), - // ) - // } - // } - - // //create offer - // const offerDescription = await pc.current.createOffer() - // await pc.current.setLocalDescription(offerDescription) - - // const offer = { - // sdp: offerDescription.sdp, - // type: offerDescription.type, - // } - - // console.log('offer', offer) - // // await channelDoc.set({ offer }) - - // // // Listen for remote answer - // // channelDoc.onSnapshot(snapshot => { - // // const data = snapshot.data() - // // if (!pc.current.currentRemoteDescription && data?.answer) { - // // const answerDescription = new RTCSessionDescription(data.answer) - // // pc.current.setRemoteDescription(answerDescription) - // // } - // // }) - - // // // When answered, add candidate to peer connection - // // answerCandidates.onSnapshot(snapshot => { - // // snapshot.docChanges().forEach(change => { - // // if (change.type === 'added') { - // // const data = change.doc.data() - // // pc.current.addIceCandidate(new RTCIceCandidate(data)) - // // } - // // }) - // // }) - // } - - return ( - - test -