@stream-io/video-react-native-sdk 1.12.0 → 1.13.1
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/CHANGELOG.md +19 -0
- package/android/build.gradle +2 -0
- package/android/src/main/java/com/streamvideo/reactnative/StreamVideoReactNativeModule.kt +72 -0
- package/android/src/main/java/com/streamvideo/reactnative/util/YuvFrame.kt +97 -0
- package/dist/commonjs/components/Call/CallContent/CallContent.js +1 -2
- package/dist/commonjs/components/Call/CallContent/CallContent.js.map +1 -1
- package/dist/commonjs/components/Call/CallContent/RTCViewPipIOS.js +1 -2
- package/dist/commonjs/components/Call/CallContent/RTCViewPipIOS.js.map +1 -1
- package/dist/commonjs/components/Call/CallControls/AcceptCallButton.js +1 -2
- package/dist/commonjs/components/Call/CallControls/AcceptCallButton.js.map +1 -1
- package/dist/commonjs/components/Call/CallControls/LobbyControls.js +1 -2
- package/dist/commonjs/components/Call/CallControls/LobbyControls.js.map +1 -1
- package/dist/commonjs/components/Call/CallControls/ReactionsButton.js +1 -2
- package/dist/commonjs/components/Call/CallControls/ReactionsButton.js.map +1 -1
- package/dist/commonjs/components/Call/CallControls/RejectCallButton.js +1 -2
- package/dist/commonjs/components/Call/CallControls/RejectCallButton.js.map +1 -1
- package/dist/commonjs/components/Call/CallControls/ScreenShareToggleButton.js +1 -2
- package/dist/commonjs/components/Call/CallControls/ScreenShareToggleButton.js.map +1 -1
- package/dist/commonjs/components/Call/CallControls/internal/ReactionsPicker.js +1 -2
- package/dist/commonjs/components/Call/CallControls/internal/ReactionsPicker.js.map +1 -1
- package/dist/commonjs/components/Call/CallLayout/CallParticipantsSpotlight.js +1 -2
- package/dist/commonjs/components/Call/CallLayout/CallParticipantsSpotlight.js.map +1 -1
- package/dist/commonjs/components/Call/CallParticipantsList/CallParticipantsList.js +1 -2
- package/dist/commonjs/components/Call/CallParticipantsList/CallParticipantsList.js.map +1 -1
- package/dist/commonjs/components/Call/Lobby/JoinCallButton.js +1 -2
- package/dist/commonjs/components/Call/Lobby/JoinCallButton.js.map +1 -1
- package/dist/commonjs/components/Call/Lobby/Lobby.js +1 -2
- package/dist/commonjs/components/Call/Lobby/Lobby.js.map +1 -1
- package/dist/commonjs/components/Call/Lobby/LobbyFooter.js +1 -2
- package/dist/commonjs/components/Call/Lobby/LobbyFooter.js.map +1 -1
- package/dist/commonjs/components/Livestream/HostLivestream/HostLivestream.js +1 -2
- package/dist/commonjs/components/Livestream/HostLivestream/HostLivestream.js.map +1 -1
- package/dist/commonjs/components/Livestream/LivestreamControls/HostStartStreamButton.js +1 -2
- package/dist/commonjs/components/Livestream/LivestreamControls/HostStartStreamButton.js.map +1 -1
- package/dist/commonjs/components/Livestream/LivestreamControls/ViewerLeaveStreamButton.js +1 -2
- package/dist/commonjs/components/Livestream/LivestreamControls/ViewerLeaveStreamButton.js.map +1 -1
- package/dist/commonjs/components/Livestream/LivestreamLayout/LivestreamLayout.js +1 -2
- package/dist/commonjs/components/Livestream/LivestreamLayout/LivestreamLayout.js.map +1 -1
- package/dist/commonjs/components/Livestream/LivestreamPlayer/LivestreamPlayer.js +1 -2
- package/dist/commonjs/components/Livestream/LivestreamPlayer/LivestreamPlayer.js.map +1 -1
- package/dist/commonjs/components/Livestream/LivestreamTopView/DurationBadge.js +1 -2
- package/dist/commonjs/components/Livestream/LivestreamTopView/DurationBadge.js.map +1 -1
- package/dist/commonjs/components/Livestream/ViewerLivestream/ViewerLivestream.js +1 -2
- package/dist/commonjs/components/Livestream/ViewerLivestream/ViewerLivestream.js.map +1 -1
- package/dist/commonjs/components/Participant/FloatingParticipantView/FloatingView/AnimatedFloatingView.js +1 -2
- package/dist/commonjs/components/Participant/FloatingParticipantView/FloatingView/AnimatedFloatingView.js.map +1 -1
- package/dist/commonjs/components/Participant/FloatingParticipantView/FloatingView/ReanimatedFloatingView.js +1 -2
- package/dist/commonjs/components/Participant/FloatingParticipantView/FloatingView/ReanimatedFloatingView.js.map +1 -1
- package/dist/commonjs/components/Participant/ParticipantView/ParticipantLabel.js +1 -2
- package/dist/commonjs/components/Participant/ParticipantView/ParticipantLabel.js.map +1 -1
- package/dist/commonjs/components/Participant/ParticipantView/ParticipantReaction.js +1 -2
- package/dist/commonjs/components/Participant/ParticipantView/ParticipantReaction.js.map +1 -1
- package/dist/commonjs/components/Participant/ParticipantView/ParticipantView.js +1 -2
- package/dist/commonjs/components/Participant/ParticipantView/ParticipantView.js.map +1 -1
- package/dist/commonjs/components/Participant/ParticipantView/SpeechIndicator.js +1 -2
- package/dist/commonjs/components/Participant/ParticipantView/SpeechIndicator.js.map +1 -1
- package/dist/commonjs/components/Participant/ParticipantView/VideoRenderer.js +18 -4
- package/dist/commonjs/components/Participant/ParticipantView/VideoRenderer.js.map +1 -1
- package/dist/commonjs/contexts/BackgroundFilters.js +1 -2
- package/dist/commonjs/contexts/BackgroundFilters.js.map +1 -1
- package/dist/commonjs/contexts/StreamVideoContext.js +1 -2
- package/dist/commonjs/contexts/StreamVideoContext.js.map +1 -1
- package/dist/commonjs/contexts/ThemeContext.js +1 -2
- package/dist/commonjs/contexts/ThemeContext.js.map +1 -1
- package/dist/commonjs/contexts/internal/ScreenshotIosContext.js +77 -0
- package/dist/commonjs/contexts/internal/ScreenshotIosContext.js.map +1 -0
- package/dist/commonjs/hooks/index.js +11 -0
- package/dist/commonjs/hooks/index.js.map +1 -1
- package/dist/commonjs/hooks/useScreenshot.js +54 -0
- package/dist/commonjs/hooks/useScreenshot.js.map +1 -0
- package/dist/commonjs/icons/Lock.js +1 -2
- package/dist/commonjs/icons/Lock.js.map +1 -1
- package/dist/commonjs/icons/ScreenShare.js +1 -2
- package/dist/commonjs/icons/ScreenShare.js.map +1 -1
- package/dist/commonjs/icons/ScreenShareIndicator.js +1 -2
- package/dist/commonjs/icons/ScreenShareIndicator.js.map +1 -1
- package/dist/commonjs/icons/Settings.js +1 -2
- package/dist/commonjs/icons/Settings.js.map +1 -1
- package/dist/commonjs/icons/StopScreenShare.js +1 -2
- package/dist/commonjs/icons/StopScreenShare.js.map +1 -1
- package/dist/commonjs/providers/StreamCall/index.js +1 -2
- package/dist/commonjs/providers/StreamCall/index.js.map +1 -1
- package/dist/commonjs/providers/StreamVideo.js +3 -3
- package/dist/commonjs/providers/StreamVideo.js.map +1 -1
- package/dist/commonjs/version.js +1 -1
- package/dist/module/components/Participant/ParticipantView/VideoRenderer.js +18 -3
- package/dist/module/components/Participant/ParticipantView/VideoRenderer.js.map +1 -1
- package/dist/module/contexts/internal/ScreenshotIosContext.js +68 -0
- package/dist/module/contexts/internal/ScreenshotIosContext.js.map +1 -0
- package/dist/module/hooks/index.js +1 -0
- package/dist/module/hooks/index.js.map +1 -1
- package/dist/module/hooks/useScreenshot.js +48 -0
- package/dist/module/hooks/useScreenshot.js.map +1 -0
- package/dist/module/providers/StreamVideo.js +3 -1
- package/dist/module/providers/StreamVideo.js.map +1 -1
- package/dist/module/version.js +1 -1
- package/dist/typescript/components/Call/CallContent/RTCViewPipNative.d.ts +2 -2
- package/dist/typescript/components/Call/CallContent/RTCViewPipNative.d.ts.map +1 -1
- package/dist/typescript/components/Participant/ParticipantView/VideoRenderer.d.ts.map +1 -1
- package/dist/typescript/contexts/internal/ScreenshotIosContext.d.ts +11 -0
- package/dist/typescript/contexts/internal/ScreenshotIosContext.d.ts.map +1 -0
- package/dist/typescript/hooks/index.d.ts +1 -0
- package/dist/typescript/hooks/index.d.ts.map +1 -1
- package/dist/typescript/hooks/useScreenshot.d.ts +19 -0
- package/dist/typescript/hooks/useScreenshot.d.ts.map +1 -0
- package/dist/typescript/providers/StreamVideo.d.ts.map +1 -1
- package/dist/typescript/version.d.ts +1 -1
- package/expo-config-plugin/dist/common/{addNewLinesToAppDelegate.js → addNewLinesToAppDelegateObjc.js} +3 -3
- package/expo-config-plugin/dist/common/addToSwiftBridgingHeaderFile.js +48 -0
- package/expo-config-plugin/dist/withAppDelegate.js +216 -34
- package/ios/StreamVideoReactNative.m +96 -0
- package/package.json +23 -25
- package/src/components/Participant/ParticipantView/VideoRenderer.tsx +35 -3
- package/src/contexts/internal/ScreenshotIosContext.tsx +145 -0
- package/src/hooks/index.ts +1 -0
- package/src/hooks/useScreenshot.ts +78 -0
- package/src/providers/StreamVideo.tsx +5 -2
- package/src/version.ts +1 -1
|
@@ -5,12 +5,8 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
const config_plugins_1 = require("@expo/config-plugins");
|
|
7
7
|
const codeMod_1 = require("@expo/config-plugins/build/ios/codeMod");
|
|
8
|
-
const
|
|
9
|
-
const
|
|
10
|
-
const DID_UPDATE_PUSH_CREDENTIALS = 'pushRegistry:didUpdatePushCredentials:forType:';
|
|
11
|
-
const DID_RECEIVE_INCOMING_PUSH = 'pushRegistry:didReceiveIncomingPushWithPayload:forType:withCompletionHandler:';
|
|
12
|
-
const DID_ACTIVATE_AUDIO_SESSION = 'provider:didActivateAudioSession:audioSession';
|
|
13
|
-
const DID_DEACTIVATE_AUDIO_SESSION = 'provider:didDeactivateAudioSession:audioSession';
|
|
8
|
+
const addNewLinesToAppDelegateObjc_1 = __importDefault(require("./common/addNewLinesToAppDelegateObjc"));
|
|
9
|
+
const addToSwiftBridgingHeaderFile_1 = require("./common/addToSwiftBridgingHeaderFile");
|
|
14
10
|
const withAppDelegate = (configuration, props) => {
|
|
15
11
|
return (0, config_plugins_1.withAppDelegate)(configuration, (config) => {
|
|
16
12
|
if (!props?.ringingPushNotifications &&
|
|
@@ -20,7 +16,7 @@ const withAppDelegate = (configuration, props) => {
|
|
|
20
16
|
}
|
|
21
17
|
if (['objc', 'objcpp'].includes(config.modResults.language)) {
|
|
22
18
|
try {
|
|
23
|
-
|
|
19
|
+
config.modResults.contents = addDidFinishLaunchingWithOptionsObjc(config.modResults.contents, props.iOSEnableMultitaskingCameraAccess);
|
|
24
20
|
if (props?.ringingPushNotifications) {
|
|
25
21
|
config.modResults.contents = (0, codeMod_1.addObjcImports)(config.modResults.contents, [
|
|
26
22
|
'"RNCallKeep.h"',
|
|
@@ -29,35 +25,114 @@ const withAppDelegate = (configuration, props) => {
|
|
|
29
25
|
'"StreamVideoReactNative.h"',
|
|
30
26
|
'<WebRTC/RTCAudioSession.h>',
|
|
31
27
|
]);
|
|
32
|
-
config.modResults.contents =
|
|
33
|
-
|
|
34
|
-
config.modResults.contents =
|
|
35
|
-
config.modResults.contents =
|
|
28
|
+
config.modResults.contents =
|
|
29
|
+
addDidFinishLaunchingWithOptionsRingingObjc(config.modResults.contents, props.ringingPushNotifications);
|
|
30
|
+
config.modResults.contents = addDidUpdatePushCredentialsObjc(config.modResults.contents);
|
|
31
|
+
config.modResults.contents = addDidReceiveIncomingPushCallbackObjc(config.modResults.contents);
|
|
32
|
+
config.modResults.contents = addAudioSessionMethodsObjc(config.modResults.contents);
|
|
36
33
|
}
|
|
37
|
-
config.modResults.contents = addDidFinishLaunchingWithOptions(config.modResults.contents, props.iOSEnableMultitaskingCameraAccess);
|
|
38
34
|
return config;
|
|
39
35
|
}
|
|
40
36
|
catch (error) {
|
|
41
|
-
throw new Error(`Cannot setup StreamVideoReactNativeSDK because the AppDelegate is malformed ${error}`);
|
|
37
|
+
throw new Error(`Cannot setup StreamVideoReactNativeSDK because the AppDelegate(objc) is malformed ${error}`);
|
|
42
38
|
}
|
|
43
39
|
}
|
|
44
40
|
else {
|
|
45
|
-
|
|
41
|
+
try {
|
|
42
|
+
if (props?.ringingPushNotifications) {
|
|
43
|
+
// make it public class AppDelegate: ExpoAppDelegate, PKPushRegistryDelegate {
|
|
44
|
+
const regex = /(class\s+AppDelegate[^{]*)(\s*\{)/;
|
|
45
|
+
config.modResults.contents = config.modResults.contents.replace(regex, (match, declarationPart, openBrace) => {
|
|
46
|
+
// Check if PKPushRegistryDelegate is already in the declaration part
|
|
47
|
+
if (declarationPart.includes('PKPushRegistryDelegate')) {
|
|
48
|
+
return match; // Already present, no change needed
|
|
49
|
+
}
|
|
50
|
+
const trimmedDecl = declarationPart.trimRight();
|
|
51
|
+
// If the declaration already has a colon (superclass or other protocols)
|
|
52
|
+
if (trimmedDecl.includes(':')) {
|
|
53
|
+
return `${trimmedDecl}, PKPushRegistryDelegate${openBrace}`;
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
// No colon, so AppDelegate is the first thing to be listed after :
|
|
57
|
+
// This means the class declaration was like "class AppDelegate {"
|
|
58
|
+
return `${trimmedDecl}: PKPushRegistryDelegate${openBrace}`;
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
config.modResults.contents = (0, codeMod_1.addSwiftImports)(config.modResults.contents, ['WebRTC']);
|
|
63
|
+
(0, addToSwiftBridgingHeaderFile_1.addToSwiftBridgingHeaderFile)(config.modRequest.projectRoot, (headerFileContents) => {
|
|
64
|
+
headerFileContents = (0, codeMod_1.addObjcImports)(headerFileContents, [
|
|
65
|
+
'"ProcessorProvider.h"',
|
|
66
|
+
'"StreamVideoReactNative.h"',
|
|
67
|
+
'<WebRTCModuleOptions.h>',
|
|
68
|
+
]);
|
|
69
|
+
return headerFileContents;
|
|
70
|
+
});
|
|
71
|
+
config.modResults.contents = addDidFinishLaunchingWithOptionsSwift(config.modResults.contents, props.iOSEnableMultitaskingCameraAccess);
|
|
72
|
+
if (props?.ringingPushNotifications) {
|
|
73
|
+
config.modResults.contents = (0, codeMod_1.addSwiftImports)(config.modResults.contents, ['RNCallKeep', 'PushKit', 'RNVoipPushNotification']);
|
|
74
|
+
config.modResults.contents =
|
|
75
|
+
addDidFinishLaunchingWithOptionsRingingSwift(config.modResults.contents, props.ringingPushNotifications);
|
|
76
|
+
config.modResults.contents = addDidUpdatePushCredentialsSwift(config.modResults.contents);
|
|
77
|
+
config.modResults.contents = addDidReceiveIncomingPushCallbackSwift(config.modResults.contents);
|
|
78
|
+
config.modResults.contents = addAudioSessionMethodsSwift(config.modResults.contents);
|
|
79
|
+
}
|
|
80
|
+
return config;
|
|
81
|
+
}
|
|
82
|
+
catch (error) {
|
|
83
|
+
throw new Error(`Cannot setup StreamVideoReactNativeSDK because the AppDelegate(swift) is malformed ${error}`);
|
|
84
|
+
}
|
|
46
85
|
}
|
|
47
86
|
});
|
|
48
87
|
};
|
|
49
|
-
function
|
|
88
|
+
function addDidFinishLaunchingWithOptionsSwift(contents, iOSEnableMultitaskingCameraAccess) {
|
|
50
89
|
if (iOSEnableMultitaskingCameraAccess) {
|
|
90
|
+
const functionSelector = 'application(_:didFinishLaunchingWithOptions:)';
|
|
91
|
+
const setupMethod = `let options = WebRTCModuleOptions.sharedInstance()
|
|
92
|
+
options.enableMultitaskingCameraAccess = true`;
|
|
93
|
+
if (!contents.includes('options.enableMultitaskingCameraAccess = true')) {
|
|
94
|
+
contents = (0, codeMod_1.insertContentsInsideSwiftFunctionBlock)(contents, functionSelector, setupMethod, { position: 'head' });
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return contents;
|
|
98
|
+
}
|
|
99
|
+
function addDidFinishLaunchingWithOptionsObjc(contents, iOSEnableMultitaskingCameraAccess) {
|
|
100
|
+
if (iOSEnableMultitaskingCameraAccess) {
|
|
101
|
+
const functionSelector = 'application:didFinishLaunchingWithOptions:';
|
|
51
102
|
contents = (0, codeMod_1.addObjcImports)(contents, ['<WebRTCModuleOptions.h>']);
|
|
52
103
|
const setupMethod = `WebRTCModuleOptions *options = [WebRTCModuleOptions sharedInstance];
|
|
53
104
|
options.enableMultitaskingCameraAccess = YES;`;
|
|
54
105
|
if (!contents.includes('options.enableMultitaskingCameraAccess = YES')) {
|
|
55
|
-
contents = (0, codeMod_1.insertContentsInsideObjcFunctionBlock)(contents,
|
|
106
|
+
contents = (0, codeMod_1.insertContentsInsideObjcFunctionBlock)(contents, functionSelector, setupMethod, { position: 'head' });
|
|
56
107
|
}
|
|
57
108
|
}
|
|
58
109
|
return contents;
|
|
59
110
|
}
|
|
60
|
-
function
|
|
111
|
+
function addDidFinishLaunchingWithOptionsRingingSwift(contents, ringingPushNotifications) {
|
|
112
|
+
const functionSelector = 'application(_:didFinishLaunchingWithOptions:)';
|
|
113
|
+
const supportsVideoString = ringingPushNotifications.disableVideoIos
|
|
114
|
+
? 'false'
|
|
115
|
+
: 'true';
|
|
116
|
+
const includesCallsInRecents = ringingPushNotifications.includesCallsInRecentsIos ? 'false' : 'true';
|
|
117
|
+
const setupCallKeep = ` let localizedAppName = Bundle.main.localizedInfoDictionary?["CFBundleDisplayName"] as? String
|
|
118
|
+
let appName = Bundle.main.infoDictionary?["CFBundleDisplayName"] as? String
|
|
119
|
+
RNCallKeep.setup([
|
|
120
|
+
"appName": localizedAppName != nil ? localizedAppName! : appName as Any,
|
|
121
|
+
"supportsVideo": ${supportsVideoString},
|
|
122
|
+
"includesCallsInRecents": ${includesCallsInRecents},
|
|
123
|
+
])`;
|
|
124
|
+
if (!contents.includes('RNCallKeep.setup')) {
|
|
125
|
+
contents = (0, codeMod_1.insertContentsInsideSwiftFunctionBlock)(contents, functionSelector, setupCallKeep, { position: 'head' });
|
|
126
|
+
}
|
|
127
|
+
// call the setup of voip push notification
|
|
128
|
+
const voipSetupMethod = 'RNVoipPushNotificationManager.voipRegistration()';
|
|
129
|
+
if (!contents.includes(voipSetupMethod)) {
|
|
130
|
+
contents = (0, codeMod_1.insertContentsInsideSwiftFunctionBlock)(contents, functionSelector, ' ' /* indentation */ + voipSetupMethod, { position: 'head' });
|
|
131
|
+
}
|
|
132
|
+
return contents;
|
|
133
|
+
}
|
|
134
|
+
function addDidFinishLaunchingWithOptionsRingingObjc(contents, ringingPushNotifications) {
|
|
135
|
+
const functionSelector = 'application:didFinishLaunchingWithOptions:';
|
|
61
136
|
// call the setup RNCallKeep
|
|
62
137
|
const supportsVideoString = ringingPushNotifications.disableVideoIos
|
|
63
138
|
? '@NO'
|
|
@@ -71,64 +146,170 @@ function addDidFinishLaunchingWithOptionsRinging(contents, ringingPushNotificati
|
|
|
71
146
|
@"includesCallsInRecents": ${includesCallsInRecents},
|
|
72
147
|
}];`;
|
|
73
148
|
if (!contents.includes('[RNCallKeep setup:@')) {
|
|
74
|
-
contents = (0, codeMod_1.insertContentsInsideObjcFunctionBlock)(contents,
|
|
149
|
+
contents = (0, codeMod_1.insertContentsInsideObjcFunctionBlock)(contents, functionSelector, setupCallKeep, { position: 'head' });
|
|
75
150
|
}
|
|
76
151
|
// call the setup of voip push notification
|
|
77
152
|
const voipSetupMethod = '[RNVoipPushNotificationManager voipRegistration];';
|
|
78
153
|
if (!contents.includes(voipSetupMethod)) {
|
|
79
|
-
contents = (0, codeMod_1.insertContentsInsideObjcFunctionBlock)(contents,
|
|
154
|
+
contents = (0, codeMod_1.insertContentsInsideObjcFunctionBlock)(contents, functionSelector, voipSetupMethod, { position: 'head' });
|
|
80
155
|
}
|
|
81
156
|
return contents;
|
|
82
157
|
}
|
|
83
|
-
function
|
|
158
|
+
function addDidUpdatePushCredentialsSwift(contents) {
|
|
159
|
+
const updatedPushCredentialsMethod = 'RNVoipPushNotificationManager.didUpdate(credentials, forType: type.rawValue)';
|
|
160
|
+
if (!contents.includes(updatedPushCredentialsMethod)) {
|
|
161
|
+
const functionSelector = 'pushRegistry(_:didUpdate:for:)';
|
|
162
|
+
const codeblock = (0, codeMod_1.findSwiftFunctionCodeBlock)(contents, functionSelector);
|
|
163
|
+
if (!codeblock) {
|
|
164
|
+
return (0, codeMod_1.insertContentsInsideSwiftClassBlock)(contents, 'class AppDelegate', `
|
|
165
|
+
public func pushRegistry(
|
|
166
|
+
_ registry: PKPushRegistry,
|
|
167
|
+
didUpdate credentials: PKPushCredentials,
|
|
168
|
+
for type: PKPushType
|
|
169
|
+
) {
|
|
170
|
+
${updatedPushCredentialsMethod}
|
|
171
|
+
}
|
|
172
|
+
`, { position: 'tail' });
|
|
173
|
+
}
|
|
174
|
+
else {
|
|
175
|
+
return (0, codeMod_1.insertContentsInsideSwiftFunctionBlock)(contents, functionSelector, updatedPushCredentialsMethod, { position: 'tail' });
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
return contents;
|
|
179
|
+
}
|
|
180
|
+
function addDidUpdatePushCredentialsObjc(contents) {
|
|
84
181
|
const updatedPushCredentialsMethod = '[RNVoipPushNotificationManager didUpdatePushCredentials:credentials forType:(NSString *)type];';
|
|
85
182
|
if (!contents.includes(updatedPushCredentialsMethod)) {
|
|
86
|
-
const
|
|
183
|
+
const functionSelector = 'pushRegistry:didUpdatePushCredentials:forType:';
|
|
184
|
+
const codeblock = (0, codeMod_1.findObjcFunctionCodeBlock)(contents, functionSelector);
|
|
87
185
|
if (!codeblock) {
|
|
88
|
-
return (0,
|
|
186
|
+
return (0, addNewLinesToAppDelegateObjc_1.default)(contents, [
|
|
89
187
|
'- (void)pushRegistry:(PKPushRegistry *)registry didUpdatePushCredentials:(PKPushCredentials *)credentials forType:(PKPushType)type {',
|
|
90
188
|
' ' /* indentation */ + updatedPushCredentialsMethod,
|
|
91
189
|
'}',
|
|
92
190
|
]);
|
|
93
191
|
}
|
|
94
192
|
else {
|
|
95
|
-
return (0, codeMod_1.insertContentsInsideObjcFunctionBlock)(contents,
|
|
193
|
+
return (0, codeMod_1.insertContentsInsideObjcFunctionBlock)(contents, functionSelector, updatedPushCredentialsMethod, { position: 'tail' });
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
return contents;
|
|
197
|
+
}
|
|
198
|
+
function addAudioSessionMethodsSwift(contents) {
|
|
199
|
+
const audioSessionDidActivateMethod = 'RTCAudioSession.sharedInstance().audioSessionDidActivate(AVAudioSession.sharedInstance())';
|
|
200
|
+
if (!contents.includes(audioSessionDidActivateMethod)) {
|
|
201
|
+
const functionSelector = 'provider(_:didActivate:)';
|
|
202
|
+
if (!contents.includes('didActivateAudioSession')) {
|
|
203
|
+
contents = (0, codeMod_1.insertContentsInsideSwiftClassBlock)(contents, 'class AppDelegate', `
|
|
204
|
+
func provider(_ provider: CXProvider, didActivateAudioSession audioSession: AVAudioSession) {
|
|
205
|
+
${audioSessionDidActivateMethod}
|
|
206
|
+
}
|
|
207
|
+
`, { position: 'tail' });
|
|
208
|
+
}
|
|
209
|
+
else {
|
|
210
|
+
contents = (0, codeMod_1.insertContentsInsideSwiftFunctionBlock)(contents, functionSelector, audioSessionDidActivateMethod, { position: 'tail' });
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
const audioSessionDidDeactivateMethod = 'RTCAudioSession.sharedInstance().audioSessionDidDeactivate(AVAudioSession.sharedInstance())';
|
|
214
|
+
if (!contents.includes(audioSessionDidDeactivateMethod)) {
|
|
215
|
+
const functionSelector = 'provider(_:didDeactivate:)';
|
|
216
|
+
if (!contents.includes('didDeactivateAudioSession')) {
|
|
217
|
+
contents = (0, codeMod_1.insertContentsInsideSwiftClassBlock)(contents, 'class AppDelegate', `
|
|
218
|
+
func provider(_ provider: CXProvider, didDeactivateAudioSession audioSession: AVAudioSession) {
|
|
219
|
+
${audioSessionDidDeactivateMethod}
|
|
220
|
+
}
|
|
221
|
+
`, { position: 'tail' });
|
|
222
|
+
}
|
|
223
|
+
else {
|
|
224
|
+
contents = (0, codeMod_1.insertContentsInsideSwiftFunctionBlock)(contents, functionSelector, audioSessionDidDeactivateMethod, { position: 'tail' });
|
|
96
225
|
}
|
|
97
226
|
}
|
|
98
227
|
return contents;
|
|
99
228
|
}
|
|
100
|
-
function
|
|
229
|
+
function addAudioSessionMethodsObjc(contents) {
|
|
101
230
|
const audioSessionDidActivateMethod = '[[RTCAudioSession sharedInstance] audioSessionDidActivate:[AVAudioSession sharedInstance]];';
|
|
102
231
|
if (!contents.includes(audioSessionDidActivateMethod)) {
|
|
103
|
-
const
|
|
232
|
+
const functionSelector = 'provider:didActivateAudioSession:audioSession:';
|
|
233
|
+
const codeblock = (0, codeMod_1.findObjcFunctionCodeBlock)(contents, functionSelector);
|
|
104
234
|
if (!codeblock) {
|
|
105
|
-
contents = (0,
|
|
235
|
+
contents = (0, addNewLinesToAppDelegateObjc_1.default)(contents, [
|
|
106
236
|
'- (void) provider:(CXProvider *) provider didActivateAudioSession:(AVAudioSession *) audioSession {',
|
|
107
237
|
' ' /* indentation */ + audioSessionDidActivateMethod,
|
|
108
238
|
'}',
|
|
109
239
|
]);
|
|
110
240
|
}
|
|
111
241
|
else {
|
|
112
|
-
contents = (0, codeMod_1.insertContentsInsideObjcFunctionBlock)(contents,
|
|
242
|
+
contents = (0, codeMod_1.insertContentsInsideObjcFunctionBlock)(contents, functionSelector, audioSessionDidActivateMethod, { position: 'tail' });
|
|
113
243
|
}
|
|
114
244
|
}
|
|
115
245
|
const audioSessionDidDeactivateMethod = '[[RTCAudioSession sharedInstance] audioSessionDidDeactivate:[AVAudioSession sharedInstance]];';
|
|
116
246
|
if (!contents.includes(audioSessionDidDeactivateMethod)) {
|
|
117
|
-
const
|
|
247
|
+
const functionSelector = 'provider:didDeactivateAudioSession:audioSession:';
|
|
248
|
+
const codeblock = (0, codeMod_1.findObjcFunctionCodeBlock)(contents, functionSelector);
|
|
118
249
|
if (!codeblock) {
|
|
119
|
-
contents = (0,
|
|
250
|
+
contents = (0, addNewLinesToAppDelegateObjc_1.default)(contents, [
|
|
120
251
|
'- (void) provider:(CXProvider *) provider didDeactivateAudioSession:(AVAudioSession *) audioSession {',
|
|
121
252
|
' ' /* indentation */ + audioSessionDidDeactivateMethod,
|
|
122
253
|
'}',
|
|
123
254
|
]);
|
|
124
255
|
}
|
|
125
256
|
else {
|
|
126
|
-
contents = (0, codeMod_1.insertContentsInsideObjcFunctionBlock)(contents,
|
|
257
|
+
contents = (0, codeMod_1.insertContentsInsideObjcFunctionBlock)(contents, functionSelector, audioSessionDidDeactivateMethod, { position: 'tail' });
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
return contents;
|
|
261
|
+
}
|
|
262
|
+
function addDidReceiveIncomingPushCallbackSwift(contents) {
|
|
263
|
+
const onIncomingPush = `
|
|
264
|
+
guard let stream = payload.dictionaryPayload["stream"] as? [String: Any],
|
|
265
|
+
let createdCallerName = stream["created_by_display_name"] as? String,
|
|
266
|
+
let cid = stream["call_cid"] as? String else {
|
|
267
|
+
completion()
|
|
268
|
+
return
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
let uuid = UUID().uuidString
|
|
272
|
+
|
|
273
|
+
StreamVideoReactNative.registerIncomingCall(cid, uuid: uuid)
|
|
274
|
+
|
|
275
|
+
RNVoipPushNotificationManager.addCompletionHandler(uuid, completionHandler: completion)
|
|
276
|
+
|
|
277
|
+
RNVoipPushNotificationManager.didReceiveIncomingPush(with: payload, forType: type.rawValue)
|
|
278
|
+
|
|
279
|
+
RNCallKeep.reportNewIncomingCall(uuid,
|
|
280
|
+
handle: createdCallerName,
|
|
281
|
+
handleType: "generic",
|
|
282
|
+
hasVideo: true,
|
|
283
|
+
localizedCallerName: createdCallerName,
|
|
284
|
+
supportsHolding: true,
|
|
285
|
+
supportsDTMF: true,
|
|
286
|
+
supportsGrouping: true,
|
|
287
|
+
supportsUngrouping: true,
|
|
288
|
+
fromPushKit: true,
|
|
289
|
+
payload: stream,
|
|
290
|
+
withCompletionHandler: nil)`;
|
|
291
|
+
if (!contents.includes('RNVoipPushNotificationManager.didReceiveIncomingPush')) {
|
|
292
|
+
const functionSelector = 'pushRegistry(_:didReceiveIncomingPushWith:for:completion:)';
|
|
293
|
+
const codeblock = (0, codeMod_1.findSwiftFunctionCodeBlock)(contents, functionSelector);
|
|
294
|
+
if (!codeblock) {
|
|
295
|
+
return (0, codeMod_1.insertContentsInsideSwiftClassBlock)(contents, 'class AppDelegate', `
|
|
296
|
+
public func pushRegistry(
|
|
297
|
+
_ registry: PKPushRegistry,
|
|
298
|
+
didReceiveIncomingPushWith payload: PKPushPayload,
|
|
299
|
+
for type: PKPushType,
|
|
300
|
+
completion: @escaping () -> Void
|
|
301
|
+
) {
|
|
302
|
+
${onIncomingPush}
|
|
303
|
+
}
|
|
304
|
+
`, { position: 'tail' });
|
|
305
|
+
}
|
|
306
|
+
else {
|
|
307
|
+
return (0, codeMod_1.insertContentsInsideSwiftFunctionBlock)(contents, functionSelector, onIncomingPush, { position: 'tail' });
|
|
127
308
|
}
|
|
128
309
|
}
|
|
129
310
|
return contents;
|
|
130
311
|
}
|
|
131
|
-
function
|
|
312
|
+
function addDidReceiveIncomingPushCallbackObjc(contents) {
|
|
132
313
|
const onIncomingPush = `
|
|
133
314
|
// process the payload and store it in the native module's cache
|
|
134
315
|
NSDictionary *stream = payload.dictionaryPayload[@"stream"];
|
|
@@ -160,16 +341,17 @@ function addDidReceiveIncomingPushCallback(contents) {
|
|
|
160
341
|
withCompletionHandler: nil];
|
|
161
342
|
`;
|
|
162
343
|
if (!contents.includes('[RNVoipPushNotificationManager didReceiveIncomingPushWithPayload')) {
|
|
163
|
-
const
|
|
344
|
+
const functionSelector = 'pushRegistry:didReceiveIncomingPushWithPayload:forType:withCompletionHandler:';
|
|
345
|
+
const codeblock = (0, codeMod_1.findObjcFunctionCodeBlock)(contents, functionSelector);
|
|
164
346
|
if (!codeblock) {
|
|
165
|
-
return (0,
|
|
347
|
+
return (0, addNewLinesToAppDelegateObjc_1.default)(contents, [
|
|
166
348
|
'- (void)pushRegistry:(PKPushRegistry *)registry didReceiveIncomingPushWithPayload:(PKPushPayload *)payload forType:(PKPushType)type withCompletionHandler:(void (^)(void))completion {',
|
|
167
349
|
...onIncomingPush.trim().split('\n'),
|
|
168
350
|
'}',
|
|
169
351
|
]);
|
|
170
352
|
}
|
|
171
353
|
else {
|
|
172
|
-
return (0, codeMod_1.insertContentsInsideObjcFunctionBlock)(contents,
|
|
354
|
+
return (0, codeMod_1.insertContentsInsideObjcFunctionBlock)(contents, functionSelector, onIncomingPush, { position: 'tail' });
|
|
173
355
|
}
|
|
174
356
|
}
|
|
175
357
|
return contents;
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
#import <React/RCTBridgeModule.h>
|
|
2
2
|
#import <React/RCTEventEmitter.h>
|
|
3
|
+
#import <React/RCTUIManager.h>
|
|
4
|
+
#import <UIKit/UIKit.h>
|
|
3
5
|
#import "StreamVideoReactNative.h"
|
|
4
6
|
#import "WebRTCModule.h"
|
|
5
7
|
#import "WebRTCModuleOptions.h"
|
|
@@ -29,6 +31,12 @@ void broadcastNotificationCallback(CFNotificationCenterRef center,
|
|
|
29
31
|
}
|
|
30
32
|
RCT_EXPORT_MODULE();
|
|
31
33
|
|
|
34
|
+
// the viewRegistry approach is taken from https://github.com/facebook/react-native/issues/50800#issuecomment-2823327307
|
|
35
|
+
#ifdef RCT_NEW_ARCH_ENABLED
|
|
36
|
+
@synthesize viewRegistry_DEPRECATED = _viewRegistry_DEPRECATED;
|
|
37
|
+
#endif // RCT_NEW_ARCH_ENABLED
|
|
38
|
+
@synthesize bridge = _bridge;
|
|
39
|
+
|
|
32
40
|
+(BOOL)requiresMainQueueSetup {
|
|
33
41
|
return NO;
|
|
34
42
|
}
|
|
@@ -225,6 +233,94 @@ RCT_EXPORT_METHOD(removeIncomingCall:(NSString *)cid
|
|
|
225
233
|
});
|
|
226
234
|
}
|
|
227
235
|
|
|
236
|
+
RCT_EXPORT_METHOD(captureRef:(nonnull NSNumber *)reactTag
|
|
237
|
+
options:(NSDictionary *)options
|
|
238
|
+
resolver:(RCTPromiseResolveBlock)resolve
|
|
239
|
+
rejecter:(RCTPromiseRejectBlock)reject)
|
|
240
|
+
{
|
|
241
|
+
#ifdef RCT_NEW_ARCH_ENABLED
|
|
242
|
+
[self.viewRegistry_DEPRECATED addUIBlock:^(RCTViewRegistry *viewRegistry) {
|
|
243
|
+
UIView *view = [self.viewRegistry_DEPRECATED viewForReactTag:reactTag];
|
|
244
|
+
|
|
245
|
+
#else
|
|
246
|
+
[self.bridge.uiManager
|
|
247
|
+
addUIBlock:^(RCTUIManager *uiManager, NSDictionary<NSNumber *, UIView *> *viewRegistry) {
|
|
248
|
+
UIView *view = [uiManager viewForReactTag:reactTag];
|
|
249
|
+
#endif
|
|
250
|
+
|
|
251
|
+
if (!view) {
|
|
252
|
+
reject(RCTErrorUnspecified, [NSString stringWithFormat:@"No view found with reactTag: %@", reactTag], nil);
|
|
253
|
+
return;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
// Get capture options
|
|
257
|
+
NSString *format = options[@"format"] ? [options[@"format"] lowercaseString] : @"png";
|
|
258
|
+
CGFloat quality = options[@"quality"] ? [options[@"quality"] floatValue] : 1.0;
|
|
259
|
+
NSNumber *width = options[@"width"];
|
|
260
|
+
NSNumber *height = options[@"height"];
|
|
261
|
+
|
|
262
|
+
// Determine the size to render
|
|
263
|
+
CGSize size;
|
|
264
|
+
CGRect bounds = view.bounds;
|
|
265
|
+
if (width && height) {
|
|
266
|
+
size = CGSizeMake([width floatValue], [height floatValue]);
|
|
267
|
+
} else {
|
|
268
|
+
size = bounds.size;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
// Abort if size is invalid
|
|
272
|
+
if (size.width <= 0 || size.height <= 0) {
|
|
273
|
+
reject(@"INVALID_SIZE", @"View has invalid size", nil);
|
|
274
|
+
return;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
// Begin image context with appropriate scale
|
|
278
|
+
UIGraphicsBeginImageContextWithOptions(size, NO, 0);
|
|
279
|
+
|
|
280
|
+
// Calculate scaling if needed
|
|
281
|
+
CGRect drawRect = bounds;
|
|
282
|
+
if (width && height) {
|
|
283
|
+
CGFloat scaleX = size.width / bounds.size.width;
|
|
284
|
+
CGFloat scaleY = size.height / bounds.size.height;
|
|
285
|
+
|
|
286
|
+
// Apply transform to context for scaling if dimensions differ
|
|
287
|
+
CGContextRef context = UIGraphicsGetCurrentContext();
|
|
288
|
+
if (context) {
|
|
289
|
+
CGContextTranslateCTM(context, 0, size.height);
|
|
290
|
+
CGContextScaleCTM(context, scaleX, -scaleY);
|
|
291
|
+
drawRect = CGRectMake(0, 0, bounds.size.width, bounds.size.height);
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
BOOL success = [view drawViewHierarchyInRect:drawRect afterScreenUpdates:YES];
|
|
296
|
+
|
|
297
|
+
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
|
|
298
|
+
UIGraphicsEndImageContext();
|
|
299
|
+
|
|
300
|
+
if (!success || !image) {
|
|
301
|
+
reject(@"CAPTURE_FAILED", @"Failed to capture view as image", nil);
|
|
302
|
+
return;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
// Convert to base64 string based on format
|
|
306
|
+
NSString *base64;
|
|
307
|
+
if ([format isEqualToString:@"jpg"] || [format isEqualToString:@"jpeg"]) {
|
|
308
|
+
NSData *imageData = UIImageJPEGRepresentation(image, quality);
|
|
309
|
+
base64 = [imageData base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithCarriageReturn];
|
|
310
|
+
} else {
|
|
311
|
+
// Default to PNG
|
|
312
|
+
NSData *imageData = UIImagePNGRepresentation(image);
|
|
313
|
+
base64 = [imageData base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithCarriageReturn];
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
if (base64) {
|
|
317
|
+
resolve(base64);
|
|
318
|
+
} else {
|
|
319
|
+
reject(@"ENCODING_FAILED", @"Failed to encode image to base64", nil);
|
|
320
|
+
}
|
|
321
|
+
}];
|
|
322
|
+
}
|
|
323
|
+
|
|
228
324
|
-(NSArray<NSString *> *)supportedEvents {
|
|
229
325
|
return @[@"StreamVideoReactNative_Ios_Screenshare_Event", @"isLowPowerModeEnabled", @"thermalStateDidChange"];
|
|
230
326
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stream-io/video-react-native-sdk",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.13.1",
|
|
4
4
|
"description": "Stream Video SDK for React Native",
|
|
5
5
|
"author": "https://getstream.io",
|
|
6
6
|
"homepage": "https://getstream.io/video/docs/react-native/",
|
|
@@ -45,8 +45,8 @@
|
|
|
45
45
|
"!**/.*"
|
|
46
46
|
],
|
|
47
47
|
"dependencies": {
|
|
48
|
-
"@stream-io/video-client": "1.
|
|
49
|
-
"@stream-io/video-react-bindings": "1.
|
|
48
|
+
"@stream-io/video-client": "1.22.0",
|
|
49
|
+
"@stream-io/video-react-bindings": "1.6.0",
|
|
50
50
|
"intl-pluralrules": "2.0.1",
|
|
51
51
|
"lodash.merge": "^4.6.2",
|
|
52
52
|
"react-native-url-polyfill": "1.3.0",
|
|
@@ -59,7 +59,7 @@
|
|
|
59
59
|
"@react-native-community/push-notification-ios": ">=1.11.0",
|
|
60
60
|
"@react-native-firebase/app": ">=17.5.0",
|
|
61
61
|
"@react-native-firebase/messaging": ">=17.5.0",
|
|
62
|
-
"@stream-io/react-native-webrtc": ">=125.
|
|
62
|
+
"@stream-io/react-native-webrtc": ">=125.2.1",
|
|
63
63
|
"@stream-io/video-filters-react-native": ">=0.1.0",
|
|
64
64
|
"expo": ">=47.0.0",
|
|
65
65
|
"expo-build-properties": "*",
|
|
@@ -112,45 +112,43 @@
|
|
|
112
112
|
}
|
|
113
113
|
},
|
|
114
114
|
"devDependencies": {
|
|
115
|
-
"@expo/config-plugins": "
|
|
116
|
-
"@expo/config-types": "^
|
|
117
|
-
"@expo/plist": "^0.
|
|
115
|
+
"@expo/config-plugins": "10.0.2",
|
|
116
|
+
"@expo/config-types": "^53.0.4",
|
|
117
|
+
"@expo/plist": "^0.3.4",
|
|
118
118
|
"@notifee/react-native": "9.1.8",
|
|
119
119
|
"@react-native-community/netinfo": "11.4.1",
|
|
120
120
|
"@react-native-community/push-notification-ios": "1.11.0",
|
|
121
|
-
"@react-native-firebase/app": "^
|
|
122
|
-
"@react-native-firebase/messaging": "^
|
|
123
|
-
"@react-native/babel-preset": "^0.
|
|
124
|
-
"@stream-io/react-native-webrtc": "^125.2.
|
|
125
|
-
"@stream-io/video-filters-react-native": "^0.
|
|
121
|
+
"@react-native-firebase/app": "^22.1.0",
|
|
122
|
+
"@react-native-firebase/messaging": "^22.1.0",
|
|
123
|
+
"@react-native/babel-preset": "^0.79.2",
|
|
124
|
+
"@stream-io/react-native-webrtc": "^125.2.1",
|
|
125
|
+
"@stream-io/video-filters-react-native": "^0.3.0",
|
|
126
126
|
"@testing-library/jest-native": "^5.4.3",
|
|
127
|
-
"@testing-library/react-native": "
|
|
127
|
+
"@testing-library/react-native": "13.2.0",
|
|
128
128
|
"@tsconfig/node14": "14.1.3",
|
|
129
129
|
"@types/jest": "^29.5.14",
|
|
130
130
|
"@types/lodash.merge": "^4.6.9",
|
|
131
|
-
"@types/react": "^
|
|
131
|
+
"@types/react": "^19.1.3",
|
|
132
132
|
"@types/react-native-incall-manager": "^4.0.3",
|
|
133
|
-
"@types/react-test-renderer": "^
|
|
134
|
-
"expo": "~
|
|
133
|
+
"@types/react-test-renderer": "^19.1.0",
|
|
134
|
+
"expo": "~53.0.8",
|
|
135
135
|
"expo-build-properties": "^0.13.2",
|
|
136
136
|
"expo-module-scripts": "^4.0.5",
|
|
137
137
|
"expo-modules-core": "2.2.3",
|
|
138
138
|
"expo-notifications": "~0.29.14",
|
|
139
139
|
"jest": "^29.7.0",
|
|
140
|
-
"react
|
|
140
|
+
"react": "19.0.0",
|
|
141
|
+
"react-native": "0.79.2",
|
|
141
142
|
"react-native-builder-bob": "~0.23",
|
|
142
143
|
"react-native-callkeep": "^4.3.16",
|
|
143
144
|
"react-native-gesture-handler": "^2.25.0",
|
|
144
|
-
"react-native-incall-manager": "^4.2.
|
|
145
|
-
"react-native-reanimated": "~3.
|
|
145
|
+
"react-native-incall-manager": "^4.2.1",
|
|
146
|
+
"react-native-reanimated": "~3.17.5",
|
|
146
147
|
"react-native-svg": "15.11.2",
|
|
147
|
-
"react-native-voip-push-notification": "3.3.
|
|
148
|
-
"react-test-renderer": "
|
|
148
|
+
"react-native-voip-push-notification": "3.3.3",
|
|
149
|
+
"react-test-renderer": "19.0.0",
|
|
149
150
|
"rimraf": "^6.0.1",
|
|
150
|
-
"typescript": "^5.8.
|
|
151
|
-
},
|
|
152
|
-
"resolutions": {
|
|
153
|
-
"@types/react": "^18.2.44"
|
|
151
|
+
"typescript": "^5.8.3"
|
|
154
152
|
},
|
|
155
153
|
"react-native-builder-bob": {
|
|
156
154
|
"source": "src",
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React, { useEffect, useRef } from 'react';
|
|
2
|
-
import { StyleSheet, View } from 'react-native';
|
|
2
|
+
import { Platform, StyleSheet, View } from 'react-native';
|
|
3
3
|
import type { MediaStream } from '@stream-io/react-native-webrtc';
|
|
4
4
|
import { RTCView } from '@stream-io/react-native-webrtc';
|
|
5
5
|
import type { ParticipantViewProps } from './ParticipantView';
|
|
@@ -15,6 +15,7 @@ import { useCall, useCallStateHooks } from '@stream-io/video-react-bindings';
|
|
|
15
15
|
import { ParticipantVideoFallback as DefaultParticipantVideoFallback } from './ParticipantVideoFallback';
|
|
16
16
|
import { useTheme } from '../../../contexts/ThemeContext';
|
|
17
17
|
import { useTrackDimensions } from '../../../hooks/useTrackDimensions';
|
|
18
|
+
import { useScreenshotIosContext } from '../../../contexts/internal/ScreenshotIosContext';
|
|
18
19
|
|
|
19
20
|
const DEFAULT_VIEWPORT_VISIBILITY_STATE: Record<
|
|
20
21
|
VideoTrackType,
|
|
@@ -58,9 +59,19 @@ export const VideoRenderer = ({
|
|
|
58
59
|
useCallStateHooks();
|
|
59
60
|
const { isParticipantVideoEnabled } = useIncomingVideoSettings();
|
|
60
61
|
const callingState = useCallCallingState();
|
|
61
|
-
const pendingVideoLayoutRef = useRef<SfuModels.VideoDimension>(
|
|
62
|
-
|
|
62
|
+
const pendingVideoLayoutRef = useRef<SfuModels.VideoDimension | undefined>(
|
|
63
|
+
undefined,
|
|
64
|
+
);
|
|
65
|
+
const subscribedVideoLayoutRef = useRef<SfuModels.VideoDimension | undefined>(
|
|
66
|
+
undefined,
|
|
67
|
+
);
|
|
63
68
|
const { direction } = useCameraState();
|
|
69
|
+
const viewRef = useRef(null);
|
|
70
|
+
const {
|
|
71
|
+
register: registerIosScreenshot,
|
|
72
|
+
deregister: deregisterIosScreenshot,
|
|
73
|
+
} = useScreenshotIosContext();
|
|
74
|
+
|
|
64
75
|
const videoDimensions = useTrackDimensions(participant, trackType);
|
|
65
76
|
const {
|
|
66
77
|
isLocalParticipant,
|
|
@@ -86,6 +97,26 @@ export const VideoRenderer = ({
|
|
|
86
97
|
isPublishingVideoTrack &&
|
|
87
98
|
isParticipantVideoEnabled(participant.sessionId);
|
|
88
99
|
|
|
100
|
+
React.useEffect(() => {
|
|
101
|
+
if (
|
|
102
|
+
Platform.OS === 'ios' &&
|
|
103
|
+
registerIosScreenshot &&
|
|
104
|
+
viewRef.current &&
|
|
105
|
+
canShowVideo
|
|
106
|
+
) {
|
|
107
|
+
registerIosScreenshot(participant, trackType, viewRef);
|
|
108
|
+
return () => {
|
|
109
|
+
deregisterIosScreenshot(participant, trackType);
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
}, [
|
|
113
|
+
participant,
|
|
114
|
+
trackType,
|
|
115
|
+
registerIosScreenshot,
|
|
116
|
+
canShowVideo,
|
|
117
|
+
deregisterIosScreenshot,
|
|
118
|
+
]);
|
|
119
|
+
|
|
89
120
|
const mirror =
|
|
90
121
|
isLocalParticipant && !isScreenSharing && direction === 'front';
|
|
91
122
|
|
|
@@ -262,6 +293,7 @@ export const VideoRenderer = ({
|
|
|
262
293
|
style={[styles.videoStream, videoRenderer.videoStream]}
|
|
263
294
|
streamURL={videoStreamToRender.toURL()}
|
|
264
295
|
mirror={mirror}
|
|
296
|
+
ref={viewRef}
|
|
265
297
|
objectFit={
|
|
266
298
|
objectFit ??
|
|
267
299
|
(videoDimensions.width > videoDimensions.height
|