@capgo/capacitor-stream-call 0.0.2

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.
Files changed (39) hide show
  1. package/Package.swift +31 -0
  2. package/README.md +340 -0
  3. package/StreamCall.podspec +19 -0
  4. package/android/build.gradle +74 -0
  5. package/android/src/main/AndroidManifest.xml +2 -0
  6. package/android/src/main/java/ee/forgr/capacitor/streamcall/CallOverlayView.kt +281 -0
  7. package/android/src/main/java/ee/forgr/capacitor/streamcall/CustomNotificationHandler.kt +142 -0
  8. package/android/src/main/java/ee/forgr/capacitor/streamcall/IncomingCallView.kt +147 -0
  9. package/android/src/main/java/ee/forgr/capacitor/streamcall/RingtonePlayer.kt +164 -0
  10. package/android/src/main/java/ee/forgr/capacitor/streamcall/StreamCallPlugin.kt +1014 -0
  11. package/android/src/main/java/ee/forgr/capacitor/streamcall/TouchInterceptWrapper.kt +31 -0
  12. package/android/src/main/java/ee/forgr/capacitor/streamcall/UserRepository.kt +111 -0
  13. package/android/src/main/res/.gitkeep +0 -0
  14. package/android/src/main/res/values/strings.xml +7 -0
  15. package/dist/docs.json +533 -0
  16. package/dist/esm/definitions.d.ts +169 -0
  17. package/dist/esm/definitions.js +2 -0
  18. package/dist/esm/definitions.js.map +1 -0
  19. package/dist/esm/index.d.ts +4 -0
  20. package/dist/esm/index.js +7 -0
  21. package/dist/esm/index.js.map +1 -0
  22. package/dist/esm/web.d.ts +32 -0
  23. package/dist/esm/web.js +323 -0
  24. package/dist/esm/web.js.map +1 -0
  25. package/dist/plugin.cjs.js +337 -0
  26. package/dist/plugin.cjs.js.map +1 -0
  27. package/dist/plugin.js +339 -0
  28. package/dist/plugin.js.map +1 -0
  29. package/ios/Sources/StreamCallPlugin/CallOverlayView.swift +147 -0
  30. package/ios/Sources/StreamCallPlugin/CustomCallParticipantImageView.swift +60 -0
  31. package/ios/Sources/StreamCallPlugin/CustomCallView.swift +257 -0
  32. package/ios/Sources/StreamCallPlugin/CustomVideoParticipantsView.swift +107 -0
  33. package/ios/Sources/StreamCallPlugin/ParticipantsView.swift +206 -0
  34. package/ios/Sources/StreamCallPlugin/StreamCallPlugin.swift +722 -0
  35. package/ios/Sources/StreamCallPlugin/TouchInterceptView.swift +177 -0
  36. package/ios/Sources/StreamCallPlugin/UserRepository.swift +96 -0
  37. package/ios/Sources/StreamCallPlugin/WebviewNavigationDelegate.swift +68 -0
  38. package/ios/Tests/StreamCallPluginTests/StreamCallPluginTests.swift +15 -0
  39. package/package.json +96 -0
package/dist/plugin.js ADDED
@@ -0,0 +1,339 @@
1
+ var capacitorStreamCall = (function (exports, core, videoClient) {
2
+ 'use strict';
3
+
4
+ const StreamCall = core.registerPlugin('StreamCall', {
5
+ web: () => Promise.resolve().then(function () { return web; }).then((m) => new m.StreamCallWeb()),
6
+ });
7
+
8
+ class StreamCallWeb extends core.WebPlugin {
9
+ constructor() {
10
+ super(...arguments);
11
+ this.videoBindings = new Map();
12
+ this.audioBindings = new Map();
13
+ this.ringCallback = (event) => {
14
+ var _a, _b;
15
+ console.log('Call ringing', event, this.currentCall);
16
+ this.incomingCall = event.call;
17
+ if (!this.currentCall) {
18
+ console.log('Creating new call', event.call.id);
19
+ this.currentCall = (_a = this.client) === null || _a === void 0 ? void 0 : _a.call(event.call.type, event.call.id);
20
+ this.notifyListeners('callEvent', { callId: event.call.id, state: videoClient.CallingState.RINGING });
21
+ }
22
+ if (this.currentCall) {
23
+ console.log('Call found', this.currentCall.id);
24
+ this.callStateSubscription = (_b = this.currentCall) === null || _b === void 0 ? void 0 : _b.state.callingState$.subscribe((s) => {
25
+ var _a;
26
+ console.log('Call state', s);
27
+ if (s === videoClient.CallingState.JOINED) {
28
+ this.setupParticipantListener();
29
+ }
30
+ else if (s === videoClient.CallingState.LEFT || s === videoClient.CallingState.RECONNECTING_FAILED) {
31
+ this.cleanupCall();
32
+ }
33
+ if (this.outgoingCall && s === videoClient.CallingState.RINGING) {
34
+ this.outgoingCall = undefined;
35
+ }
36
+ else {
37
+ this.notifyListeners('callEvent', { callId: (_a = this.currentCall) === null || _a === void 0 ? void 0 : _a.id, state: s });
38
+ }
39
+ });
40
+ }
41
+ };
42
+ }
43
+ setupCallRingListener() {
44
+ var _a, _b;
45
+ (_a = this.client) === null || _a === void 0 ? void 0 : _a.off('call.ring', this.ringCallback);
46
+ (_b = this.client) === null || _b === void 0 ? void 0 : _b.on('call.ring', this.ringCallback);
47
+ }
48
+ setupParticipantListener() {
49
+ // Subscribe to participant changes
50
+ this.incomingCall = undefined;
51
+ if (!this.currentCall)
52
+ return;
53
+ this.participantJoinedListener = (event) => {
54
+ if (this.magicDivId && event.participant) {
55
+ const magicDiv = document.getElementById(this.magicDivId);
56
+ if (magicDiv && this.currentCall) {
57
+ this.setupParticipantVideo(this.currentCall, event.participant, magicDiv);
58
+ this.setupParticipantAudio(this.currentCall, event.participant, magicDiv);
59
+ }
60
+ }
61
+ };
62
+ this.participantLeftListener = (event) => {
63
+ if (this.magicDivId && event.participant) {
64
+ const videoId = `video-${event.participant.sessionId}`;
65
+ const audioId = `audio-${event.participant.sessionId}`;
66
+ // Remove video element
67
+ const videoEl = document.getElementById(videoId);
68
+ if (videoEl) {
69
+ const unbindVideo = this.videoBindings.get(videoId);
70
+ if (unbindVideo) {
71
+ unbindVideo();
72
+ this.videoBindings.delete(videoId);
73
+ }
74
+ const tracks = videoEl.srcObject;
75
+ if (tracks) {
76
+ tracks.getTracks().forEach((track) => {
77
+ track.stop();
78
+ track.enabled = false;
79
+ });
80
+ videoEl.srcObject = null;
81
+ }
82
+ videoEl.remove();
83
+ }
84
+ // Remove audio element
85
+ const audioEl = document.getElementById(audioId);
86
+ if (audioEl) {
87
+ const unbindAudio = this.audioBindings.get(audioId);
88
+ if (unbindAudio) {
89
+ unbindAudio();
90
+ this.audioBindings.delete(audioId);
91
+ }
92
+ const tracks = audioEl.srcObject;
93
+ if (tracks) {
94
+ tracks.getTracks().forEach((track) => {
95
+ track.stop();
96
+ track.enabled = false;
97
+ });
98
+ audioEl.srcObject = null;
99
+ }
100
+ audioEl.remove();
101
+ }
102
+ }
103
+ };
104
+ this.currentCall.on('participantJoined', this.participantJoinedListener);
105
+ this.currentCall.on('participantLeft', this.participantLeftListener);
106
+ // Setup initial participants
107
+ const participants = this.currentCall.state.participants;
108
+ if (this.magicDivId) {
109
+ const magicDiv = document.getElementById(this.magicDivId);
110
+ if (magicDiv) {
111
+ participants.forEach((participant) => {
112
+ if (this.currentCall) {
113
+ this.setupParticipantVideo(this.currentCall, participant, magicDiv);
114
+ this.setupParticipantAudio(this.currentCall, participant, magicDiv);
115
+ }
116
+ });
117
+ }
118
+ }
119
+ }
120
+ setupParticipantVideo(call, participant, container) {
121
+ const id = `video-${participant.sessionId}`;
122
+ if (!document.getElementById(id)) {
123
+ const videoEl = document.createElement('video');
124
+ videoEl.id = id;
125
+ videoEl.style.width = '100%';
126
+ videoEl.style.maxWidth = '300px';
127
+ videoEl.style.aspectRatio = '16/9';
128
+ container.appendChild(videoEl);
129
+ const unbind = call.bindVideoElement(videoEl, participant.sessionId, 'videoTrack');
130
+ if (unbind)
131
+ this.videoBindings.set(id, unbind);
132
+ }
133
+ }
134
+ setupParticipantAudio(call, participant, container) {
135
+ if (participant.isLocalParticipant)
136
+ return;
137
+ const id = `audio-${participant.sessionId}`;
138
+ if (!document.getElementById(id)) {
139
+ const audioEl = document.createElement('audio');
140
+ audioEl.id = id;
141
+ container.appendChild(audioEl);
142
+ const unbind = call.bindAudioElement(audioEl, participant.sessionId);
143
+ if (unbind)
144
+ this.audioBindings.set(id, unbind);
145
+ }
146
+ }
147
+ cleanupCall() {
148
+ var _a;
149
+ // First cleanup the call listeners
150
+ if (this.currentCall) {
151
+ if (this.participantJoinedListener) {
152
+ this.currentCall.off('participantJoined', this.participantJoinedListener);
153
+ this.participantJoinedListener = undefined;
154
+ }
155
+ if (this.participantLeftListener) {
156
+ this.currentCall.off('participantLeft', this.participantLeftListener);
157
+ this.participantLeftListener = undefined;
158
+ }
159
+ (_a = this.callStateSubscription) === null || _a === void 0 ? void 0 : _a.unsubscribe();
160
+ }
161
+ if (this.magicDivId) {
162
+ const magicDiv = document.getElementById(this.magicDivId);
163
+ if (magicDiv) {
164
+ // Remove all video elements
165
+ const videoElements = magicDiv.querySelectorAll('video');
166
+ videoElements.forEach((video) => {
167
+ const id = video.id;
168
+ const unbind = this.videoBindings.get(id);
169
+ if (unbind) {
170
+ unbind();
171
+ this.videoBindings.delete(id);
172
+ }
173
+ // Stop all tracks
174
+ const tracks = video.srcObject;
175
+ if (tracks) {
176
+ tracks.getTracks().forEach((track) => {
177
+ track.stop();
178
+ track.enabled = false;
179
+ });
180
+ video.srcObject = null;
181
+ }
182
+ video.remove();
183
+ });
184
+ // Remove all audio elements
185
+ const audioElements = magicDiv.querySelectorAll('audio');
186
+ audioElements.forEach((audio) => {
187
+ const id = audio.id;
188
+ const unbind = this.audioBindings.get(id);
189
+ if (unbind) {
190
+ unbind();
191
+ this.audioBindings.delete(id);
192
+ }
193
+ // Stop all tracks
194
+ const tracks = audio.srcObject;
195
+ if (tracks) {
196
+ tracks.getTracks().forEach((track) => {
197
+ track.stop();
198
+ track.enabled = false;
199
+ });
200
+ audio.srcObject = null;
201
+ }
202
+ audio.remove();
203
+ });
204
+ // Clear the container
205
+ while (magicDiv.firstChild) {
206
+ magicDiv.removeChild(magicDiv.firstChild);
207
+ }
208
+ }
209
+ }
210
+ // Clear all bindings
211
+ this.videoBindings.clear();
212
+ this.audioBindings.clear();
213
+ // Clear call references
214
+ this.currentCall = undefined;
215
+ this.incomingCall = undefined;
216
+ }
217
+ async login(options) {
218
+ this.client = videoClient.StreamVideoClient.getOrCreateInstance({
219
+ apiKey: options.apiKey,
220
+ user: { id: options.userId, name: options.name, image: options.imageURL },
221
+ token: options.token,
222
+ });
223
+ this.magicDivId = options.magicDivId;
224
+ this.setupCallRingListener();
225
+ return { success: true };
226
+ }
227
+ async logout() {
228
+ var _a;
229
+ if (!this.client) {
230
+ console.log('No client', this.client);
231
+ throw new Error('Client not initialized');
232
+ }
233
+ // Cleanup subscription
234
+ (_a = this.callStateSubscription) === null || _a === void 0 ? void 0 : _a.unsubscribe();
235
+ this.callStateSubscription = undefined;
236
+ await this.client.disconnectUser();
237
+ this.client = undefined;
238
+ this.currentCall = undefined;
239
+ return { success: true };
240
+ }
241
+ async call(options) {
242
+ if (!this.client) {
243
+ console.log('No client', this.client);
244
+ throw new Error('Client not initialized - Please login first');
245
+ }
246
+ const call = this.client.call(options.type || 'default', crypto.randomUUID());
247
+ const members = [{ user_id: options.userId }];
248
+ if (this.client.streamClient.userID && options.userId !== this.client.streamClient.userID) {
249
+ members.push({ user_id: this.client.streamClient.userID });
250
+ }
251
+ await call.getOrCreate({ data: { members } });
252
+ this.currentCall = call;
253
+ if (options.ring) {
254
+ this.outgoingCall = call.cid;
255
+ await call.ring();
256
+ }
257
+ await call.join();
258
+ return { success: true };
259
+ }
260
+ async endCall() {
261
+ if (!this.currentCall) {
262
+ console.log('No active call', this.currentCall);
263
+ throw new Error('No active call');
264
+ }
265
+ await this.currentCall.leave();
266
+ this.currentCall = undefined;
267
+ this.cleanupCall();
268
+ return { success: true };
269
+ }
270
+ async setMicrophoneEnabled(options) {
271
+ if (!this.currentCall) {
272
+ console.log('No active call', this.currentCall);
273
+ throw new Error('No active call');
274
+ }
275
+ if (options.enabled) {
276
+ await this.currentCall.microphone.enable();
277
+ }
278
+ else {
279
+ await this.currentCall.microphone.disable();
280
+ }
281
+ return { success: true };
282
+ }
283
+ async setCameraEnabled(options) {
284
+ if (!this.currentCall) {
285
+ console.log('No active call', this.currentCall);
286
+ throw new Error('No active call');
287
+ }
288
+ if (options.enabled) {
289
+ await this.currentCall.camera.enable();
290
+ }
291
+ else {
292
+ await this.currentCall.camera.disable();
293
+ }
294
+ return { success: true };
295
+ }
296
+ async acceptCall() {
297
+ if (!this.incomingCall || !this.client) {
298
+ console.log('No incoming call to accept', this.incomingCall, this.client);
299
+ throw new Error('No incoming call to accept');
300
+ }
301
+ console.log('Accepting call', this.incomingCall);
302
+ const call = this.client.call(this.incomingCall.type, this.incomingCall.id);
303
+ this.currentCall = call;
304
+ console.log('Joining call', call);
305
+ await call.accept();
306
+ await call.join();
307
+ console.log('Joined call', call);
308
+ this.notifyListeners('callEvent', { callId: call.id, state: videoClient.CallingState.JOINED });
309
+ this.setupParticipantListener();
310
+ return { success: true };
311
+ }
312
+ async rejectCall() {
313
+ if (!this.incomingCall || !this.client) {
314
+ console.log('No incoming call to reject', this.incomingCall, this.client);
315
+ throw new Error('No incoming call to reject');
316
+ }
317
+ console.log('Rejecting call', this.incomingCall);
318
+ const call = this.client.call(this.incomingCall.type, this.incomingCall.id);
319
+ console.log('Leaving call', call);
320
+ await call.leave();
321
+ this.incomingCall = undefined;
322
+ console.log('Rejected call', call);
323
+ this.notifyListeners('callEvent', { callId: call.id, state: videoClient.CallingState.LEFT });
324
+ this.cleanupCall();
325
+ return { success: true };
326
+ }
327
+ }
328
+
329
+ var web = /*#__PURE__*/Object.freeze({
330
+ __proto__: null,
331
+ StreamCallWeb: StreamCallWeb
332
+ });
333
+
334
+ exports.StreamCall = StreamCall;
335
+
336
+ return exports;
337
+
338
+ })({}, capacitorExports, videoClient);
339
+ //# sourceMappingURL=plugin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin.js","sources":["esm/index.js","esm/web.js"],"sourcesContent":["import { registerPlugin } from '@capacitor/core';\nconst StreamCall = registerPlugin('StreamCall', {\n web: () => import('./web').then((m) => new m.StreamCallWeb()),\n});\nexport * from './definitions';\nexport { StreamCall };\n//# sourceMappingURL=index.js.map","import { WebPlugin } from '@capacitor/core';\nimport { CallingState, StreamVideoClient } from '@stream-io/video-client';\nexport class StreamCallWeb extends WebPlugin {\n constructor() {\n super(...arguments);\n this.videoBindings = new Map();\n this.audioBindings = new Map();\n this.ringCallback = (event) => {\n var _a, _b;\n console.log('Call ringing', event, this.currentCall);\n this.incomingCall = event.call;\n if (!this.currentCall) {\n console.log('Creating new call', event.call.id);\n this.currentCall = (_a = this.client) === null || _a === void 0 ? void 0 : _a.call(event.call.type, event.call.id);\n this.notifyListeners('callEvent', { callId: event.call.id, state: CallingState.RINGING });\n }\n if (this.currentCall) {\n console.log('Call found', this.currentCall.id);\n this.callStateSubscription = (_b = this.currentCall) === null || _b === void 0 ? void 0 : _b.state.callingState$.subscribe((s) => {\n var _a;\n console.log('Call state', s);\n if (s === CallingState.JOINED) {\n this.setupParticipantListener();\n }\n else if (s === CallingState.LEFT || s === CallingState.RECONNECTING_FAILED) {\n this.cleanupCall();\n }\n if (this.outgoingCall && s === CallingState.RINGING) {\n this.outgoingCall = undefined;\n }\n else {\n this.notifyListeners('callEvent', { callId: (_a = this.currentCall) === null || _a === void 0 ? void 0 : _a.id, state: s });\n }\n });\n }\n };\n }\n setupCallRingListener() {\n var _a, _b;\n (_a = this.client) === null || _a === void 0 ? void 0 : _a.off('call.ring', this.ringCallback);\n (_b = this.client) === null || _b === void 0 ? void 0 : _b.on('call.ring', this.ringCallback);\n }\n setupParticipantListener() {\n // Subscribe to participant changes\n this.incomingCall = undefined;\n if (!this.currentCall)\n return;\n this.participantJoinedListener = (event) => {\n if (this.magicDivId && event.participant) {\n const magicDiv = document.getElementById(this.magicDivId);\n if (magicDiv && this.currentCall) {\n this.setupParticipantVideo(this.currentCall, event.participant, magicDiv);\n this.setupParticipantAudio(this.currentCall, event.participant, magicDiv);\n }\n }\n };\n this.participantLeftListener = (event) => {\n if (this.magicDivId && event.participant) {\n const videoId = `video-${event.participant.sessionId}`;\n const audioId = `audio-${event.participant.sessionId}`;\n // Remove video element\n const videoEl = document.getElementById(videoId);\n if (videoEl) {\n const unbindVideo = this.videoBindings.get(videoId);\n if (unbindVideo) {\n unbindVideo();\n this.videoBindings.delete(videoId);\n }\n const tracks = videoEl.srcObject;\n if (tracks) {\n tracks.getTracks().forEach((track) => {\n track.stop();\n track.enabled = false;\n });\n videoEl.srcObject = null;\n }\n videoEl.remove();\n }\n // Remove audio element\n const audioEl = document.getElementById(audioId);\n if (audioEl) {\n const unbindAudio = this.audioBindings.get(audioId);\n if (unbindAudio) {\n unbindAudio();\n this.audioBindings.delete(audioId);\n }\n const tracks = audioEl.srcObject;\n if (tracks) {\n tracks.getTracks().forEach((track) => {\n track.stop();\n track.enabled = false;\n });\n audioEl.srcObject = null;\n }\n audioEl.remove();\n }\n }\n };\n this.currentCall.on('participantJoined', this.participantJoinedListener);\n this.currentCall.on('participantLeft', this.participantLeftListener);\n // Setup initial participants\n const participants = this.currentCall.state.participants;\n if (this.magicDivId) {\n const magicDiv = document.getElementById(this.magicDivId);\n if (magicDiv) {\n participants.forEach((participant) => {\n if (this.currentCall) {\n this.setupParticipantVideo(this.currentCall, participant, magicDiv);\n this.setupParticipantAudio(this.currentCall, participant, magicDiv);\n }\n });\n }\n }\n }\n setupParticipantVideo(call, participant, container) {\n const id = `video-${participant.sessionId}`;\n if (!document.getElementById(id)) {\n const videoEl = document.createElement('video');\n videoEl.id = id;\n videoEl.style.width = '100%';\n videoEl.style.maxWidth = '300px';\n videoEl.style.aspectRatio = '16/9';\n container.appendChild(videoEl);\n const unbind = call.bindVideoElement(videoEl, participant.sessionId, 'videoTrack');\n if (unbind)\n this.videoBindings.set(id, unbind);\n }\n }\n setupParticipantAudio(call, participant, container) {\n if (participant.isLocalParticipant)\n return;\n const id = `audio-${participant.sessionId}`;\n if (!document.getElementById(id)) {\n const audioEl = document.createElement('audio');\n audioEl.id = id;\n container.appendChild(audioEl);\n const unbind = call.bindAudioElement(audioEl, participant.sessionId);\n if (unbind)\n this.audioBindings.set(id, unbind);\n }\n }\n cleanupCall() {\n var _a;\n // First cleanup the call listeners\n if (this.currentCall) {\n if (this.participantJoinedListener) {\n this.currentCall.off('participantJoined', this.participantJoinedListener);\n this.participantJoinedListener = undefined;\n }\n if (this.participantLeftListener) {\n this.currentCall.off('participantLeft', this.participantLeftListener);\n this.participantLeftListener = undefined;\n }\n (_a = this.callStateSubscription) === null || _a === void 0 ? void 0 : _a.unsubscribe();\n }\n if (this.magicDivId) {\n const magicDiv = document.getElementById(this.magicDivId);\n if (magicDiv) {\n // Remove all video elements\n const videoElements = magicDiv.querySelectorAll('video');\n videoElements.forEach((video) => {\n const id = video.id;\n const unbind = this.videoBindings.get(id);\n if (unbind) {\n unbind();\n this.videoBindings.delete(id);\n }\n // Stop all tracks\n const tracks = video.srcObject;\n if (tracks) {\n tracks.getTracks().forEach((track) => {\n track.stop();\n track.enabled = false;\n });\n video.srcObject = null;\n }\n video.remove();\n });\n // Remove all audio elements\n const audioElements = magicDiv.querySelectorAll('audio');\n audioElements.forEach((audio) => {\n const id = audio.id;\n const unbind = this.audioBindings.get(id);\n if (unbind) {\n unbind();\n this.audioBindings.delete(id);\n }\n // Stop all tracks\n const tracks = audio.srcObject;\n if (tracks) {\n tracks.getTracks().forEach((track) => {\n track.stop();\n track.enabled = false;\n });\n audio.srcObject = null;\n }\n audio.remove();\n });\n // Clear the container\n while (magicDiv.firstChild) {\n magicDiv.removeChild(magicDiv.firstChild);\n }\n }\n }\n // Clear all bindings\n this.videoBindings.clear();\n this.audioBindings.clear();\n // Clear call references\n this.currentCall = undefined;\n this.incomingCall = undefined;\n }\n async login(options) {\n this.client = StreamVideoClient.getOrCreateInstance({\n apiKey: options.apiKey,\n user: { id: options.userId, name: options.name, image: options.imageURL },\n token: options.token,\n });\n this.magicDivId = options.magicDivId;\n this.setupCallRingListener();\n return { success: true };\n }\n async logout() {\n var _a;\n if (!this.client) {\n console.log('No client', this.client);\n throw new Error('Client not initialized');\n }\n // Cleanup subscription\n (_a = this.callStateSubscription) === null || _a === void 0 ? void 0 : _a.unsubscribe();\n this.callStateSubscription = undefined;\n await this.client.disconnectUser();\n this.client = undefined;\n this.currentCall = undefined;\n return { success: true };\n }\n async call(options) {\n if (!this.client) {\n console.log('No client', this.client);\n throw new Error('Client not initialized - Please login first');\n }\n const call = this.client.call(options.type || 'default', crypto.randomUUID());\n const members = [{ user_id: options.userId }];\n if (this.client.streamClient.userID && options.userId !== this.client.streamClient.userID) {\n members.push({ user_id: this.client.streamClient.userID });\n }\n await call.getOrCreate({ data: { members } });\n this.currentCall = call;\n if (options.ring) {\n this.outgoingCall = call.cid;\n await call.ring();\n }\n await call.join();\n return { success: true };\n }\n async endCall() {\n if (!this.currentCall) {\n console.log('No active call', this.currentCall);\n throw new Error('No active call');\n }\n await this.currentCall.leave();\n this.currentCall = undefined;\n this.cleanupCall();\n return { success: true };\n }\n async setMicrophoneEnabled(options) {\n if (!this.currentCall) {\n console.log('No active call', this.currentCall);\n throw new Error('No active call');\n }\n if (options.enabled) {\n await this.currentCall.microphone.enable();\n }\n else {\n await this.currentCall.microphone.disable();\n }\n return { success: true };\n }\n async setCameraEnabled(options) {\n if (!this.currentCall) {\n console.log('No active call', this.currentCall);\n throw new Error('No active call');\n }\n if (options.enabled) {\n await this.currentCall.camera.enable();\n }\n else {\n await this.currentCall.camera.disable();\n }\n return { success: true };\n }\n async acceptCall() {\n if (!this.incomingCall || !this.client) {\n console.log('No incoming call to accept', this.incomingCall, this.client);\n throw new Error('No incoming call to accept');\n }\n console.log('Accepting call', this.incomingCall);\n const call = this.client.call(this.incomingCall.type, this.incomingCall.id);\n this.currentCall = call;\n console.log('Joining call', call);\n await call.accept();\n await call.join();\n console.log('Joined call', call);\n this.notifyListeners('callEvent', { callId: call.id, state: CallingState.JOINED });\n this.setupParticipantListener();\n return { success: true };\n }\n async rejectCall() {\n if (!this.incomingCall || !this.client) {\n console.log('No incoming call to reject', this.incomingCall, this.client);\n throw new Error('No incoming call to reject');\n }\n console.log('Rejecting call', this.incomingCall);\n const call = this.client.call(this.incomingCall.type, this.incomingCall.id);\n console.log('Leaving call', call);\n await call.leave();\n this.incomingCall = undefined;\n console.log('Rejected call', call);\n this.notifyListeners('callEvent', { callId: call.id, state: CallingState.LEFT });\n this.cleanupCall();\n return { success: true };\n }\n}\n//# sourceMappingURL=web.js.map"],"names":["registerPlugin","WebPlugin","CallingState","StreamVideoClient"],"mappings":"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"}
@@ -0,0 +1,147 @@
1
+ import SwiftUI
2
+ import StreamVideo
3
+ import StreamVideoSwiftUI
4
+ import Combine
5
+
6
+ class CallOverlayViewModel: ObservableObject {
7
+ @Published var streamVideo: StreamVideo?
8
+ @Published var call: Call?
9
+ @Published var callState: CallState?
10
+ @Published var viewModel: CallViewModel?
11
+ @Published var participants: [CallParticipant] = []
12
+
13
+ private var participantsSubscription: AnyCancellable?
14
+
15
+ init(streamVideo: StreamVideo?) {
16
+ self.streamVideo = streamVideo
17
+ }
18
+
19
+ @MainActor
20
+ func updateCall(_ call: Call?) {
21
+ self.call = call
22
+ // Clean up previous subscription if any
23
+ participantsSubscription?.cancel()
24
+
25
+ if let call = call {
26
+ participantsSubscription = call.state.$participants.sink { [weak self] participants in
27
+ print("Participants update \(participants.map { $0.name })")
28
+ self?.participants = participants
29
+ }
30
+ self.callState = call.state
31
+ participantsSubscription = call.state.$callSettings.sink { [weak self] callSettings in
32
+ print("Call settings update")
33
+ self?.viewModel = CallViewModel(callSettings: callSettings)
34
+ self?.viewModel?.setActiveCall(call)
35
+ }
36
+ } else {
37
+ // Clear participants when call ends
38
+ self.participants = []
39
+ self.callState = nil
40
+ }
41
+ }
42
+
43
+ @MainActor
44
+ func updateStreamVideo(_ streamVideo: StreamVideo?) {
45
+ self.streamVideo = streamVideo
46
+ if streamVideo == nil {
47
+ self.call = nil
48
+ self.callState = nil
49
+ }
50
+ }
51
+ }
52
+
53
+ class CallOverlayViewFactory: ViewFactory {
54
+ // ... existing ViewFactory methods ...
55
+ func makeVideoParticipantView(
56
+ participant: CallParticipant,
57
+ id: String,
58
+ availableFrame: CGRect,
59
+ contentMode: UIView.ContentMode,
60
+ customData: [String: RawJSON],
61
+ call: Call?
62
+ ) -> some View {
63
+ VideoCallParticipantView(
64
+ viewFactory: self,
65
+ participant: participant,
66
+ id: id,
67
+ availableFrame: availableFrame,
68
+ contentMode: .scaleAspectFit,
69
+ customData: customData,
70
+ call: call
71
+ )
72
+ }
73
+ }
74
+
75
+ struct CallOverlayView: View {
76
+ @ObservedObject var viewModel: CallOverlayViewModel
77
+ @State private var safeAreaInsets: EdgeInsets = .init()
78
+ private let viewFactory: CallOverlayViewFactory
79
+
80
+ init(viewModel: CallOverlayViewModel) {
81
+ self.viewModel = viewModel
82
+ self.viewFactory = CallOverlayViewFactory()
83
+ }
84
+
85
+ var body: some View {
86
+ VStack(spacing: 0) {
87
+ if let viewModelStandard = viewModel.viewModel {
88
+ ZStack {
89
+ CustomCallView(viewFactory: viewFactory, viewModel: viewModelStandard)
90
+ }
91
+ .padding(.top, safeAreaInsets.top)
92
+ .padding(.bottom, safeAreaInsets.bottom)
93
+ } else {
94
+ Color.white
95
+ }
96
+ }
97
+ .edgesIgnoringSafeArea(.all)
98
+ .overlay(
99
+ GeometryReader { geometry in
100
+ Color.clear
101
+ .preference(key: SafeAreaInsetsKey.self, value: geometry.safeAreaInsets)
102
+ }
103
+ )
104
+ .onPreferenceChange(SafeAreaInsetsKey.self) { value in
105
+ safeAreaInsets = value
106
+ }
107
+ .frame(maxWidth: .infinity, maxHeight: .infinity)
108
+ }
109
+
110
+ private func changeTrackVisibility(_ participant: CallParticipant?, isVisible: Bool) {
111
+ print("changeTrackVisibility for \(participant?.userId), visible: \(isVisible)")
112
+ guard let participant = participant,
113
+ let call = viewModel.call else { return }
114
+ Task {
115
+ await call.changeTrackVisibility(for: participant, isVisible: isVisible)
116
+ }
117
+ }
118
+ }
119
+
120
+ extension CallOverlayView {
121
+ static func create(streamVideo: StreamVideo?) -> (UIHostingController<CallOverlayView>, CallOverlayViewModel) {
122
+ let viewModel = CallOverlayViewModel(streamVideo: streamVideo)
123
+ let view = CallOverlayView(viewModel: viewModel)
124
+ let hostingController = UIHostingController(rootView: view)
125
+ hostingController.view.backgroundColor = .clear
126
+
127
+ // Make sure we respect safe areas
128
+ hostingController.view.insetsLayoutMarginsFromSafeArea = true
129
+
130
+ return (hostingController, viewModel)
131
+ }
132
+ }
133
+
134
+ #if DEBUG
135
+ struct CallOverlayView_Previews: PreviewProvider {
136
+ static var previews: some View {
137
+ CallOverlayView(viewModel: CallOverlayViewModel(streamVideo: nil))
138
+ }
139
+ }
140
+ #endif
141
+
142
+ struct SafeAreaInsetsKey: PreferenceKey {
143
+ static var defaultValue: EdgeInsets = .init()
144
+ static func reduce(value: inout EdgeInsets, nextValue: () -> EdgeInsets) {
145
+ value = nextValue()
146
+ }
147
+ }
@@ -0,0 +1,60 @@
1
+ import SwiftUI
2
+ import StreamVideo
3
+ import StreamVideoSwiftUI
4
+
5
+ struct CircledTitleView: View {
6
+
7
+ @Injected(\.colors) var colors
8
+ @Injected(\.fonts) var fonts
9
+
10
+ var title: String
11
+ var size: CGFloat = 172 // .expandedAvatarSize
12
+
13
+ var body: some View {
14
+ ZStack {
15
+ Circle()
16
+ .foregroundColor(colors.tintColor)
17
+ Text(title)
18
+ .foregroundColor(.white)
19
+ .font(fonts.title)
20
+ .minimumScaleFactor(0.4)
21
+ .padding()
22
+ }
23
+ .frame(maxWidth: size, maxHeight: size)
24
+ // .modifier(ShadowModifier())
25
+ }
26
+ }
27
+
28
+ struct CustomCallParticipantImageView<Factory: ViewFactory>: View {
29
+ var viewFactory: Factory
30
+ var id: String
31
+ var name: String
32
+ var imageURL: URL?
33
+ var size: CGFloat = 90
34
+ // var frame: CGSize?
35
+
36
+ @Injected(\.colors) var colors
37
+
38
+ var body: some View {
39
+ StreamLazyImage(imageURL: imageURL) {
40
+ Color(colors.participantBackground)
41
+ }
42
+ .frame(maxWidth: .infinity, maxHeight: .infinity)
43
+ .blur(radius: 8)
44
+ .clipped()
45
+ .overlay(
46
+ viewFactory.makeUserAvatar(
47
+ .init(id: id, name: name, imageURL: imageURL),
48
+ with: .init(size: size) {
49
+ AnyView(
50
+ CircledTitleView(
51
+ title: name.isEmpty ? id : String(name.uppercased().first!),
52
+ size: size
53
+ )
54
+ )
55
+ }
56
+ )
57
+ )
58
+ .clipShape(Rectangle())
59
+ }
60
+ }