@cometchat/skills 4.0.0 → 4.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +42 -2
- package/bin/install.js +448 -57
- package/package.json +1 -1
- package/skills/cometchat/SKILL.md +337 -80
- package/skills/cometchat-a11y/SKILL.md +476 -0
- package/skills/cometchat-android-v5/SKILL.md +1 -1
- package/skills/cometchat-android-v5-calls/SKILL.md +413 -0
- package/skills/cometchat-android-v5-calls/references/README.md +53 -0
- package/skills/cometchat-android-v5-calls/references/add-calls-to-existing-chat.md +195 -0
- package/skills/cometchat-android-v5-calls/references/audio-controls.md +91 -0
- package/skills/cometchat-android-v5-calls/references/background-handling.md +168 -0
- package/skills/cometchat-android-v5-calls/references/call-layouts.md +123 -0
- package/skills/cometchat-android-v5-calls/references/call-logs.md +113 -0
- package/skills/cometchat-android-v5-calls/references/call-session.md +274 -0
- package/skills/cometchat-android-v5-calls/references/custom-ui.md +150 -0
- package/skills/cometchat-android-v5-calls/references/event-listeners.md +123 -0
- package/skills/cometchat-android-v5-calls/references/group-calls.md +205 -0
- package/skills/cometchat-android-v5-calls/references/idle-timeout.md +111 -0
- package/skills/cometchat-android-v5-calls/references/in-call-chat.md +134 -0
- package/skills/cometchat-android-v5-calls/references/join-session.md +120 -0
- package/skills/cometchat-android-v5-calls/references/migration-v4-to-v5.md +206 -0
- package/skills/cometchat-android-v5-calls/references/participant-management.md +110 -0
- package/skills/cometchat-android-v5-calls/references/picture-in-picture.md +106 -0
- package/skills/cometchat-android-v5-calls/references/raise-hand.md +242 -0
- package/skills/cometchat-android-v5-calls/references/recording.md +101 -0
- package/skills/cometchat-android-v5-calls/references/ringing-integration.md +152 -0
- package/skills/cometchat-android-v5-calls/references/screen-sharing.md +82 -0
- package/skills/cometchat-android-v5-calls/references/server-fcm-voip.md +215 -0
- package/skills/cometchat-android-v5-calls/references/session-settings.md +121 -0
- package/skills/cometchat-android-v5-calls/references/setup.md +137 -0
- package/skills/cometchat-android-v5-calls/references/share-invite.md +151 -0
- package/skills/cometchat-android-v5-calls/references/video-controls.md +87 -0
- package/skills/cometchat-android-v5-calls/references/voip-calling.md +526 -0
- package/skills/cometchat-android-v5-components/SKILL.md +1 -1
- package/skills/cometchat-android-v5-core/SKILL.md +1 -1
- package/skills/cometchat-android-v5-customization/SKILL.md +1 -1
- package/skills/cometchat-android-v5-extensions/SKILL.md +1 -1
- package/skills/cometchat-android-v5-features/SKILL.md +1 -1
- package/skills/cometchat-android-v5-placement/SKILL.md +1 -1
- package/skills/cometchat-android-v5-production/SKILL.md +1 -1
- package/skills/cometchat-android-v5-push/SKILL.md +1 -1
- package/skills/cometchat-android-v5-testing/SKILL.md +1 -1
- package/skills/cometchat-android-v5-theming/SKILL.md +1 -1
- package/skills/cometchat-android-v5-troubleshooting/SKILL.md +1 -1
- package/skills/cometchat-android-v6/SKILL.md +1 -1
- package/skills/cometchat-android-v6-builder-settings/SKILL.md +1 -1
- package/skills/cometchat-android-v6-calls/SKILL.md +375 -0
- package/skills/cometchat-android-v6-calls/references/add-calls-to-existing-chat.md +97 -0
- package/skills/cometchat-android-v6-calls/references/call-layouts.md +91 -0
- package/skills/cometchat-android-v6-calls/references/call-session.md +163 -0
- package/skills/cometchat-android-v6-calls/references/device-management.md +171 -0
- package/skills/cometchat-android-v6-calls/references/group-calls.md +191 -0
- package/skills/cometchat-android-v6-calls/references/idle-timeout.md +107 -0
- package/skills/cometchat-android-v6-calls/references/in-call-chat.md +136 -0
- package/skills/cometchat-android-v6-calls/references/raise-hand.md +186 -0
- package/skills/cometchat-android-v6-calls/references/ringing-integration.md +176 -0
- package/skills/cometchat-android-v6-calls/references/server-fcm-voip.md +127 -0
- package/skills/cometchat-android-v6-calls/references/share-invite.md +105 -0
- package/skills/cometchat-android-v6-compose-components/SKILL.md +2 -2
- package/skills/cometchat-android-v6-compose-customization/SKILL.md +1 -1
- package/skills/cometchat-android-v6-compose-placement/SKILL.md +1 -1
- package/skills/cometchat-android-v6-compose-theming/SKILL.md +1 -1
- package/skills/cometchat-android-v6-core/SKILL.md +1 -1
- package/skills/cometchat-android-v6-events/SKILL.md +1 -1
- package/skills/cometchat-android-v6-extensions/SKILL.md +1 -1
- package/skills/cometchat-android-v6-features/SKILL.md +1 -1
- package/skills/cometchat-android-v6-kotlin-components/SKILL.md +1 -1
- package/skills/cometchat-android-v6-kotlin-customization/SKILL.md +1 -1
- package/skills/cometchat-android-v6-kotlin-placement/SKILL.md +1 -1
- package/skills/cometchat-android-v6-kotlin-theming/SKILL.md +1 -1
- package/skills/cometchat-android-v6-migration/SKILL.md +398 -0
- package/skills/cometchat-android-v6-production/SKILL.md +1 -1
- package/skills/cometchat-android-v6-push/SKILL.md +1 -1
- package/skills/cometchat-android-v6-testing/SKILL.md +1 -1
- package/skills/cometchat-android-v6-troubleshooting/SKILL.md +1 -1
- package/skills/cometchat-angular-calls/SKILL.md +511 -0
- package/skills/cometchat-angular-calls/references/add-calls-to-existing-chat.md +95 -0
- package/skills/cometchat-angular-calls/references/call-layouts.md +106 -0
- package/skills/cometchat-angular-calls/references/call-session.md +167 -0
- package/skills/cometchat-angular-calls/references/custom-ui.md +231 -0
- package/skills/cometchat-angular-calls/references/device-management.md +135 -0
- package/skills/cometchat-angular-calls/references/group-calls.md +412 -0
- package/skills/cometchat-angular-calls/references/idle-timeout.md +145 -0
- package/skills/cometchat-angular-calls/references/in-call-chat.md +148 -0
- package/skills/cometchat-angular-calls/references/lazy-loading-pitfalls.md +205 -0
- package/skills/cometchat-angular-calls/references/migration-v4-to-v5.md +53 -0
- package/skills/cometchat-angular-calls/references/ngzone-and-async-callbacks.md +183 -0
- package/skills/cometchat-angular-calls/references/picture-in-picture.md +285 -0
- package/skills/cometchat-angular-calls/references/raise-hand.md +167 -0
- package/skills/cometchat-angular-calls/references/recording-screen-share.md +267 -0
- package/skills/cometchat-angular-calls/references/ringing-integration.md +131 -0
- package/skills/cometchat-angular-calls/references/server-web-push-vapid.md +100 -0
- package/skills/cometchat-angular-calls/references/share-invite.md +116 -0
- package/skills/cometchat-angular-components/SKILL.md +1 -1
- package/skills/cometchat-angular-core/SKILL.md +1 -1
- package/skills/cometchat-angular-customization/SKILL.md +1 -1
- package/skills/cometchat-angular-features/SKILL.md +1 -1
- package/skills/cometchat-angular-patterns/SKILL.md +1 -1
- package/skills/cometchat-angular-placement/SKILL.md +1 -1
- package/skills/cometchat-angular-production/SKILL.md +1 -1
- package/skills/cometchat-angular-push/SKILL.md +403 -0
- package/skills/cometchat-angular-testing/SKILL.md +333 -0
- package/skills/cometchat-angular-theming/SKILL.md +1 -1
- package/skills/cometchat-angular-troubleshooting/SKILL.md +1 -1
- package/skills/cometchat-astro-patterns/SKILL.md +1 -1
- package/skills/cometchat-calls/SKILL.md +358 -0
- package/skills/cometchat-calls/references/use-case-broadcast.md +194 -0
- package/skills/cometchat-calls/references/use-case-marketplace.md +158 -0
- package/skills/cometchat-calls/references/use-case-support.md +190 -0
- package/skills/cometchat-calls/references/use-case-team.md +169 -0
- package/skills/cometchat-calls/references/use-case-telehealth.md +154 -0
- package/skills/cometchat-components/SKILL.md +1 -1
- package/skills/cometchat-core/SKILL.md +1 -1
- package/skills/cometchat-customization/SKILL.md +2 -2
- package/skills/cometchat-features/SKILL.md +2 -2
- package/skills/cometchat-flutter-v5/SKILL.md +1 -1
- package/skills/cometchat-flutter-v5-calls/SKILL.md +325 -94
- package/skills/cometchat-flutter-v5-calls/references/add-calls-to-existing-chat.md +169 -0
- package/skills/cometchat-flutter-v5-calls/references/call-layouts.md +98 -0
- package/skills/cometchat-flutter-v5-calls/references/call-session.md +330 -0
- package/skills/cometchat-flutter-v5-calls/references/device-management.md +120 -0
- package/skills/cometchat-flutter-v5-calls/references/group-calls.md +187 -0
- package/skills/cometchat-flutter-v5-calls/references/idle-timeout.md +97 -0
- package/skills/cometchat-flutter-v5-calls/references/in-call-chat.md +132 -0
- package/skills/cometchat-flutter-v5-calls/references/migration-v4-to-v5.md +160 -0
- package/skills/cometchat-flutter-v5-calls/references/raise-hand.md +244 -0
- package/skills/cometchat-flutter-v5-calls/references/ringing-integration.md +193 -0
- package/skills/cometchat-flutter-v5-calls/references/server-push-bridge.md +101 -0
- package/skills/cometchat-flutter-v5-calls/references/share-invite.md +142 -0
- package/skills/cometchat-flutter-v5-conversations/SKILL.md +1 -1
- package/skills/cometchat-flutter-v5-core/SKILL.md +1 -1
- package/skills/cometchat-flutter-v5-customization/SKILL.md +1 -1
- package/skills/cometchat-flutter-v5-events/SKILL.md +1 -1
- package/skills/cometchat-flutter-v5-messages/SKILL.md +1 -1
- package/skills/cometchat-flutter-v5-production/SKILL.md +1 -1
- package/skills/cometchat-flutter-v5-push/SKILL.md +1 -1
- package/skills/cometchat-flutter-v5-testing/SKILL.md +390 -0
- package/skills/cometchat-flutter-v5-theming/SKILL.md +1 -1
- package/skills/cometchat-flutter-v5-troubleshooting/SKILL.md +1 -1
- package/skills/cometchat-flutter-v5-users-groups/SKILL.md +1 -1
- package/skills/cometchat-flutter-v6/SKILL.md +1 -1
- package/skills/cometchat-flutter-v6-calls/SKILL.md +308 -243
- package/skills/cometchat-flutter-v6-calls/references/add-calls-to-existing-chat.md +134 -0
- package/skills/cometchat-flutter-v6-calls/references/call-layouts.md +102 -0
- package/skills/cometchat-flutter-v6-calls/references/call-session.md +229 -0
- package/skills/cometchat-flutter-v6-calls/references/device-management.md +99 -0
- package/skills/cometchat-flutter-v6-calls/references/group-calls.md +190 -0
- package/skills/cometchat-flutter-v6-calls/references/idle-timeout.md +80 -0
- package/skills/cometchat-flutter-v6-calls/references/in-call-chat.md +122 -0
- package/skills/cometchat-flutter-v6-calls/references/raise-hand.md +268 -0
- package/skills/cometchat-flutter-v6-calls/references/ringing-integration.md +171 -0
- package/skills/cometchat-flutter-v6-calls/references/server-push-bridge.md +93 -0
- package/skills/cometchat-flutter-v6-calls/references/share-invite.md +102 -0
- package/skills/cometchat-flutter-v6-components/SKILL.md +1 -1
- package/skills/cometchat-flutter-v6-conversations/SKILL.md +1 -1
- package/skills/cometchat-flutter-v6-core/SKILL.md +1 -1
- package/skills/cometchat-flutter-v6-customization/SKILL.md +1 -1
- package/skills/cometchat-flutter-v6-events/SKILL.md +1 -1
- package/skills/cometchat-flutter-v6-features/SKILL.md +1 -1
- package/skills/cometchat-flutter-v6-messages/SKILL.md +1 -1
- package/skills/cometchat-flutter-v6-migration/SKILL.md +1 -1
- package/skills/cometchat-flutter-v6-placement/SKILL.md +1 -1
- package/skills/cometchat-flutter-v6-production/SKILL.md +1 -1
- package/skills/cometchat-flutter-v6-push/SKILL.md +452 -0
- package/skills/cometchat-flutter-v6-testing/SKILL.md +319 -0
- package/skills/cometchat-flutter-v6-theming/SKILL.md +1 -1
- package/skills/cometchat-flutter-v6-troubleshooting/SKILL.md +1 -1
- package/skills/cometchat-flutter-v6-users-groups/SKILL.md +1 -1
- package/skills/cometchat-i18n/SKILL.md +358 -0
- package/skills/cometchat-ios/SKILL.md +5 -5
- package/skills/cometchat-ios-calls/SKILL.md +409 -0
- package/skills/cometchat-ios-calls/references/add-calls-to-existing-chat.md +172 -0
- package/skills/cometchat-ios-calls/references/avaudiosession-routing.md +189 -0
- package/skills/cometchat-ios-calls/references/call-layouts.md +136 -0
- package/skills/cometchat-ios-calls/references/call-session.md +221 -0
- package/skills/cometchat-ios-calls/references/callkit-and-pushkit.md +353 -0
- package/skills/cometchat-ios-calls/references/custom-ui.md +322 -0
- package/skills/cometchat-ios-calls/references/device-management.md +171 -0
- package/skills/cometchat-ios-calls/references/group-calls.md +396 -0
- package/skills/cometchat-ios-calls/references/idle-timeout.md +185 -0
- package/skills/cometchat-ios-calls/references/in-call-chat.md +183 -0
- package/skills/cometchat-ios-calls/references/migration-v4-to-v5.md +138 -0
- package/skills/cometchat-ios-calls/references/picture-in-picture.md +246 -0
- package/skills/cometchat-ios-calls/references/raise-hand.md +239 -0
- package/skills/cometchat-ios-calls/references/recording-screen-share.md +339 -0
- package/skills/cometchat-ios-calls/references/ringing-integration.md +142 -0
- package/skills/cometchat-ios-calls/references/server-apns-pushkit.md +267 -0
- package/skills/cometchat-ios-calls/references/share-invite.md +152 -0
- package/skills/cometchat-ios-calls/references/swiftui-uikit-hosting.md +246 -0
- package/skills/cometchat-ios-calls/references/voip-cert-setup.md +166 -0
- package/skills/cometchat-ios-components/SKILL.md +1 -1
- package/skills/cometchat-ios-core/SKILL.md +1 -1
- package/skills/cometchat-ios-customization/SKILL.md +1 -1
- package/skills/cometchat-ios-features/SKILL.md +1 -1
- package/skills/cometchat-ios-placement/SKILL.md +1 -1
- package/skills/cometchat-ios-production/SKILL.md +1 -1
- package/skills/cometchat-ios-push/SKILL.md +1 -1
- package/skills/cometchat-ios-testing/SKILL.md +371 -0
- package/skills/cometchat-ios-theming/SKILL.md +1 -1
- package/skills/cometchat-ios-troubleshooting/SKILL.md +1 -1
- package/skills/cometchat-native-bare-patterns/SKILL.md +45 -3
- package/skills/cometchat-native-calls/SKILL.md +599 -0
- package/skills/cometchat-native-calls/references/add-calls-to-existing-chat.md +203 -0
- package/skills/cometchat-native-calls/references/call-layouts.md +124 -0
- package/skills/cometchat-native-calls/references/call-session.md +182 -0
- package/skills/cometchat-native-calls/references/custom-ui.md +250 -0
- package/skills/cometchat-native-calls/references/device-management.md +135 -0
- package/skills/cometchat-native-calls/references/expo-vs-bare.md +179 -0
- package/skills/cometchat-native-calls/references/group-calls.md +291 -0
- package/skills/cometchat-native-calls/references/idle-timeout.md +128 -0
- package/skills/cometchat-native-calls/references/in-call-chat.md +143 -0
- package/skills/cometchat-native-calls/references/migration-v4-to-v5.md +72 -0
- package/skills/cometchat-native-calls/references/picture-in-picture.md +276 -0
- package/skills/cometchat-native-calls/references/raise-hand.md +203 -0
- package/skills/cometchat-native-calls/references/recording-screen-share.md +290 -0
- package/skills/cometchat-native-calls/references/ringing-integration.md +118 -0
- package/skills/cometchat-native-calls/references/server-push-bridge.md +135 -0
- package/skills/cometchat-native-calls/references/server-push-payloads.md +193 -0
- package/skills/cometchat-native-calls/references/share-invite.md +144 -0
- package/skills/cometchat-native-calls/references/voip-push-end-to-end.md +317 -0
- package/skills/cometchat-native-components/SKILL.md +1 -1
- package/skills/cometchat-native-core/SKILL.md +1 -1
- package/skills/cometchat-native-customization/SKILL.md +1 -1
- package/skills/cometchat-native-expo-patterns/SKILL.md +18 -1
- package/skills/cometchat-native-features/SKILL.md +1 -1
- package/skills/cometchat-native-placement/SKILL.md +1 -1
- package/skills/cometchat-native-production/SKILL.md +1 -1
- package/skills/cometchat-native-push/SKILL.md +1 -1
- package/skills/cometchat-native-testing/SKILL.md +1 -1
- package/skills/cometchat-native-theming/SKILL.md +1 -1
- package/skills/cometchat-native-troubleshooting/SKILL.md +1 -1
- package/skills/cometchat-nextjs-patterns/SKILL.md +1 -1
- package/skills/cometchat-placement/SKILL.md +29 -1
- package/skills/cometchat-production/SKILL.md +1 -1
- package/skills/cometchat-react-calls/SKILL.md +539 -0
- package/skills/cometchat-react-calls/references/add-calls-to-existing-chat.md +145 -0
- package/skills/cometchat-react-calls/references/call-layouts.md +161 -0
- package/skills/cometchat-react-calls/references/call-session.md +235 -0
- package/skills/cometchat-react-calls/references/custom-ui.md +201 -0
- package/skills/cometchat-react-calls/references/device-management.md +206 -0
- package/skills/cometchat-react-calls/references/group-calls.md +262 -0
- package/skills/cometchat-react-calls/references/idle-timeout.md +175 -0
- package/skills/cometchat-react-calls/references/in-call-chat.md +212 -0
- package/skills/cometchat-react-calls/references/migration-v4-to-v5.md +172 -0
- package/skills/cometchat-react-calls/references/picture-in-picture.md +245 -0
- package/skills/cometchat-react-calls/references/raise-hand.md +238 -0
- package/skills/cometchat-react-calls/references/recording-screen-share.md +143 -0
- package/skills/cometchat-react-calls/references/ringing-integration.md +255 -0
- package/skills/cometchat-react-calls/references/server-web-push-vapid.md +241 -0
- package/skills/cometchat-react-calls/references/share-invite.md +176 -0
- package/skills/cometchat-react-calls/references/testing-calls-on-web.md +198 -0
- package/skills/cometchat-react-calls/references/voip-and-web-push.md +165 -0
- package/skills/cometchat-react-patterns/SKILL.md +56 -8
- package/skills/cometchat-react-push/SKILL.md +448 -0
- package/skills/cometchat-react-router-patterns/SKILL.md +1 -1
- package/skills/cometchat-react-testing/SKILL.md +404 -0
- package/skills/cometchat-theming/SKILL.md +3 -3
- package/skills/cometchat-troubleshooting/SKILL.md +2 -2
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
# Picture-in-Picture on React Native
|
|
2
|
+
|
|
3
|
+
Both Android and iOS support PiP for video calls — but the integration paths are different. Android exposes `PictureInPictureParams` via `Activity` APIs; iOS exposes `AVPictureInPictureController` (and CallKit handles it for VoIP calls). RN bridges both via native modules.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Android — Activity-level PiP
|
|
8
|
+
|
|
9
|
+
Android PiP is an Activity attribute. The activity declares it supports PiP, and you transition into PiP by calling `enterPictureInPictureMode()` from native (RN exposes a bridge).
|
|
10
|
+
|
|
11
|
+
### Manifest
|
|
12
|
+
|
|
13
|
+
```xml
|
|
14
|
+
<!-- android/app/src/main/AndroidManifest.xml -->
|
|
15
|
+
<activity
|
|
16
|
+
android:name=".MainActivity"
|
|
17
|
+
android:supportsPictureInPicture="true"
|
|
18
|
+
android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation|keyboardHidden">
|
|
19
|
+
<!-- ... -->
|
|
20
|
+
</activity>
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
`configChanges` is critical — without it, Android destroys + recreates the activity on PiP transition, which kills the WebRTC connection.
|
|
24
|
+
|
|
25
|
+
### Bridge
|
|
26
|
+
|
|
27
|
+
`react-native-webrtc` ships a helper module (in some versions) for entering PiP. If your version doesn't have it, write a tiny native module:
|
|
28
|
+
|
|
29
|
+
```kotlin
|
|
30
|
+
// android/app/src/main/java/com/yourapp/PictureInPictureModule.kt
|
|
31
|
+
package com.yourapp
|
|
32
|
+
|
|
33
|
+
import android.app.PictureInPictureParams
|
|
34
|
+
import android.os.Build
|
|
35
|
+
import android.util.Rational
|
|
36
|
+
import com.facebook.react.bridge.ReactApplicationContext
|
|
37
|
+
import com.facebook.react.bridge.ReactContextBaseJavaModule
|
|
38
|
+
import com.facebook.react.bridge.ReactMethod
|
|
39
|
+
import com.facebook.react.bridge.Promise
|
|
40
|
+
|
|
41
|
+
class PictureInPictureModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaModule(reactContext) {
|
|
42
|
+
override fun getName() = "PictureInPicture"
|
|
43
|
+
|
|
44
|
+
@ReactMethod
|
|
45
|
+
fun enterPip(promise: Promise) {
|
|
46
|
+
val activity = currentActivity
|
|
47
|
+
if (activity == null) {
|
|
48
|
+
promise.reject("NO_ACTIVITY", "No current activity")
|
|
49
|
+
return
|
|
50
|
+
}
|
|
51
|
+
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
|
|
52
|
+
promise.reject("UNSUPPORTED", "Android < 8.0 doesn't support PiP")
|
|
53
|
+
return
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
val aspectRatio = Rational(16, 9)
|
|
57
|
+
val params = PictureInPictureParams.Builder()
|
|
58
|
+
.setAspectRatio(aspectRatio)
|
|
59
|
+
.build()
|
|
60
|
+
|
|
61
|
+
val ok = activity.enterPictureInPictureMode(params)
|
|
62
|
+
if (ok) promise.resolve(null) else promise.reject("FAILED", "Couldn't enter PiP")
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Register in `MainApplication.kt`:
|
|
68
|
+
|
|
69
|
+
```kotlin
|
|
70
|
+
override fun getPackages(): List<ReactPackage> {
|
|
71
|
+
val packages = PackageList(this).packages
|
|
72
|
+
packages.add(PictureInPicturePackage()) // your package wrapping the module
|
|
73
|
+
return packages
|
|
74
|
+
}
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### React side
|
|
78
|
+
|
|
79
|
+
```ts
|
|
80
|
+
import { NativeModules, Platform } from "react-native";
|
|
81
|
+
|
|
82
|
+
const PictureInPicture = NativeModules.PictureInPicture;
|
|
83
|
+
|
|
84
|
+
async function enterPiP() {
|
|
85
|
+
if (Platform.OS !== "android") return;
|
|
86
|
+
try {
|
|
87
|
+
await PictureInPicture.enterPip();
|
|
88
|
+
} catch (err) {
|
|
89
|
+
console.warn("PiP failed:", err);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### Listening for PiP transitions
|
|
95
|
+
|
|
96
|
+
On Android, the activity gets `onPictureInPictureModeChanged` callback. RN exposes this via `AppState`:
|
|
97
|
+
|
|
98
|
+
```ts
|
|
99
|
+
import { AppState, type AppStateStatus } from "react-native";
|
|
100
|
+
|
|
101
|
+
useEffect(() => {
|
|
102
|
+
const handler = (state: AppStateStatus) => {
|
|
103
|
+
// 'background' fires when entering PiP on some Android versions
|
|
104
|
+
// 'active' fires on returning
|
|
105
|
+
if (state === "active") {
|
|
106
|
+
// restore full UI
|
|
107
|
+
}
|
|
108
|
+
};
|
|
109
|
+
const sub = AppState.addEventListener("change", handler);
|
|
110
|
+
return () => sub.remove();
|
|
111
|
+
}, []);
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
Better — emit a custom event from your native module on `onPictureInPictureModeChanged` and listen in JS:
|
|
115
|
+
|
|
116
|
+
```ts
|
|
117
|
+
import { NativeEventEmitter, NativeModules } from "react-native";
|
|
118
|
+
|
|
119
|
+
const emitter = new NativeEventEmitter(NativeModules.PictureInPicture);
|
|
120
|
+
useEffect(() => {
|
|
121
|
+
const sub = emitter.addListener("pipModeChanged", ({ inPip }: { inPip: boolean }) => {
|
|
122
|
+
setInPip(inPip);
|
|
123
|
+
});
|
|
124
|
+
return () => sub.remove();
|
|
125
|
+
}, []);
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
---
|
|
129
|
+
|
|
130
|
+
## iOS — CallKit handles it for VoIP calls
|
|
131
|
+
|
|
132
|
+
The simplest iOS PiP path: **don't write any.** If you've integrated CallKit (rule 1.2 in the SKILL.md, mandatory for standalone-mode VoIP), iOS auto-handles PiP for active video calls when the user backgrounds the app. The system shows your CallKit-reported call in a small floating window.
|
|
133
|
+
|
|
134
|
+
For non-CallKit calls (in-foreground only), you need `AVPictureInPictureController`. This is involved on iOS because `AVPictureInPictureController` requires an `AVSampleBufferDisplayLayer` — it doesn't work directly with `<RTCView />`.
|
|
135
|
+
|
|
136
|
+
### AVPictureInPictureController bridge
|
|
137
|
+
|
|
138
|
+
`react-native-webrtc` ≥ 119 ships an `RTCVideoView` that supports PiP via a system-managed display layer. The bridge:
|
|
139
|
+
|
|
140
|
+
```ts
|
|
141
|
+
import { RTCView } from "react-native-webrtc";
|
|
142
|
+
|
|
143
|
+
// react-native-webrtc 119+
|
|
144
|
+
<RTCView
|
|
145
|
+
streamURL={remoteStream.toURL()}
|
|
146
|
+
style={styles.remoteVideo}
|
|
147
|
+
pictureInPicture={true}
|
|
148
|
+
onPictureInPictureStart={() => setInPip(true)}
|
|
149
|
+
onPictureInPictureStop={() => setInPip(false)}
|
|
150
|
+
/>
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
Older versions: write a wrapper around `AVPictureInPictureController` and a `WebRTCVideoView` subclass that exposes its `AVSampleBufferDisplayLayer` to the controller. Substantial native work; deferring to CallKit is the right call for most apps.
|
|
154
|
+
|
|
155
|
+
### Info.plist
|
|
156
|
+
|
|
157
|
+
Background modes must include `audio` (rule 1.3 in the SKILL.md). PiP itself doesn't need a separate capability; it inherits from "audio" + active call.
|
|
158
|
+
|
|
159
|
+
---
|
|
160
|
+
|
|
161
|
+
## App state preservation across PiP
|
|
162
|
+
|
|
163
|
+
When the app enters PiP (Android) or background-with-active-call (iOS), the call state must persist. Practical rules:
|
|
164
|
+
|
|
165
|
+
1. **Don't tear down the WebRTC connection** on `componentWillUnmount` of the call screen. The screen survives PiP; tearing down kills the call.
|
|
166
|
+
2. **Hide the in-page video** when PiP is active — same rule as web. Two videos rendering = bad UX, double battery.
|
|
167
|
+
3. **Restore on PiP exit** — listen to `pipModeChanged` and re-render the full call surface.
|
|
168
|
+
|
|
169
|
+
```tsx
|
|
170
|
+
function CallScreen() {
|
|
171
|
+
const [inPip, setInPip] = useState(false);
|
|
172
|
+
|
|
173
|
+
return (
|
|
174
|
+
<View style={[styles.container, inPip && styles.minimalPip]}>
|
|
175
|
+
<RTCView
|
|
176
|
+
streamURL={remoteStream?.toURL()}
|
|
177
|
+
style={inPip ? styles.pipFullSize : styles.normalSize}
|
|
178
|
+
pictureInPicture={true}
|
|
179
|
+
onPictureInPictureStart={() => setInPip(true)}
|
|
180
|
+
onPictureInPictureStop={() => setInPip(false)}
|
|
181
|
+
/>
|
|
182
|
+
{!inPip && <ControlPanel onEnd={endCall} />}
|
|
183
|
+
</View>
|
|
184
|
+
);
|
|
185
|
+
}
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
The control panel is only visible in non-PiP mode; PiP is video-only by design.
|
|
189
|
+
|
|
190
|
+
---
|
|
191
|
+
|
|
192
|
+
## Auto-PiP on app backgrounding
|
|
193
|
+
|
|
194
|
+
Common UX: user presses Home button or switches apps → call auto-enters PiP so video keeps playing.
|
|
195
|
+
|
|
196
|
+
### Android
|
|
197
|
+
|
|
198
|
+
In `MainActivity.kt`:
|
|
199
|
+
|
|
200
|
+
```kotlin
|
|
201
|
+
override fun onUserLeaveHint() {
|
|
202
|
+
super.onUserLeaveHint()
|
|
203
|
+
// User pressed Home — auto-enter PiP if a call is active
|
|
204
|
+
if (isCallActive() && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
|
205
|
+
enterPictureInPictureMode(PictureInPictureParams.Builder().build())
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
private fun isCallActive(): Boolean {
|
|
210
|
+
// bridge to JS state — store this in a SharedPreferences flag
|
|
211
|
+
return getSharedPreferences("call", MODE_PRIVATE).getBoolean("active", false)
|
|
212
|
+
}
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
JS side: write the flag whenever the call starts/ends:
|
|
216
|
+
|
|
217
|
+
```ts
|
|
218
|
+
import { NativeModules } from "react-native";
|
|
219
|
+
|
|
220
|
+
useEffect(() => {
|
|
221
|
+
NativeModules.PictureInPicture.setCallActive(true);
|
|
222
|
+
return () => NativeModules.PictureInPicture.setCallActive(false);
|
|
223
|
+
}, []);
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
### iOS
|
|
227
|
+
|
|
228
|
+
CallKit handles this — if you've reported the call to CallKit (rule 1.2), iOS auto-PiPs on background. No bridge code needed for the auto-PiP path.
|
|
229
|
+
|
|
230
|
+
For non-CallKit calls (rare in production calling apps), use `react-native-webrtc`'s `pictureInPicture` prop with auto-enter behavior at the native level.
|
|
231
|
+
|
|
232
|
+
---
|
|
233
|
+
|
|
234
|
+
## Anti-patterns
|
|
235
|
+
|
|
236
|
+
1. **Skipping `configChanges` on the manifest activity.** PiP transition destroys + recreates the activity → call dies.
|
|
237
|
+
2. **Tearing down WebRTC in PiP transition.** Same outcome — call dies.
|
|
238
|
+
3. **No iOS Background Modes `audio` capability.** PiP video plays without sound; user thinks it's broken.
|
|
239
|
+
4. **Auto-PiP on every app background, including non-call screens.** User opens settings, comes back to a PiP'd home screen. Gate on `isCallActive()`.
|
|
240
|
+
5. **Rendering control panel inside PiP window.** PiP windows are small; controls don't fit. Hide them.
|
|
241
|
+
6. **Using two separate `<RTCView />` instances** — one for normal, one for PiP. The `pictureInPicture` prop on a single view is the right pattern.
|
|
242
|
+
7. **iOS PiP without CallKit.** Doesn't work for backgrounded calls — only foregrounded. CallKit is required for "real" PiP.
|
|
243
|
+
|
|
244
|
+
---
|
|
245
|
+
|
|
246
|
+
## Verification checklist
|
|
247
|
+
|
|
248
|
+
**Android:**
|
|
249
|
+
- [ ] `android:supportsPictureInPicture="true"` on the activity
|
|
250
|
+
- [ ] `android:configChanges` includes screenSize/smallestScreenSize/screenLayout/orientation
|
|
251
|
+
- [ ] Native PiP module registered + bridged
|
|
252
|
+
- [ ] `onUserLeaveHint` auto-PiP gated on `isCallActive()`
|
|
253
|
+
- [ ] PiP entry uses 16:9 aspect ratio (or matches stream resolution)
|
|
254
|
+
- [ ] PiP mode change emits to JS; controls hidden in PiP
|
|
255
|
+
|
|
256
|
+
**iOS:**
|
|
257
|
+
- [ ] CallKit integrated (rule 1.2 in SKILL.md)
|
|
258
|
+
- [ ] Background Modes: audio + voip + remote-notification
|
|
259
|
+
- [ ] `react-native-webrtc` ≥ 119 if using `pictureInPicture` prop
|
|
260
|
+
- [ ] PiP transitions don't tear down call
|
|
261
|
+
|
|
262
|
+
**Real-device smoke:**
|
|
263
|
+
- [ ] Android: press Home during call → PiP appears, video keeps playing, audio continues
|
|
264
|
+
- [ ] Android: tap PiP window → call screen restored, controls visible
|
|
265
|
+
- [ ] iOS: press Home during call → CallKit-managed PiP appears
|
|
266
|
+
- [ ] iOS: tap PiP → app foregrounds, full call screen visible
|
|
267
|
+
|
|
268
|
+
---
|
|
269
|
+
|
|
270
|
+
## Pointers
|
|
271
|
+
|
|
272
|
+
- `references/custom-ui.md` — composing custom call surfaces (PiP integration via the `pictureInPicture` prop pattern)
|
|
273
|
+
- `references/voip-push-end-to-end.md` — CallKit which handles iOS PiP for free
|
|
274
|
+
- `cometchat-android-v5-calls/references/picture-in-picture.md` — Android-native PiP reference (deeper Android-specific patterns)
|
|
275
|
+
- `cometchat-react-calls/references/picture-in-picture.md` — Web PiP (different APIs but same UX shape)
|
|
276
|
+
- `cometchat-native-calls` SKILL.md — base hard rules
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
# Raise hand on React Native
|
|
2
|
+
|
|
3
|
+
Same SDK API as web (`@cometchat/calls-sdk-react-native` exposes the same calls). The difference is the UI surface — native components instead of HTML, RN re-renders with state, no `aria-pressed` (use `accessibilityState` instead).
|
|
4
|
+
|
|
5
|
+
**Canonical docs:** https://www.cometchat.com/docs/calls/react-native/raise-hand
|
|
6
|
+
**Read first:** `cometchat-react-calls/references/raise-hand.md` — the integration shape and anti-patterns are identical; this reference covers RN-specific wiring.
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## SDK API
|
|
11
|
+
|
|
12
|
+
```ts
|
|
13
|
+
import { CometChatCalls } from "@cometchat/calls-sdk-react-native";
|
|
14
|
+
|
|
15
|
+
CometChatCalls.raiseHand();
|
|
16
|
+
CometChatCalls.lowerHand();
|
|
17
|
+
|
|
18
|
+
CometChatCalls.addEventListener("onParticipantHandRaised", (p) => { ... });
|
|
19
|
+
CometChatCalls.addEventListener("onParticipantHandLowered", (p) => { ... });
|
|
20
|
+
|
|
21
|
+
const settings = new CometChatCalls.CallSettingsBuilder()
|
|
22
|
+
.setSessionID(sessionId)
|
|
23
|
+
.hideRaiseHandButton(true)
|
|
24
|
+
.build();
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## RN-specific UX patterns
|
|
30
|
+
|
|
31
|
+
### Toggle button (TouchableOpacity)
|
|
32
|
+
|
|
33
|
+
```tsx
|
|
34
|
+
import { useState } from "react";
|
|
35
|
+
import { TouchableOpacity, Text, AccessibilityInfo } from "react-native";
|
|
36
|
+
import { CometChatCalls } from "@cometchat/calls-sdk-react-native";
|
|
37
|
+
|
|
38
|
+
function RaiseHandButton() {
|
|
39
|
+
const [raised, setRaised] = useState(false);
|
|
40
|
+
|
|
41
|
+
function toggle() {
|
|
42
|
+
if (raised) {
|
|
43
|
+
CometChatCalls.lowerHand();
|
|
44
|
+
setRaised(false);
|
|
45
|
+
AccessibilityInfo.announceForAccessibility("Hand lowered");
|
|
46
|
+
} else {
|
|
47
|
+
CometChatCalls.raiseHand();
|
|
48
|
+
setRaised(true);
|
|
49
|
+
AccessibilityInfo.announceForAccessibility("Hand raised");
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return (
|
|
54
|
+
<TouchableOpacity
|
|
55
|
+
onPress={toggle}
|
|
56
|
+
accessibilityRole="button"
|
|
57
|
+
accessibilityState={{ selected: raised }}
|
|
58
|
+
accessibilityLabel={raised ? "Lower hand" : "Raise hand"}
|
|
59
|
+
style={{
|
|
60
|
+
padding: 12,
|
|
61
|
+
borderRadius: 32,
|
|
62
|
+
backgroundColor: raised ? "#FFD60A" : "rgba(255,255,255,0.2)",
|
|
63
|
+
}}
|
|
64
|
+
>
|
|
65
|
+
<Text style={{ color: raised ? "#000" : "#FFF" }}>
|
|
66
|
+
✋ {raised ? "Lower" : "Raise"}
|
|
67
|
+
</Text>
|
|
68
|
+
</TouchableOpacity>
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
`AccessibilityInfo.announceForAccessibility` is the RN equivalent of web's `aria-live` regions — TalkBack / VoiceOver pick up the announcement. This is the canonical RN a11y pattern (cf. `cometchat-a11y`).
|
|
74
|
+
|
|
75
|
+
### Raised-hands roster (BottomSheet pattern)
|
|
76
|
+
|
|
77
|
+
For a host's "raised hands" list, the natural RN UX is a bottom sheet rather than a permanent sidebar (vertical phone screens are tight on horizontal real estate):
|
|
78
|
+
|
|
79
|
+
```tsx
|
|
80
|
+
import { useEffect, useRef, useState } from "react";
|
|
81
|
+
import { View, Text, FlatList } from "react-native";
|
|
82
|
+
import BottomSheet from "@gorhom/bottom-sheet";
|
|
83
|
+
import { CometChatCalls } from "@cometchat/calls-sdk-react-native";
|
|
84
|
+
|
|
85
|
+
interface RaisedParticipant { uid: string; name: string; raisedAt: number; }
|
|
86
|
+
|
|
87
|
+
function RaisedHandsSheet() {
|
|
88
|
+
const sheetRef = useRef<BottomSheet>(null);
|
|
89
|
+
const [raised, setRaised] = useState<Map<string, RaisedParticipant>>(new Map());
|
|
90
|
+
|
|
91
|
+
useEffect(() => {
|
|
92
|
+
const onRaised = (p: { uid: string; name: string }) => {
|
|
93
|
+
setRaised(prev => new Map(prev).set(p.uid, { ...p, raisedAt: Date.now() }));
|
|
94
|
+
// Auto-expand the sheet on first hand raised
|
|
95
|
+
if (raised.size === 0) sheetRef.current?.snapToIndex(1);
|
|
96
|
+
};
|
|
97
|
+
const onLowered = (p: { uid: string }) => {
|
|
98
|
+
setRaised(prev => {
|
|
99
|
+
const next = new Map(prev);
|
|
100
|
+
next.delete(p.uid);
|
|
101
|
+
return next;
|
|
102
|
+
});
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
CometChatCalls.addEventListener("onParticipantHandRaised", onRaised);
|
|
106
|
+
CometChatCalls.addEventListener("onParticipantHandLowered", onLowered);
|
|
107
|
+
return () => {
|
|
108
|
+
CometChatCalls.removeEventListener("onParticipantHandRaised", onRaised);
|
|
109
|
+
CometChatCalls.removeEventListener("onParticipantHandLowered", onLowered);
|
|
110
|
+
};
|
|
111
|
+
}, [raised.size]);
|
|
112
|
+
|
|
113
|
+
const sorted = Array.from(raised.values()).sort((a, b) => a.raisedAt - b.raisedAt);
|
|
114
|
+
|
|
115
|
+
return (
|
|
116
|
+
<BottomSheet ref={sheetRef} snapPoints={["10%", "40%"]} index={raised.size > 0 ? 1 : 0}>
|
|
117
|
+
<View style={{ padding: 16 }}>
|
|
118
|
+
<Text style={{ fontWeight: "600", marginBottom: 8 }}>
|
|
119
|
+
Raised hands ({raised.size})
|
|
120
|
+
</Text>
|
|
121
|
+
<FlatList
|
|
122
|
+
data={sorted}
|
|
123
|
+
keyExtractor={(p) => p.uid}
|
|
124
|
+
renderItem={({ item }) => (
|
|
125
|
+
<Text style={{ paddingVertical: 6 }}>
|
|
126
|
+
✋ {item.name}
|
|
127
|
+
</Text>
|
|
128
|
+
)}
|
|
129
|
+
/>
|
|
130
|
+
</View>
|
|
131
|
+
</BottomSheet>
|
|
132
|
+
);
|
|
133
|
+
}
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
`@gorhom/bottom-sheet` is the canonical RN bottom-sheet library; if you've already integrated CometChat the kit's setup includes its peer deps (`react-native-gesture-handler`, `react-native-reanimated`).
|
|
137
|
+
|
|
138
|
+
### Toast for the host
|
|
139
|
+
|
|
140
|
+
```tsx
|
|
141
|
+
import Toast from "react-native-toast-message";
|
|
142
|
+
|
|
143
|
+
useEffect(() => {
|
|
144
|
+
const onRaised = (p: { name: string }) => {
|
|
145
|
+
Toast.show({
|
|
146
|
+
type: "info",
|
|
147
|
+
text1: `${p.name} raised their hand`,
|
|
148
|
+
visibilityTime: 4000,
|
|
149
|
+
position: "top",
|
|
150
|
+
});
|
|
151
|
+
};
|
|
152
|
+
CometChatCalls.addEventListener("onParticipantHandRaised", onRaised);
|
|
153
|
+
return () => CometChatCalls.removeEventListener("onParticipantHandRaised", onRaised);
|
|
154
|
+
}, []);
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
---
|
|
158
|
+
|
|
159
|
+
## When to gate raise-hand UI
|
|
160
|
+
|
|
161
|
+
Same rule as web: hide for 1:1 calls. Gate on participant count:
|
|
162
|
+
|
|
163
|
+
```tsx
|
|
164
|
+
const showRaiseHand = participants.length > 2;
|
|
165
|
+
return showRaiseHand ? <RaiseHandButton /> : null;
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
---
|
|
169
|
+
|
|
170
|
+
## Anti-patterns
|
|
171
|
+
|
|
172
|
+
Same shape as web (cf. sister reference) plus RN-specific:
|
|
173
|
+
|
|
174
|
+
1. **Forgetting `accessibilityRole="button"`.** TouchableOpacity defaults to "image" or no role — TalkBack reads it wrong. Always set the role.
|
|
175
|
+
2. **`Toast.show` from inside the SDK callback without UI-thread guarantee.** Toast lib usually handles this, but if you use a custom toast, wrap in `requestAnimationFrame` or check that the call from the SDK callback is on the JS thread.
|
|
176
|
+
3. **BottomSheet with a single snap-point.** Use 2 snaps so users can collapse without dismissing entirely.
|
|
177
|
+
4. **Animating the raise-hand badge with Reanimated `withSpring`** in a video-call context. CPU-intensive; can stutter the WebRTC pipeline. Use `withTiming` with short durations or skip the animation.
|
|
178
|
+
|
|
179
|
+
---
|
|
180
|
+
|
|
181
|
+
## Verification checklist
|
|
182
|
+
|
|
183
|
+
- [ ] `raiseHand()` / `lowerHand()` wired to your toggle button
|
|
184
|
+
- [ ] Both event listeners registered + cleaned up
|
|
185
|
+
- [ ] `accessibilityState`, `accessibilityRole`, `accessibilityLabel` on the toggle button
|
|
186
|
+
- [ ] `AccessibilityInfo.announceForAccessibility` on state change
|
|
187
|
+
- [ ] Roster sorted by `raisedAt` ascending
|
|
188
|
+
- [ ] `hideRaiseHandButton: true` in CallSettings if custom UI
|
|
189
|
+
- [ ] Real-device smoke: 3 devices in same call, hand-raise from 2 → host's BottomSheet shows both
|
|
190
|
+
- [ ] iOS device: VoiceOver announces "Hand raised" / "Hand lowered"
|
|
191
|
+
- [ ] Android device: TalkBack announces same
|
|
192
|
+
- [ ] Visual at 360×640 (small Android phone) — button + sheet still legible
|
|
193
|
+
|
|
194
|
+
---
|
|
195
|
+
|
|
196
|
+
## Pointers
|
|
197
|
+
|
|
198
|
+
- `cometchat-react-calls/references/raise-hand.md` — sister reference (same SDK, web-flavored UI)
|
|
199
|
+
- `cometchat-native-calls` SKILL.md — the seven hard rules
|
|
200
|
+
- `references/group-calls.md` — group call architecture
|
|
201
|
+
- `references/custom-ui.md` — RN custom call UI
|
|
202
|
+
- `cometchat-a11y` — RN announcement patterns
|
|
203
|
+
- Canonical docs: https://www.cometchat.com/docs/calls/react-native/raise-hand
|