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.
- package/CameraMultiCapture.podspec +17 -0
- package/LICENSE +21 -0
- package/Package.swift +28 -0
- package/README.md +551 -0
- package/android/build.gradle +69 -0
- package/android/src/main/AndroidManifest.xml +6 -0
- package/android/src/main/java/dev/hemang/cameramulticapture/CameraConfig.java +45 -0
- package/android/src/main/java/dev/hemang/cameramulticapture/CameraConfigMapper.java +98 -0
- package/android/src/main/java/dev/hemang/cameramulticapture/CameraMultiCapture.java +10 -0
- package/android/src/main/java/dev/hemang/cameramulticapture/CameraMultiCapturePlugin.java +1340 -0
- package/android/src/main/java/dev/hemang/cameramulticapture/ExifWrapper.java +108 -0
- package/android/src/main/java/dev/hemang/cameramulticapture/GenericUploadWorker.java +173 -0
- package/android/src/main/java/dev/hemang/cameramulticapture/ImageUtils.java +215 -0
- package/android/src/main/java/dev/hemang/cameramulticapture/PluginVersion.java +6 -0
- package/android/src/main/java/dev/hemang/cameramulticapture/ThumbnailGenerator.java +48 -0
- package/android/src/main/res/.gitkeep +0 -0
- package/dist/esm/controllers/camera-controller.d.ts +127 -0
- package/dist/esm/controllers/camera-controller.js +388 -0
- package/dist/esm/controllers/camera-controller.js.map +1 -0
- package/dist/esm/controllers/gallery-controller.d.ts +66 -0
- package/dist/esm/controllers/gallery-controller.js +333 -0
- package/dist/esm/controllers/gallery-controller.js.map +1 -0
- package/dist/esm/definitions.d.ts +372 -0
- package/dist/esm/definitions.js +6 -0
- package/dist/esm/definitions.js.map +1 -0
- package/dist/esm/index.d.ts +5 -0
- package/dist/esm/index.js +6 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/overlay-manager.d.ts +124 -0
- package/dist/esm/overlay-manager.js +732 -0
- package/dist/esm/overlay-manager.js.map +1 -0
- package/dist/esm/overlay.d.ts +2 -0
- package/dist/esm/overlay.js +39 -0
- package/dist/esm/overlay.js.map +1 -0
- package/dist/esm/registration.d.ts +5 -0
- package/dist/esm/registration.js +8 -0
- package/dist/esm/registration.js.map +1 -0
- package/dist/esm/types/ui-types.d.ts +78 -0
- package/dist/esm/types/ui-types.js +2 -0
- package/dist/esm/types/ui-types.js.map +1 -0
- package/dist/esm/ui/capture-gesture-handler.d.ts +15 -0
- package/dist/esm/ui/capture-gesture-handler.js +87 -0
- package/dist/esm/ui/capture-gesture-handler.js.map +1 -0
- package/dist/esm/ui/default-styles.d.ts +27 -0
- package/dist/esm/ui/default-styles.js +134 -0
- package/dist/esm/ui/default-styles.js.map +1 -0
- package/dist/esm/ui/image-editor.d.ts +10 -0
- package/dist/esm/ui/image-editor.js +103 -0
- package/dist/esm/ui/image-editor.js.map +1 -0
- package/dist/esm/ui/layout-manager.d.ts +42 -0
- package/dist/esm/ui/layout-manager.js +199 -0
- package/dist/esm/ui/layout-manager.js.map +1 -0
- package/dist/esm/ui/media-viewer.d.ts +2 -0
- package/dist/esm/ui/media-viewer.js +267 -0
- package/dist/esm/ui/media-viewer.js.map +1 -0
- package/dist/esm/ui/pinch-zoom-handler.d.ts +37 -0
- package/dist/esm/ui/pinch-zoom-handler.js +118 -0
- package/dist/esm/ui/pinch-zoom-handler.js.map +1 -0
- package/dist/esm/ui/ui-factory.d.ts +39 -0
- package/dist/esm/ui/ui-factory.js +272 -0
- package/dist/esm/ui/ui-factory.js.map +1 -0
- package/dist/esm/version.d.ts +1 -0
- package/dist/esm/version.js +3 -0
- package/dist/esm/version.js.map +1 -0
- package/dist/esm/web.d.ts +69 -0
- package/dist/esm/web.js +122 -0
- package/dist/esm/web.js.map +1 -0
- package/dist/plugin.cjs.js +6274 -0
- package/dist/plugin.cjs.js.map +1 -0
- package/dist/plugin.js +6276 -0
- package/dist/plugin.js.map +1 -0
- package/ios/Sources/CameraMultiCapturePlugin/CameraMultiCapture.swift +8 -0
- package/ios/Sources/CameraMultiCapturePlugin/CameraMultiCapturePlugin.swift +1551 -0
- package/ios/Sources/CameraMultiCapturePlugin/PluginVersion.swift +2 -0
- package/ios/Tests/CameraMultiCapturePluginTests/CameraMultiCapturePluginTests.swift +15 -0
- 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"]}
|