capacitor-camera-multicapture 0.12.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 (76) hide show
  1. package/CameraMultiCapture.podspec +17 -0
  2. package/LICENSE +21 -0
  3. package/Package.swift +28 -0
  4. package/README.md +551 -0
  5. package/android/build.gradle +69 -0
  6. package/android/src/main/AndroidManifest.xml +6 -0
  7. package/android/src/main/java/dev/hemang/cameramulticapture/CameraConfig.java +45 -0
  8. package/android/src/main/java/dev/hemang/cameramulticapture/CameraConfigMapper.java +98 -0
  9. package/android/src/main/java/dev/hemang/cameramulticapture/CameraMultiCapture.java +10 -0
  10. package/android/src/main/java/dev/hemang/cameramulticapture/CameraMultiCapturePlugin.java +1340 -0
  11. package/android/src/main/java/dev/hemang/cameramulticapture/ExifWrapper.java +108 -0
  12. package/android/src/main/java/dev/hemang/cameramulticapture/GenericUploadWorker.java +173 -0
  13. package/android/src/main/java/dev/hemang/cameramulticapture/ImageUtils.java +215 -0
  14. package/android/src/main/java/dev/hemang/cameramulticapture/PluginVersion.java +6 -0
  15. package/android/src/main/java/dev/hemang/cameramulticapture/ThumbnailGenerator.java +48 -0
  16. package/android/src/main/res/.gitkeep +0 -0
  17. package/dist/esm/controllers/camera-controller.d.ts +127 -0
  18. package/dist/esm/controllers/camera-controller.js +388 -0
  19. package/dist/esm/controllers/camera-controller.js.map +1 -0
  20. package/dist/esm/controllers/gallery-controller.d.ts +66 -0
  21. package/dist/esm/controllers/gallery-controller.js +333 -0
  22. package/dist/esm/controllers/gallery-controller.js.map +1 -0
  23. package/dist/esm/definitions.d.ts +372 -0
  24. package/dist/esm/definitions.js +6 -0
  25. package/dist/esm/definitions.js.map +1 -0
  26. package/dist/esm/index.d.ts +5 -0
  27. package/dist/esm/index.js +6 -0
  28. package/dist/esm/index.js.map +1 -0
  29. package/dist/esm/overlay-manager.d.ts +124 -0
  30. package/dist/esm/overlay-manager.js +732 -0
  31. package/dist/esm/overlay-manager.js.map +1 -0
  32. package/dist/esm/overlay.d.ts +2 -0
  33. package/dist/esm/overlay.js +39 -0
  34. package/dist/esm/overlay.js.map +1 -0
  35. package/dist/esm/registration.d.ts +5 -0
  36. package/dist/esm/registration.js +8 -0
  37. package/dist/esm/registration.js.map +1 -0
  38. package/dist/esm/types/ui-types.d.ts +78 -0
  39. package/dist/esm/types/ui-types.js +2 -0
  40. package/dist/esm/types/ui-types.js.map +1 -0
  41. package/dist/esm/ui/capture-gesture-handler.d.ts +15 -0
  42. package/dist/esm/ui/capture-gesture-handler.js +87 -0
  43. package/dist/esm/ui/capture-gesture-handler.js.map +1 -0
  44. package/dist/esm/ui/default-styles.d.ts +27 -0
  45. package/dist/esm/ui/default-styles.js +134 -0
  46. package/dist/esm/ui/default-styles.js.map +1 -0
  47. package/dist/esm/ui/image-editor.d.ts +10 -0
  48. package/dist/esm/ui/image-editor.js +103 -0
  49. package/dist/esm/ui/image-editor.js.map +1 -0
  50. package/dist/esm/ui/layout-manager.d.ts +42 -0
  51. package/dist/esm/ui/layout-manager.js +199 -0
  52. package/dist/esm/ui/layout-manager.js.map +1 -0
  53. package/dist/esm/ui/media-viewer.d.ts +2 -0
  54. package/dist/esm/ui/media-viewer.js +267 -0
  55. package/dist/esm/ui/media-viewer.js.map +1 -0
  56. package/dist/esm/ui/pinch-zoom-handler.d.ts +37 -0
  57. package/dist/esm/ui/pinch-zoom-handler.js +118 -0
  58. package/dist/esm/ui/pinch-zoom-handler.js.map +1 -0
  59. package/dist/esm/ui/ui-factory.d.ts +39 -0
  60. package/dist/esm/ui/ui-factory.js +272 -0
  61. package/dist/esm/ui/ui-factory.js.map +1 -0
  62. package/dist/esm/version.d.ts +1 -0
  63. package/dist/esm/version.js +3 -0
  64. package/dist/esm/version.js.map +1 -0
  65. package/dist/esm/web.d.ts +69 -0
  66. package/dist/esm/web.js +122 -0
  67. package/dist/esm/web.js.map +1 -0
  68. package/dist/plugin.cjs.js +6274 -0
  69. package/dist/plugin.cjs.js.map +1 -0
  70. package/dist/plugin.js +6276 -0
  71. package/dist/plugin.js.map +1 -0
  72. package/ios/Sources/CameraMultiCapturePlugin/CameraMultiCapture.swift +8 -0
  73. package/ios/Sources/CameraMultiCapturePlugin/CameraMultiCapturePlugin.swift +1551 -0
  74. package/ios/Sources/CameraMultiCapturePlugin/PluginVersion.swift +2 -0
  75. package/ios/Tests/CameraMultiCapturePluginTests/CameraMultiCapturePluginTests.swift +15 -0
  76. package/package.json +93 -0
@@ -0,0 +1,333 @@
1
+ /**
2
+ * Controller for gallery operations and captured images
3
+ */
4
+ import { Capacitor } from '@capacitor/core';
5
+ import { Filesystem, Directory } from '@capacitor/filesystem';
6
+ import { createThumbnailContainer } from '../ui/ui-factory';
7
+ import { openImagePreview, openVideoPreview } from '../ui/media-viewer';
8
+ /**
9
+ * Manages gallery operations and captured images
10
+ */
11
+ export class GalleryController {
12
+ constructor(galleryElement, thumbnailStyle = { width: '80px' }, onImageRemoved, onPhotoAdded, onPhotoUpdated, onPhotoRemoved, onVideoAdded, onVideoRemoved, onMediaCountChanged, enableEditing, markerJsLicenseKey) {
13
+ this.images = [];
14
+ this.videos = [];
15
+ this.captureOrder = [];
16
+ this.galleryElement = galleryElement;
17
+ this.thumbnailStyle = thumbnailStyle;
18
+ this.onImageRemoved = onImageRemoved || (() => { });
19
+ this.onPhotoAdded = onPhotoAdded;
20
+ this.onPhotoUpdated = onPhotoUpdated;
21
+ this.onPhotoRemoved = onPhotoRemoved;
22
+ this.onVideoAdded = onVideoAdded;
23
+ this.onVideoRemoved = onVideoRemoved;
24
+ this.onMediaCountChanged = onMediaCountChanged;
25
+ this.enableEditing = enableEditing !== null && enableEditing !== void 0 ? enableEditing : false;
26
+ this.markerJsLicenseKey = markerJsLicenseKey;
27
+ }
28
+ notifyMediaCountChanged() {
29
+ var _a;
30
+ (_a = this.onMediaCountChanged) === null || _a === void 0 ? void 0 : _a.call(this, this.images.length + this.videos.length);
31
+ }
32
+ /**
33
+ * Adds a new image to the gallery
34
+ */
35
+ addImage(imageData) {
36
+ console.log('Adding image to gallery:', imageData);
37
+ const id = `img_${Date.now()}_${this.images.length}`;
38
+ const newImage = { id, data: imageData };
39
+ this.images.push(newImage);
40
+ this.captureOrder.push({ type: 'image', item: newImage });
41
+ this.renderGallery();
42
+ this.scrollToLatest();
43
+ this.notifyMediaCountChanged();
44
+ // Trigger photoAdded callback with detailed logging
45
+ const eventData = {
46
+ imageId: id,
47
+ image: imageData,
48
+ totalCount: this.images.length
49
+ };
50
+ console.log('[CameraMultiCapture] Photo added to gallery:', {
51
+ imageId: id,
52
+ totalCount: this.images.length,
53
+ imageUri: imageData.uri,
54
+ timestamp: new Date().toISOString()
55
+ });
56
+ if (this.onPhotoAdded) {
57
+ try {
58
+ this.onPhotoAdded(eventData);
59
+ console.log('[CameraMultiCapture] photoAdded callback executed successfully');
60
+ }
61
+ catch (error) {
62
+ console.error('[CameraMultiCapture] Failed to execute photoAdded callback:', error);
63
+ }
64
+ }
65
+ else {
66
+ console.log('[CameraMultiCapture] No photoAdded callback registered');
67
+ }
68
+ }
69
+ /**
70
+ * Removes an image from the gallery
71
+ */
72
+ removeImage(imageId) {
73
+ const imageToRemove = this.images.find(img => img.id === imageId);
74
+ this.images = this.images.filter(img => img.id !== imageId);
75
+ this.captureOrder = this.captureOrder.filter(entry => !(entry.type === 'image' && entry.item.id === imageId));
76
+ this.renderGallery();
77
+ this.onImageRemoved(this.images);
78
+ this.notifyMediaCountChanged();
79
+ // Trigger photoRemoved callback with detailed logging
80
+ const eventData = {
81
+ imageId,
82
+ totalCount: this.images.length
83
+ };
84
+ console.log('[CameraMultiCapture] Photo removed from gallery:', {
85
+ removedImageId: imageId,
86
+ remainingCount: this.images.length,
87
+ removedImageUri: (imageToRemove === null || imageToRemove === void 0 ? void 0 : imageToRemove.data.uri) || 'unknown',
88
+ timestamp: new Date().toISOString()
89
+ });
90
+ if (this.onPhotoRemoved) {
91
+ try {
92
+ this.onPhotoRemoved(eventData);
93
+ console.log('[CameraMultiCapture] photoRemoved callback executed successfully');
94
+ }
95
+ catch (error) {
96
+ console.error('[CameraMultiCapture] Failed to execute photoRemoved callback:', error);
97
+ }
98
+ }
99
+ else {
100
+ console.log('[CameraMultiCapture] No photoRemoved callback registered');
101
+ }
102
+ }
103
+ /**
104
+ * Adds a new video to the gallery
105
+ */
106
+ addVideo(videoData) {
107
+ const id = `vid_${Date.now()}_${this.videos.length}`;
108
+ const newVideo = { id, data: videoData };
109
+ this.videos.push(newVideo);
110
+ this.captureOrder.push({ type: 'video', item: newVideo });
111
+ this.renderGallery();
112
+ this.scrollToLatest();
113
+ this.notifyMediaCountChanged();
114
+ // Trigger videoAdded callback
115
+ const eventData = {
116
+ videoId: id,
117
+ video: videoData,
118
+ totalCount: this.videos.length
119
+ };
120
+ console.log('[CameraMultiCapture] Video added to gallery:', {
121
+ videoId: id,
122
+ totalCount: this.videos.length,
123
+ videoUri: videoData.uri,
124
+ timestamp: new Date().toISOString()
125
+ });
126
+ if (this.onVideoAdded) {
127
+ try {
128
+ this.onVideoAdded(eventData);
129
+ console.log('[CameraMultiCapture] videoAdded callback executed successfully');
130
+ }
131
+ catch (error) {
132
+ console.error('[CameraMultiCapture] Failed to execute videoAdded callback:', error);
133
+ }
134
+ }
135
+ else {
136
+ console.log('[CameraMultiCapture] No videoAdded callback registered');
137
+ }
138
+ }
139
+ /**
140
+ * Removes a video from the gallery
141
+ */
142
+ removeVideo(videoId) {
143
+ const videoToRemove = this.videos.find(vid => vid.id === videoId);
144
+ this.videos = this.videos.filter(vid => vid.id !== videoId);
145
+ this.captureOrder = this.captureOrder.filter(entry => !(entry.type === 'video' && entry.item.id === videoId));
146
+ this.renderGallery();
147
+ this.notifyMediaCountChanged();
148
+ // Trigger videoRemoved callback
149
+ const eventData = {
150
+ videoId,
151
+ totalCount: this.videos.length
152
+ };
153
+ console.log('[CameraMultiCapture] Video removed from gallery:', {
154
+ removedVideoId: videoId,
155
+ remainingCount: this.videos.length,
156
+ removedVideoUri: (videoToRemove === null || videoToRemove === void 0 ? void 0 : videoToRemove.data.uri) || 'unknown',
157
+ timestamp: new Date().toISOString()
158
+ });
159
+ if (this.onVideoRemoved) {
160
+ try {
161
+ this.onVideoRemoved(eventData);
162
+ console.log('[CameraMultiCapture] videoRemoved callback executed successfully');
163
+ }
164
+ catch (error) {
165
+ console.error('[CameraMultiCapture] Failed to execute videoRemoved callback:', error);
166
+ }
167
+ }
168
+ else {
169
+ console.log('[CameraMultiCapture] No videoRemoved callback registered');
170
+ }
171
+ }
172
+ /**
173
+ * Clears all images from the gallery
174
+ */
175
+ clearGallery() {
176
+ // Store items to remove before clearing
177
+ const imagesToRemove = [...this.images];
178
+ const videosToRemove = [...this.videos];
179
+ this.images = [];
180
+ this.videos = [];
181
+ this.captureOrder = [];
182
+ this.renderGallery();
183
+ this.onImageRemoved(this.images);
184
+ this.notifyMediaCountChanged();
185
+ console.log(`[CameraMultiCapture] Clearing gallery - triggering ${imagesToRemove.length} photoRemoved callbacks`);
186
+ // Trigger photoRemoved callbacks for each cleared image
187
+ if (this.onPhotoRemoved) {
188
+ imagesToRemove.forEach((image, index) => {
189
+ const eventData = {
190
+ imageId: image.id,
191
+ totalCount: 0 // All images are being cleared
192
+ };
193
+ console.log(`[CameraMultiCapture] Triggering photoRemoved callback ${index + 1}/${imagesToRemove.length}:`, {
194
+ removedImageId: image.id,
195
+ imageUri: image.data.uri,
196
+ timestamp: new Date().toISOString()
197
+ });
198
+ try {
199
+ this.onPhotoRemoved(eventData);
200
+ console.log(`[CameraMultiCapture] photoRemoved callback ${index + 1} executed successfully`);
201
+ }
202
+ catch (error) {
203
+ console.error(`[CameraMultiCapture] Failed to execute photoRemoved callback ${index + 1}:`, error);
204
+ }
205
+ });
206
+ }
207
+ else {
208
+ console.log('[CameraMultiCapture] No photoRemoved callback registered for gallery clear');
209
+ }
210
+ // Trigger videoRemoved callbacks for each cleared video
211
+ if (this.onVideoRemoved) {
212
+ videosToRemove.forEach((video, index) => {
213
+ const eventData = {
214
+ videoId: video.id,
215
+ totalCount: 0 // All videos are being cleared
216
+ };
217
+ console.log(`[CameraMultiCapture] Triggering videoRemoved callback ${index + 1}/${videosToRemove.length}:`, {
218
+ removedVideoId: video.id,
219
+ videoUri: video.data.uri,
220
+ timestamp: new Date().toISOString()
221
+ });
222
+ try {
223
+ this.onVideoRemoved(eventData);
224
+ console.log(`[CameraMultiCapture] videoRemoved callback ${index + 1} executed successfully`);
225
+ }
226
+ catch (error) {
227
+ console.error(`[CameraMultiCapture] Failed to execute videoRemoved callback ${index + 1}:`, error);
228
+ }
229
+ });
230
+ }
231
+ else {
232
+ console.log('[CameraMultiCapture] No videoRemoved callback registered for gallery clear');
233
+ }
234
+ }
235
+ /**
236
+ * Gets all captured images
237
+ */
238
+ getImages() {
239
+ return this.images;
240
+ }
241
+ /**
242
+ * Gets all captured videos
243
+ */
244
+ getVideos() {
245
+ return this.videos;
246
+ }
247
+ /**
248
+ * Replaces an existing image's data (e.g. after annotation) and re-renders.
249
+ */
250
+ updateImage(imageId, newData) {
251
+ const target = this.images.find(img => img.id === imageId);
252
+ if (!target)
253
+ return;
254
+ target.data = newData;
255
+ const entry = this.captureOrder.find(e => e.type === 'image' && e.item.id === imageId);
256
+ if (entry && entry.type === 'image') {
257
+ entry.item.data = newData;
258
+ }
259
+ this.renderGallery();
260
+ }
261
+ /**
262
+ * Opens marker.js editor on the given image and replaces it on save.
263
+ */
264
+ async handleEditImage(image) {
265
+ var _a, _b;
266
+ const { openImageEditor, isEditorActive } = await import('../ui/image-editor');
267
+ if (isEditorActive())
268
+ return;
269
+ const src = image.data.webPath || image.data.uri;
270
+ try {
271
+ const result = await openImageEditor(src, image.data.editorState, this.markerJsLicenseKey);
272
+ if (!result)
273
+ return;
274
+ // Write annotated image to disk so uri is a native file path
275
+ const fileName = `annotated_${Date.now()}.jpg`;
276
+ const base64Data = result.dataUrl.split(',')[1];
277
+ const savedFile = await Filesystem.writeFile({
278
+ path: fileName,
279
+ data: base64Data,
280
+ directory: Directory.Cache,
281
+ });
282
+ const fileUri = savedFile.uri;
283
+ const webPath = Capacitor.convertFileSrc(fileUri);
284
+ const updatedData = Object.assign(Object.assign({}, image.data), { sourceUri: (_a = image.data.sourceUri) !== null && _a !== void 0 ? _a : image.data.uri, uri: fileUri, webPath, thumbnail: result.dataUrl, editorState: result.state });
285
+ this.updateImage(image.id, updatedData);
286
+ (_b = this.onPhotoUpdated) === null || _b === void 0 ? void 0 : _b.call(this, {
287
+ imageId: image.id,
288
+ image: updatedData,
289
+ totalCount: this.images.length,
290
+ });
291
+ }
292
+ catch (err) {
293
+ console.error('[CameraMultiCapture] Image editor error:', err);
294
+ }
295
+ }
296
+ /**
297
+ * Renders the gallery in chronological capture order
298
+ */
299
+ renderGallery() {
300
+ this.galleryElement.innerHTML = '';
301
+ this.captureOrder.forEach(entry => {
302
+ if (entry.type === 'image') {
303
+ const image = entry.item;
304
+ const src = image.data.webPath || image.data.uri;
305
+ const thumbnailContainer = createThumbnailContainer(image.data.thumbnail, this.thumbnailStyle, () => this.removeImage(image.id), {
306
+ onTap: () => openImagePreview(src, image.data.thumbnail, this.enableEditing ? () => this.handleEditImage(image) : undefined),
307
+ });
308
+ this.galleryElement.appendChild(thumbnailContainer);
309
+ }
310
+ else {
311
+ const video = entry.item;
312
+ const src = video.data.webPath || video.data.uri;
313
+ const thumbnailContainer = createThumbnailContainer(video.data.thumbnail, this.thumbnailStyle, () => this.removeVideo(video.id), {
314
+ isVideo: true,
315
+ duration: video.data.duration,
316
+ onTap: () => openVideoPreview(src, video.data.thumbnail),
317
+ });
318
+ this.galleryElement.appendChild(thumbnailContainer);
319
+ }
320
+ });
321
+ }
322
+ scrollToLatest() {
323
+ if (this.captureOrder.length === 0)
324
+ return;
325
+ requestAnimationFrame(() => {
326
+ this.galleryElement.scrollTo({
327
+ left: this.galleryElement.scrollWidth,
328
+ behavior: 'smooth'
329
+ });
330
+ });
331
+ }
332
+ }
333
+ //# sourceMappingURL=gallery-controller.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gallery-controller.js","sourceRoot":"","sources":["../../../src/controllers/gallery-controller.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Controller for gallery operations and captured images\n */\nimport { Capacitor } from '@capacitor/core';\nimport { Filesystem, Directory } from '@capacitor/filesystem';\nimport type { CameraImageData, CameraVideoData, CapturedImage, CapturedVideo, PhotoAddedEvent, PhotoUpdatedEvent, PhotoRemovedEvent, VideoAddedEvent, VideoRemovedEvent } from '../definitions';\nimport { createThumbnailContainer } from '../ui/ui-factory';\nimport { openImagePreview, openVideoPreview } from '../ui/media-viewer';\n\ntype CaptureEntry =\n | { type: 'image'; item: CapturedImage }\n | { type: 'video'; item: CapturedVideo };\n\n/**\n * Manages gallery operations and captured images\n */\nexport class GalleryController {\n private galleryElement: HTMLElement;\n private images: CapturedImage[] = [];\n private videos: CapturedVideo[] = [];\n private captureOrder: CaptureEntry[] = [];\n private thumbnailStyle: { width?: string; height?: string };\n private onImageRemoved: (images: CapturedImage[]) => void;\n private onPhotoAdded?: (event: PhotoAddedEvent) => void;\n private onPhotoUpdated?: (event: PhotoUpdatedEvent) => void;\n private onPhotoRemoved?: (event: PhotoRemovedEvent) => void;\n private onVideoAdded?: (event: VideoAddedEvent) => void;\n private onVideoRemoved?: (event: VideoRemovedEvent) => void;\n private onMediaCountChanged?: (totalCount: number) => void;\n private enableEditing: boolean;\n private markerJsLicenseKey?: string;\n\n constructor(\n galleryElement: HTMLElement,\n thumbnailStyle: { width?: string; height?: string } = { width: '80px' },\n onImageRemoved?: (images: CapturedImage[]) => void,\n onPhotoAdded?: (event: PhotoAddedEvent) => void,\n onPhotoUpdated?: (event: PhotoUpdatedEvent) => void,\n onPhotoRemoved?: (event: PhotoRemovedEvent) => void,\n onVideoAdded?: (event: VideoAddedEvent) => void,\n onVideoRemoved?: (event: VideoRemovedEvent) => void,\n onMediaCountChanged?: (totalCount: number) => void,\n enableEditing?: boolean,\n markerJsLicenseKey?: string,\n ) {\n this.galleryElement = galleryElement;\n this.thumbnailStyle = thumbnailStyle;\n this.onImageRemoved = onImageRemoved || (() => { });\n this.onPhotoAdded = onPhotoAdded;\n this.onPhotoUpdated = onPhotoUpdated;\n this.onPhotoRemoved = onPhotoRemoved;\n this.onVideoAdded = onVideoAdded;\n this.onVideoRemoved = onVideoRemoved;\n this.onMediaCountChanged = onMediaCountChanged;\n this.enableEditing = enableEditing ?? false;\n this.markerJsLicenseKey = markerJsLicenseKey;\n }\n\n private notifyMediaCountChanged(): void {\n this.onMediaCountChanged?.(this.images.length + this.videos.length);\n }\n\n /**\n * Adds a new image to the gallery\n */\n addImage(imageData: CameraImageData): void {\n console.log('Adding image to gallery:', imageData);\n const id = `img_${Date.now()}_${this.images.length}`;\n const newImage: CapturedImage = { id, data: imageData };\n\n this.images.push(newImage);\n this.captureOrder.push({ type: 'image', item: newImage });\n this.renderGallery();\n this.scrollToLatest();\n this.notifyMediaCountChanged();\n\n // Trigger photoAdded callback with detailed logging\n const eventData: PhotoAddedEvent = {\n imageId: id,\n image: imageData,\n totalCount: this.images.length\n };\n \n console.log('[CameraMultiCapture] Photo added to gallery:', {\n imageId: id,\n totalCount: this.images.length,\n imageUri: imageData.uri,\n timestamp: new Date().toISOString()\n });\n \n if (this.onPhotoAdded) {\n try {\n this.onPhotoAdded(eventData);\n console.log('[CameraMultiCapture] photoAdded callback executed successfully');\n } catch (error) {\n console.error('[CameraMultiCapture] Failed to execute photoAdded callback:', error);\n }\n } else {\n console.log('[CameraMultiCapture] No photoAdded callback registered');\n }\n }\n\n /**\n * Removes an image from the gallery\n */\n removeImage(imageId: string): void {\n const imageToRemove = this.images.find(img => img.id === imageId);\n this.images = this.images.filter(img => img.id !== imageId);\n this.captureOrder = this.captureOrder.filter(\n entry => !(entry.type === 'image' && entry.item.id === imageId)\n );\n this.renderGallery();\n this.onImageRemoved(this.images);\n this.notifyMediaCountChanged();\n\n // Trigger photoRemoved callback with detailed logging\n const eventData: PhotoRemovedEvent = {\n imageId,\n totalCount: this.images.length\n };\n \n console.log('[CameraMultiCapture] Photo removed from gallery:', {\n removedImageId: imageId,\n remainingCount: this.images.length,\n removedImageUri: imageToRemove?.data.uri || 'unknown',\n timestamp: new Date().toISOString()\n });\n \n if (this.onPhotoRemoved) {\n try {\n this.onPhotoRemoved(eventData);\n console.log('[CameraMultiCapture] photoRemoved callback executed successfully');\n } catch (error) {\n console.error('[CameraMultiCapture] Failed to execute photoRemoved callback:', error);\n }\n } else {\n console.log('[CameraMultiCapture] No photoRemoved callback registered');\n }\n }\n\n /**\n * Adds a new video to the gallery\n */\n addVideo(videoData: CameraVideoData): void {\n const id = `vid_${Date.now()}_${this.videos.length}`;\n const newVideo: CapturedVideo = { id, data: videoData };\n\n this.videos.push(newVideo);\n this.captureOrder.push({ type: 'video', item: newVideo });\n this.renderGallery();\n this.scrollToLatest();\n this.notifyMediaCountChanged();\n\n // Trigger videoAdded callback\n const eventData: VideoAddedEvent = {\n videoId: id,\n video: videoData,\n totalCount: this.videos.length\n };\n\n console.log('[CameraMultiCapture] Video added to gallery:', {\n videoId: id,\n totalCount: this.videos.length,\n videoUri: videoData.uri,\n timestamp: new Date().toISOString()\n });\n\n if (this.onVideoAdded) {\n try {\n this.onVideoAdded(eventData);\n console.log('[CameraMultiCapture] videoAdded callback executed successfully');\n } catch (error) {\n console.error('[CameraMultiCapture] Failed to execute videoAdded callback:', error);\n }\n } else {\n console.log('[CameraMultiCapture] No videoAdded callback registered');\n }\n }\n\n /**\n * Removes a video from the gallery\n */\n removeVideo(videoId: string): void {\n const videoToRemove = this.videos.find(vid => vid.id === videoId);\n this.videos = this.videos.filter(vid => vid.id !== videoId);\n this.captureOrder = this.captureOrder.filter(\n entry => !(entry.type === 'video' && entry.item.id === videoId)\n );\n this.renderGallery();\n this.notifyMediaCountChanged();\n\n // Trigger videoRemoved callback\n const eventData: VideoRemovedEvent = {\n videoId,\n totalCount: this.videos.length\n };\n\n console.log('[CameraMultiCapture] Video removed from gallery:', {\n removedVideoId: videoId,\n remainingCount: this.videos.length,\n removedVideoUri: videoToRemove?.data.uri || 'unknown',\n timestamp: new Date().toISOString()\n });\n\n if (this.onVideoRemoved) {\n try {\n this.onVideoRemoved(eventData);\n console.log('[CameraMultiCapture] videoRemoved callback executed successfully');\n } catch (error) {\n console.error('[CameraMultiCapture] Failed to execute videoRemoved callback:', error);\n }\n } else {\n console.log('[CameraMultiCapture] No videoRemoved callback registered');\n }\n }\n\n /**\n * Clears all images from the gallery\n */\n clearGallery(): void {\n // Store items to remove before clearing\n const imagesToRemove = [...this.images];\n const videosToRemove = [...this.videos];\n this.images = [];\n this.videos = [];\n this.captureOrder = [];\n this.renderGallery();\n this.onImageRemoved(this.images);\n this.notifyMediaCountChanged();\n\n console.log(`[CameraMultiCapture] Clearing gallery - triggering ${imagesToRemove.length} photoRemoved callbacks`);\n\n // Trigger photoRemoved callbacks for each cleared image\n if (this.onPhotoRemoved) {\n imagesToRemove.forEach((image, index) => {\n const eventData: PhotoRemovedEvent = {\n imageId: image.id,\n totalCount: 0 // All images are being cleared\n };\n \n console.log(`[CameraMultiCapture] Triggering photoRemoved callback ${index + 1}/${imagesToRemove.length}:`, {\n removedImageId: image.id,\n imageUri: image.data.uri,\n timestamp: new Date().toISOString()\n });\n \n try {\n this.onPhotoRemoved!(eventData);\n console.log(`[CameraMultiCapture] photoRemoved callback ${index + 1} executed successfully`);\n } catch (error) {\n console.error(`[CameraMultiCapture] Failed to execute photoRemoved callback ${index + 1}:`, error);\n }\n });\n } else {\n console.log('[CameraMultiCapture] No photoRemoved callback registered for gallery clear');\n }\n\n // Trigger videoRemoved callbacks for each cleared video\n if (this.onVideoRemoved) {\n videosToRemove.forEach((video, index) => {\n const eventData: VideoRemovedEvent = {\n videoId: video.id,\n totalCount: 0 // All videos are being cleared\n };\n\n console.log(`[CameraMultiCapture] Triggering videoRemoved callback ${index + 1}/${videosToRemove.length}:`, {\n removedVideoId: video.id,\n videoUri: video.data.uri,\n timestamp: new Date().toISOString()\n });\n\n try {\n this.onVideoRemoved!(eventData);\n console.log(`[CameraMultiCapture] videoRemoved callback ${index + 1} executed successfully`);\n } catch (error) {\n console.error(`[CameraMultiCapture] Failed to execute videoRemoved callback ${index + 1}:`, error);\n }\n });\n } else {\n console.log('[CameraMultiCapture] No videoRemoved callback registered for gallery clear');\n }\n }\n\n /**\n * Gets all captured images\n */\n getImages(): CapturedImage[] {\n return this.images;\n }\n\n /**\n * Gets all captured videos\n */\n getVideos(): CapturedVideo[] {\n return this.videos;\n }\n\n /**\n * Replaces an existing image's data (e.g. after annotation) and re-renders.\n */\n updateImage(imageId: string, newData: CameraImageData): void {\n const target = this.images.find(img => img.id === imageId);\n if (!target) return;\n target.data = newData;\n\n const entry = this.captureOrder.find(\n e => e.type === 'image' && e.item.id === imageId\n );\n if (entry && entry.type === 'image') {\n entry.item.data = newData;\n }\n\n this.renderGallery();\n }\n\n /**\n * Opens marker.js editor on the given image and replaces it on save.\n */\n private async handleEditImage(image: CapturedImage): Promise<void> {\n const { openImageEditor, isEditorActive } = await import('../ui/image-editor');\n if (isEditorActive()) return;\n\n const src = image.data.webPath || image.data.uri;\n\n try {\n const result = await openImageEditor(src, image.data.editorState, this.markerJsLicenseKey);\n if (!result) return;\n\n // Write annotated image to disk so uri is a native file path\n const fileName = `annotated_${Date.now()}.jpg`;\n const base64Data = result.dataUrl.split(',')[1];\n const savedFile = await Filesystem.writeFile({\n path: fileName,\n data: base64Data,\n directory: Directory.Cache,\n });\n const fileUri = savedFile.uri;\n const webPath = Capacitor.convertFileSrc(fileUri);\n\n const updatedData: CameraImageData = {\n ...image.data,\n sourceUri: image.data.sourceUri ?? image.data.uri,\n uri: fileUri,\n webPath,\n thumbnail: result.dataUrl,\n editorState: result.state,\n };\n this.updateImage(image.id, updatedData);\n this.onPhotoUpdated?.({\n imageId: image.id,\n image: updatedData,\n totalCount: this.images.length,\n });\n } catch (err) {\n console.error('[CameraMultiCapture] Image editor error:', err);\n }\n }\n\n /**\n * Renders the gallery in chronological capture order\n */\n private renderGallery(): void {\n this.galleryElement.innerHTML = '';\n\n this.captureOrder.forEach(entry => {\n if (entry.type === 'image') {\n const image = entry.item;\n const src = image.data.webPath || image.data.uri;\n const thumbnailContainer = createThumbnailContainer(\n image.data.thumbnail,\n this.thumbnailStyle,\n () => this.removeImage(image.id),\n {\n onTap: () => openImagePreview(\n src,\n image.data.thumbnail,\n this.enableEditing ? () => this.handleEditImage(image) : undefined,\n ),\n }\n );\n this.galleryElement.appendChild(thumbnailContainer);\n } else {\n const video = entry.item;\n const src = video.data.webPath || video.data.uri;\n const thumbnailContainer = createThumbnailContainer(\n video.data.thumbnail,\n this.thumbnailStyle,\n () => this.removeVideo(video.id),\n {\n isVideo: true,\n duration: video.data.duration,\n onTap: () => openVideoPreview(src, video.data.thumbnail),\n }\n );\n this.galleryElement.appendChild(thumbnailContainer);\n }\n });\n }\n\n private scrollToLatest(): void {\n if (this.captureOrder.length === 0) return;\n\n requestAnimationFrame(() => {\n this.galleryElement.scrollTo({\n left: this.galleryElement.scrollWidth,\n behavior: 'smooth'\n });\n });\n }\n}\n"]}