@yogiswara/honcho-editor-ui 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/editor/HAccordionAspectRatio.d.ts +14 -0
- package/dist/components/editor/HAccordionAspectRatio.js +102 -0
- package/dist/components/editor/HAccordionColor.d.ts +12 -0
- package/dist/components/editor/HAccordionColor.js +234 -0
- package/dist/components/editor/HAccordionColorAdjustment.d.ts +31 -0
- package/dist/components/editor/HAccordionColorAdjustment.js +37 -0
- package/dist/components/editor/HAccordionDetails.d.ts +8 -0
- package/dist/components/editor/HAccordionDetails.js +133 -0
- package/dist/components/editor/HAccordionLight.d.ts +16 -0
- package/dist/components/editor/HAccordionLight.js +342 -0
- package/dist/components/editor/HAccordionPreset.d.ts +23 -0
- package/dist/components/editor/HAccordionPreset.js +59 -0
- package/dist/components/editor/HAlertBox.d.ts +7 -0
- package/dist/components/editor/HAlertBox.js +46 -0
- package/dist/components/editor/HAspectRatioMobile.d.ts +0 -0
- package/dist/components/editor/HAspectRatioMobile.js +1 -0
- package/dist/components/editor/HBulkAccordionColorAdjustment.d.ts +55 -0
- package/dist/components/editor/HBulkAccordionColorAdjustment.js +31 -0
- package/dist/components/editor/HBulkAccordionColorAdjustmentColors.d.ts +20 -0
- package/dist/components/editor/HBulkAccordionColorAdjustmentColors.js +121 -0
- package/dist/components/editor/HBulkAccordionColorAdjustmentDetails.d.ts +12 -0
- package/dist/components/editor/HBulkAccordionColorAdjustmentDetails.js +65 -0
- package/dist/components/editor/HBulkAccordionColorAdjustmentLight.d.ts +28 -0
- package/dist/components/editor/HBulkAccordionColorAdjustmentLight.js +177 -0
- package/dist/components/editor/HBulkColorAdjustmentMobile.d.ts +53 -0
- package/dist/components/editor/HBulkColorAdjustmentMobile.js +16 -0
- package/dist/components/editor/HBulkColorMobile.d.ts +20 -0
- package/dist/components/editor/HBulkColorMobile.js +121 -0
- package/dist/components/editor/HBulkDetailsMobile.d.ts +12 -0
- package/dist/components/editor/HBulkDetailsMobile.js +65 -0
- package/dist/components/editor/HBulkLightMobile.d.ts +28 -0
- package/dist/components/editor/HBulkLightMobile.js +192 -0
- package/dist/components/editor/HBulkPreset.d.ts +24 -0
- package/dist/components/editor/HBulkPreset.js +33 -0
- package/dist/components/editor/HBulkPresetMobile.d.ts +15 -0
- package/dist/components/editor/HBulkPresetMobile.js +26 -0
- package/dist/components/editor/HDialogBox.d.ts +18 -0
- package/dist/components/editor/HDialogBox.js +51 -0
- package/dist/components/editor/HDialogCopy.d.ts +40 -0
- package/dist/components/editor/HDialogCopy.js +80 -0
- package/dist/components/editor/HFooter.d.ts +12 -0
- package/dist/components/editor/HFooter.js +24 -0
- package/dist/components/editor/HHeaderEditor.d.ts +17 -0
- package/dist/components/editor/HHeaderEditor.js +27 -0
- package/dist/components/editor/HImageEditorBulkDekstop.d.ts +15 -0
- package/dist/components/editor/HImageEditorBulkDekstop.js +26 -0
- package/dist/components/editor/HImageEditorBulkMobile.d.ts +72 -0
- package/dist/components/editor/HImageEditorBulkMobile.js +81 -0
- package/dist/components/editor/HImageEditorDekstop.d.ts +15 -0
- package/dist/components/editor/HImageEditorDekstop.js +29 -0
- package/dist/components/editor/HImageEditorMobile.d.ts +47 -0
- package/dist/components/editor/HImageEditorMobile.js +91 -0
- package/dist/components/editor/HImageEditorMobileLayout.d.ts +14 -0
- package/dist/components/editor/HImageEditorMobileLayout.js +57 -0
- package/dist/components/editor/HImageEditorPage.d.ts +1 -0
- package/dist/components/editor/HImageEditorPage.js +187 -0
- package/dist/components/editor/HModalEditorDekstop.d.ts +13 -0
- package/dist/components/editor/HModalEditorDekstop.js +22 -0
- package/dist/components/editor/HModalMobile.d.ts +12 -0
- package/dist/components/editor/HModalMobile.js +7 -0
- package/dist/components/editor/HPresetOptionMenu.d.ts +11 -0
- package/dist/components/editor/HPresetOptionMenu.js +20 -0
- package/dist/components/editor/HSliderColorMobile.d.ts +12 -0
- package/dist/components/editor/HSliderColorMobile.js +222 -0
- package/dist/components/editor/HSliderDetailsMobile.d.ts +8 -0
- package/dist/components/editor/HSliderDetailsMobile.js +130 -0
- package/dist/components/editor/HSliderLightMobile.d.ts +16 -0
- package/dist/components/editor/HSliderLightMobile.js +342 -0
- package/dist/components/editor/HTabAspectRatioMobile.d.ts +0 -0
- package/dist/components/editor/HTabAspectRatioMobile.js +1 -0
- package/dist/components/editor/HTabColorAdjustmentMobile.d.ts +29 -0
- package/dist/components/editor/HTabColorAdjustmentMobile.js +16 -0
- package/dist/components/editor/HTabPresetMobile.d.ts +14 -0
- package/dist/components/editor/HTabPresetMobile.js +10 -0
- package/dist/components/editor/HTextField.d.ts +14 -0
- package/dist/components/editor/HTextField.js +51 -0
- package/dist/components/editor/HWatermarkView.d.ts +6 -0
- package/dist/components/editor/HWatermarkView.js +16 -0
- package/dist/hooks/editor/useHonchoEditor.d.ts +272 -0
- package/dist/hooks/editor/useHonchoEditor.js +1203 -0
- package/dist/index.d.ts +23 -0
- package/dist/index.js +23 -0
- package/dist/lib/editor/honcho-editor.d.ts +324 -0
- package/dist/lib/editor/honcho-editor.js +825 -0
- package/dist/themes/colors.d.ts +12 -0
- package/dist/themes/colors.js +12 -0
- package/dist/themes/honchoTheme.d.ts +25 -0
- package/dist/themes/honchoTheme.js +94 -0
- package/dist/utils/isMobile.d.ts +1 -0
- package/dist/utils/isMobile.js +5 -0
- package/package.json +41 -0
|
@@ -0,0 +1,1203 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { useState, useRef, useCallback, useEffect } from 'react';
|
|
3
|
+
import { HonchoEditor } from '@/lib/editor/honcho-editor';
|
|
4
|
+
const initialAdjustments = {
|
|
5
|
+
tempScore: 0, tintScore: 0, vibranceScore: 0, exposureScore: 0, highlightsScore: 0, shadowsScore: 0,
|
|
6
|
+
whitesScore: 0, blacksScore: 0, saturationScore: 0, contrastScore: 0, clarityScore: 0, sharpnessScore: 0,
|
|
7
|
+
};
|
|
8
|
+
const clamp = (value) => Math.max(-100, Math.min(100, value));
|
|
9
|
+
export function useHonchoEditor(controller) {
|
|
10
|
+
// MARK: - Core Editor State & Refs
|
|
11
|
+
const editorRef = useRef(null);
|
|
12
|
+
const canvasRef = useRef(null);
|
|
13
|
+
const canvasContainerRef = useRef(null);
|
|
14
|
+
const fileInputRef = useRef(null);
|
|
15
|
+
const [editorStatus, setEditorStatus] = useState("Initializing...");
|
|
16
|
+
const [isEditorReady, setIsEditorReady] = useState(false);
|
|
17
|
+
const [isImageLoaded, setIsImageLoaded] = useState(false);
|
|
18
|
+
const [zoomLevel, setZoomLevel] = useState(1);
|
|
19
|
+
// MARK: - Adjustment & History State
|
|
20
|
+
// const [adjustments, setAdjustments] = useState<AdjustmentState>(initialAdjustments);
|
|
21
|
+
const [history, setHistory] = useState([initialAdjustments]);
|
|
22
|
+
const [historyIndex, setHistoryIndex] = useState(0);
|
|
23
|
+
const [isViewingOriginal, setIsViewingOriginal] = useState(false);
|
|
24
|
+
const [copiedAdjustments, setCopiedAdjustments] = useState(null);
|
|
25
|
+
const [copyColorChecks, setCopyColorChecks] = useState({ temperature: true, tint: true, vibrance: true, saturation: true });
|
|
26
|
+
const [copyLightChecks, setCopyLightChecks] = useState({ exposure: true, contrast: true, highlights: true, shadows: true, whites: true, blacks: true });
|
|
27
|
+
const [copyDetailsChecks, setCopyDetailsChecks] = useState({ clarity: true, sharpness: true });
|
|
28
|
+
const [copyDialogExpanded, setCopyDialogExpanded] = useState({ color: true, light: true, details: true });
|
|
29
|
+
const [adjustmentsMap, setAdjustmentsMap] = useState(new Map());
|
|
30
|
+
// Individual Adjustment State
|
|
31
|
+
const [tempScore, setTempScore] = useState(0);
|
|
32
|
+
const [tintScore, setTintScore] = useState(0);
|
|
33
|
+
const [vibranceScore, setVibranceScore] = useState(0);
|
|
34
|
+
const [saturationScore, setSaturationScore] = useState(0);
|
|
35
|
+
const [exposureScore, setExposureScore] = useState(0);
|
|
36
|
+
const [highlightsScore, setHighlightsScore] = useState(0);
|
|
37
|
+
const [shadowsScore, setShadowsScore] = useState(0);
|
|
38
|
+
const [whitesScore, setWhitesScore] = useState(0);
|
|
39
|
+
const [blacksScore, setBlacksScore] = useState(0);
|
|
40
|
+
const [contrastScore, setContrastScore] = useState(0);
|
|
41
|
+
const [clarityScore, setClarityScore] = useState(0);
|
|
42
|
+
const [sharpnessScore, setSharpnessScore] = useState(0);
|
|
43
|
+
// MARK: - UI & App State (Moved from page.tsx)
|
|
44
|
+
// General UI State
|
|
45
|
+
const [isOnline, setIsOnline] = useState(true);
|
|
46
|
+
const [isConnectionSlow, setIsConnectionSlow] = useState(false);
|
|
47
|
+
const [showCopyAlert, setShowCopyAlert] = useState(false);
|
|
48
|
+
const [isCopyDialogOpen, setCopyDialogOpen] = useState(false);
|
|
49
|
+
const [isPublished, setIsPublished] = useState(false);
|
|
50
|
+
const [activePanel, setActivePanel] = useState('colorAdjustment');
|
|
51
|
+
const [activeSubPanel, setActiveSubPanel] = useState('');
|
|
52
|
+
const [headerMenuAnchorEl, setHeaderMenuAnchorEl] = useState(null);
|
|
53
|
+
const [anchorMenuZoom, setAnchorMenuZoom] = useState(null);
|
|
54
|
+
// Panel Expansion State
|
|
55
|
+
const [colorAdjustmentExpandedPanels, setColorAdjustmentExpandedPanels] = useState(['whiteBalance']);
|
|
56
|
+
const [presetExpandedPanels, setPresetExpandedPanels] = useState(['preset']);
|
|
57
|
+
// Watermark State
|
|
58
|
+
const [isCreatingWatermark, setIsCreatingWatermark] = useState(false);
|
|
59
|
+
// Preset State
|
|
60
|
+
const [isPresetModalOpen, setPresetModalOpen] = useState(false);
|
|
61
|
+
const [isPresetModalOpenMobile, setPresetModalOpenMobile] = useState(false);
|
|
62
|
+
const [presets, setPresets] = useState([]);
|
|
63
|
+
const [presetName, setPresetName] = useState("Type Here");
|
|
64
|
+
const [isPresetCreated, setIsPresetCreated] = useState(false);
|
|
65
|
+
const [selectedMobilePreset, setSelectedMobilePreset] = useState('preset1');
|
|
66
|
+
const [selectedDesktopPreset, setSelectedDesktopPreset] = useState('preset1');
|
|
67
|
+
const [selectedBulkPreset, setSelectedBulkPreset] = useState('preset1');
|
|
68
|
+
const [presetMenuAnchorEl, setPresetMenuAnchorEl] = useState(null);
|
|
69
|
+
const [activePresetMenuId, setActivePresetMenuId] = useState(null);
|
|
70
|
+
const [isRenameModalOpen, setRenameModalOpen] = useState(false);
|
|
71
|
+
const [presetToRename, setPresetToRename] = useState(null);
|
|
72
|
+
const [newPresetName, setNewPresetName] = useState("");
|
|
73
|
+
// Aspect Ratio State
|
|
74
|
+
// Note: not used yet
|
|
75
|
+
const [currentAspectRatio, setCurrentAspectRatio] = useState('potrait');
|
|
76
|
+
const [currentSquareRatio, setCurrentSquareRatio] = useState('original');
|
|
77
|
+
const [currentWideRatio, setCurrentWideRatio] = useState('1:1');
|
|
78
|
+
const [angelScore, setAngleScore] = useState(0);
|
|
79
|
+
const [widthSizePX, setWidthSizePX] = useState(0);
|
|
80
|
+
const [heightSizePX, setHeightSizePX] = useState(0);
|
|
81
|
+
// Bulk Editing State
|
|
82
|
+
const [isBulkEditing, setIsBulkEditing] = useState(false);
|
|
83
|
+
const [selectedImages, setSelectedImages] = useState('Select');
|
|
84
|
+
const [imageList, setImageList] = useState([]);
|
|
85
|
+
const [selectedImageIds, setSelectedImageIds] = useState(new Set());
|
|
86
|
+
// MARK: Framse- (Later use)
|
|
87
|
+
const [isFrameApplied, setIsFrameApplied] = useState(false);
|
|
88
|
+
// State for Copying specific adjustments
|
|
89
|
+
const [colorAdjustments, setColorAdjustments] = useState(true);
|
|
90
|
+
const [lightAdjustments, setLightAdjustments] = useState(true);
|
|
91
|
+
const [detailsAdjustments, setDetailsAdjustments] = useState(true);
|
|
92
|
+
// for connection native
|
|
93
|
+
const [displayedToken, setDisplayedToken] = useState(null);
|
|
94
|
+
// MARK: dragable
|
|
95
|
+
const PEEK_HEIGHT = 20;
|
|
96
|
+
const COLLAPSED_HEIGHT = 165;
|
|
97
|
+
const PANEL_CHROME_HEIGHT = 10;
|
|
98
|
+
// Mobile Draggable Panel State
|
|
99
|
+
const [panelHeight, setPanelHeight] = useState(COLLAPSED_HEIGHT);
|
|
100
|
+
const [contentHeight, setContentHeight] = useState(0);
|
|
101
|
+
const [isDragging, setIsDragging] = useState(false);
|
|
102
|
+
const dragStartPos = useRef(0);
|
|
103
|
+
const initialHeight = useRef(0);
|
|
104
|
+
const panelRef = useRef(null);
|
|
105
|
+
const contentRef = useRef(null);
|
|
106
|
+
// Mobile Panel Drag Handlers
|
|
107
|
+
const handleContentHeightChange = useCallback((height) => {
|
|
108
|
+
if (height > 0 && height !== contentHeight)
|
|
109
|
+
setContentHeight(height);
|
|
110
|
+
}, [contentHeight]);
|
|
111
|
+
const handleDragStart = useCallback((e) => {
|
|
112
|
+
setIsDragging(true);
|
|
113
|
+
const startY = 'touches' in e ? e.touches[0].clientY : e.clientY;
|
|
114
|
+
dragStartPos.current = startY;
|
|
115
|
+
initialHeight.current = panelHeight;
|
|
116
|
+
if (panelRef.current)
|
|
117
|
+
panelRef.current.style.transition = 'none';
|
|
118
|
+
}, [panelHeight]);
|
|
119
|
+
const handleDragMove = useCallback((e) => {
|
|
120
|
+
if (!isDragging)
|
|
121
|
+
return;
|
|
122
|
+
const currentY = 'touches' in e ? e.touches[0].clientY : e.clientY;
|
|
123
|
+
const deltaY = dragStartPos.current - currentY;
|
|
124
|
+
const newHeight = initialHeight.current + deltaY;
|
|
125
|
+
const dynamicPanelFullHeight = contentHeight + PANEL_CHROME_HEIGHT;
|
|
126
|
+
const clampedHeight = Math.max(PEEK_HEIGHT, Math.min(newHeight, dynamicPanelFullHeight));
|
|
127
|
+
setPanelHeight(clampedHeight);
|
|
128
|
+
}, [isDragging, contentHeight]);
|
|
129
|
+
const handleDragEnd = useCallback(() => {
|
|
130
|
+
if (!isDragging)
|
|
131
|
+
return;
|
|
132
|
+
setIsDragging(false);
|
|
133
|
+
dragStartPos.current = 0;
|
|
134
|
+
if (panelRef.current)
|
|
135
|
+
panelRef.current.style.transition = 'height 0.3s ease-in-out';
|
|
136
|
+
const dynamicPanelFullHeight = contentHeight + PANEL_CHROME_HEIGHT;
|
|
137
|
+
const snapPointLow = (PEEK_HEIGHT + COLLAPSED_HEIGHT) / 2;
|
|
138
|
+
const snapPointHigh = (COLLAPSED_HEIGHT + dynamicPanelFullHeight) / 2;
|
|
139
|
+
if (panelHeight < snapPointLow) {
|
|
140
|
+
setPanelHeight(PEEK_HEIGHT);
|
|
141
|
+
}
|
|
142
|
+
else if (panelHeight >= snapPointLow && panelHeight < snapPointHigh) {
|
|
143
|
+
setPanelHeight(COLLAPSED_HEIGHT);
|
|
144
|
+
}
|
|
145
|
+
else {
|
|
146
|
+
setPanelHeight(dynamicPanelFullHeight);
|
|
147
|
+
}
|
|
148
|
+
}, [isDragging, panelHeight, contentHeight]);
|
|
149
|
+
// Keyboard Shortcut Handler
|
|
150
|
+
const handleKeyDown = useCallback((event) => {
|
|
151
|
+
const target = event.target;
|
|
152
|
+
if (target.tagName === 'INPUT' || target.tagName === 'TEXTAREA')
|
|
153
|
+
return;
|
|
154
|
+
if ((event.ctrlKey || event.metaKey) && event.key === 'c') {
|
|
155
|
+
event.preventDefault();
|
|
156
|
+
handleOpenCopyDialog(); // Assumes handleOpenCopyDialog is defined in the hook
|
|
157
|
+
}
|
|
158
|
+
}, [ /* handleOpenCopyDialog dependency */]);
|
|
159
|
+
// Effect for measuring mobile panel content
|
|
160
|
+
useEffect(() => {
|
|
161
|
+
const timeoutId = setTimeout(() => {
|
|
162
|
+
if (contentRef.current) {
|
|
163
|
+
const height = contentRef.current.scrollHeight;
|
|
164
|
+
setContentHeight(height);
|
|
165
|
+
}
|
|
166
|
+
}, 50);
|
|
167
|
+
return () => clearTimeout(timeoutId);
|
|
168
|
+
}, [activeSubPanel, isBulkEditing]);
|
|
169
|
+
// Effect for keyboard shortcuts
|
|
170
|
+
useEffect(() => {
|
|
171
|
+
window.addEventListener('keydown', handleKeyDown);
|
|
172
|
+
return () => {
|
|
173
|
+
window.removeEventListener('keydown', handleKeyDown);
|
|
174
|
+
};
|
|
175
|
+
}, [handleKeyDown]);
|
|
176
|
+
// Effect for drag listeners
|
|
177
|
+
useEffect(() => {
|
|
178
|
+
if (isDragging) {
|
|
179
|
+
window.addEventListener('mousemove', handleDragMove);
|
|
180
|
+
window.addEventListener('mouseup', handleDragEnd);
|
|
181
|
+
window.addEventListener('touchmove', handleDragMove);
|
|
182
|
+
window.addEventListener('touchend', handleDragEnd);
|
|
183
|
+
}
|
|
184
|
+
return () => {
|
|
185
|
+
window.removeEventListener('mousemove', handleDragMove);
|
|
186
|
+
window.removeEventListener('mouseup', handleDragEnd);
|
|
187
|
+
window.removeEventListener('touchmove', handleDragMove);
|
|
188
|
+
window.removeEventListener('touchend', handleDragEnd);
|
|
189
|
+
};
|
|
190
|
+
}, [isDragging, handleDragMove, handleDragEnd]);
|
|
191
|
+
useEffect(() => {
|
|
192
|
+
// Cast navigator to our custom type to access the connection property safely
|
|
193
|
+
const navigatorWithConnection = navigator;
|
|
194
|
+
if (!navigatorWithConnection.connection) {
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
const navigatorConnection = navigatorWithConnection.connection;
|
|
198
|
+
const updateConnectionStatus = () => {
|
|
199
|
+
const slowConnectionTypes = ['slow-2g', '2g', '3g'];
|
|
200
|
+
const isSlow = navigatorConnection.saveData ||
|
|
201
|
+
slowConnectionTypes.includes(navigatorConnection.effectiveType);
|
|
202
|
+
setIsConnectionSlow(isSlow);
|
|
203
|
+
};
|
|
204
|
+
// Check status immediately
|
|
205
|
+
updateConnectionStatus();
|
|
206
|
+
// Add event listener for changes
|
|
207
|
+
navigatorConnection.addEventListener('change', updateConnectionStatus);
|
|
208
|
+
// Cleanup on unmount
|
|
209
|
+
return () => {
|
|
210
|
+
navigatorConnection.removeEventListener('change', updateConnectionStatus);
|
|
211
|
+
};
|
|
212
|
+
}, []);
|
|
213
|
+
// MARK: - Core Editor Logic
|
|
214
|
+
const updateCanvas = useCallback(() => {
|
|
215
|
+
if (editorRef.current?.getInitialized() && canvasRef.current) {
|
|
216
|
+
editorRef.current.processImage();
|
|
217
|
+
editorRef.current.renderToCanvas(canvasRef.current);
|
|
218
|
+
}
|
|
219
|
+
}, []);
|
|
220
|
+
const loadImage = useCallback(async (file) => {
|
|
221
|
+
if (!editorRef.current) {
|
|
222
|
+
setEditorStatus("Editor not ready.");
|
|
223
|
+
return;
|
|
224
|
+
}
|
|
225
|
+
setEditorStatus("Loading image...");
|
|
226
|
+
try {
|
|
227
|
+
await editorRef.current.loadImageFromFile(file);
|
|
228
|
+
setIsImageLoaded(true);
|
|
229
|
+
}
|
|
230
|
+
catch (e) {
|
|
231
|
+
console.error("Error loading image:", e);
|
|
232
|
+
setEditorStatus("Error: Could not load the image.");
|
|
233
|
+
setIsImageLoaded(false);
|
|
234
|
+
}
|
|
235
|
+
}, []);
|
|
236
|
+
const applyUiStateToSelectedImages = useCallback((uiState) => {
|
|
237
|
+
setAdjustmentsMap(prevMap => {
|
|
238
|
+
const newMap = new Map(prevMap);
|
|
239
|
+
selectedImageIds.forEach(id => {
|
|
240
|
+
newMap.set(id, uiState);
|
|
241
|
+
});
|
|
242
|
+
return newMap;
|
|
243
|
+
});
|
|
244
|
+
}, [selectedImageIds]);
|
|
245
|
+
const loadImageFromUrl = useCallback(async (url) => {
|
|
246
|
+
try {
|
|
247
|
+
setEditorStatus("Downloading image...");
|
|
248
|
+
const response = await fetch(url);
|
|
249
|
+
if (!response.ok)
|
|
250
|
+
throw new Error(`Failed to fetch image from URL: ${url}`);
|
|
251
|
+
const blob = await response.blob();
|
|
252
|
+
const filename = url.substring(url.lastIndexOf('/') + 1) || 'image.jpg';
|
|
253
|
+
const file = new File([blob], filename, { type: blob.type });
|
|
254
|
+
await loadImage(file); // Pass the final File object to the core loader
|
|
255
|
+
}
|
|
256
|
+
catch (error) {
|
|
257
|
+
console.error(error);
|
|
258
|
+
setEditorStatus("Error: Could not load image from URL.");
|
|
259
|
+
}
|
|
260
|
+
}, [loadImage]);
|
|
261
|
+
const loadImageFromId = useCallback(async (imageId) => {
|
|
262
|
+
if (!controller)
|
|
263
|
+
return;
|
|
264
|
+
setEditorStatus("Fetching image URL...");
|
|
265
|
+
try {
|
|
266
|
+
const imageUrl = await controller.onGetImage(imageId);
|
|
267
|
+
if (imageUrl) {
|
|
268
|
+
await loadImageFromUrl(imageUrl);
|
|
269
|
+
}
|
|
270
|
+
else {
|
|
271
|
+
throw new Error("Controller did not return an image URL.");
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
catch (error) {
|
|
275
|
+
console.error("Failed to fetch or load image via controller:", error);
|
|
276
|
+
setEditorStatus("Error: Could not fetch the image.");
|
|
277
|
+
}
|
|
278
|
+
}, [controller, loadImageFromUrl]);
|
|
279
|
+
useEffect(() => {
|
|
280
|
+
// Define the function that the native app will call to load an image
|
|
281
|
+
const loadInitialImageFromNative = (imageId) => {
|
|
282
|
+
if (typeof imageId === 'string' && imageId) {
|
|
283
|
+
console.log(`[WebView Bridge] Received command to load imageId: ${imageId}`);
|
|
284
|
+
// Use the loadImageFromId function directly from the hook's scope
|
|
285
|
+
loadImageFromId(imageId);
|
|
286
|
+
}
|
|
287
|
+
else {
|
|
288
|
+
console.error(`[WebView Bridge] Invalid imageId received from native:`, imageId);
|
|
289
|
+
}
|
|
290
|
+
};
|
|
291
|
+
// Expose both functions on the window object for native code to access
|
|
292
|
+
window.loadInitialImageFromNative = loadInitialImageFromNative;
|
|
293
|
+
// Cleanup function to remove the global handlers when the component unmounts
|
|
294
|
+
return () => {
|
|
295
|
+
delete window.loadInitialImageFromNative;
|
|
296
|
+
delete window.setAuthToken;
|
|
297
|
+
};
|
|
298
|
+
}, [loadImageFromId]);
|
|
299
|
+
const handleFileChange = (event) => {
|
|
300
|
+
const files = event.target?.files;
|
|
301
|
+
if (!files || files.length === 0)
|
|
302
|
+
return;
|
|
303
|
+
applyAdjustmentState(initialAdjustments);
|
|
304
|
+
setHistory([initialAdjustments]);
|
|
305
|
+
setHistoryIndex(0);
|
|
306
|
+
if (files.length === 1) {
|
|
307
|
+
setIsBulkEditing(false);
|
|
308
|
+
setImageList([]);
|
|
309
|
+
setSelectedImageIds(new Set());
|
|
310
|
+
setAdjustmentsMap(new Map());
|
|
311
|
+
loadImage(files[0]);
|
|
312
|
+
}
|
|
313
|
+
else {
|
|
314
|
+
setIsBulkEditing(true);
|
|
315
|
+
const newImageList = Array.from(files).map((file, index) => ({
|
|
316
|
+
id: `${file.name}-${Date.now()}-${index}`,
|
|
317
|
+
name: file.name,
|
|
318
|
+
file: file,
|
|
319
|
+
url: URL.createObjectURL(file),
|
|
320
|
+
}));
|
|
321
|
+
const newAdjustmentsMap = new Map();
|
|
322
|
+
newImageList.forEach(image => {
|
|
323
|
+
newAdjustmentsMap.set(image.id, { ...initialAdjustments });
|
|
324
|
+
});
|
|
325
|
+
setAdjustmentsMap(newAdjustmentsMap);
|
|
326
|
+
setImageList(newImageList);
|
|
327
|
+
setIsImageLoaded(true);
|
|
328
|
+
setSelectedImageIds(new Set(newImageList.map(img => img.id)));
|
|
329
|
+
}
|
|
330
|
+
};
|
|
331
|
+
const applyAdjustmentState = useCallback((state) => {
|
|
332
|
+
// Always update the UI controls
|
|
333
|
+
setTempScore(state.tempScore);
|
|
334
|
+
setTintScore(state.tintScore);
|
|
335
|
+
setVibranceScore(state.vibranceScore);
|
|
336
|
+
setExposureScore(state.exposureScore);
|
|
337
|
+
setHighlightsScore(state.highlightsScore);
|
|
338
|
+
setShadowsScore(state.shadowsScore);
|
|
339
|
+
setWhitesScore(state.whitesScore);
|
|
340
|
+
setBlacksScore(state.blacksScore);
|
|
341
|
+
setSaturationScore(state.saturationScore);
|
|
342
|
+
setContrastScore(state.contrastScore);
|
|
343
|
+
setClarityScore(state.clarityScore);
|
|
344
|
+
setSharpnessScore(state.sharpnessScore);
|
|
345
|
+
// If in bulk mode, apply this state to all selected images
|
|
346
|
+
if (isBulkEditing) {
|
|
347
|
+
applyUiStateToSelectedImages(state);
|
|
348
|
+
}
|
|
349
|
+
}, [isBulkEditing, applyUiStateToSelectedImages]);
|
|
350
|
+
const handleRevert = useCallback(() => {
|
|
351
|
+
// This will reset the UI controls and, if in bulk mode, the selected images
|
|
352
|
+
applyAdjustmentState(initialAdjustments);
|
|
353
|
+
// For single image mode, also reset the underlying canvas engine
|
|
354
|
+
if (!isBulkEditing && editorRef.current) {
|
|
355
|
+
editorRef.current.resetAdjustments();
|
|
356
|
+
}
|
|
357
|
+
}, [applyAdjustmentState, isBulkEditing]);
|
|
358
|
+
const handleUndo = useCallback(() => {
|
|
359
|
+
if (historyIndex > 0) {
|
|
360
|
+
const prevIndex = historyIndex - 1;
|
|
361
|
+
applyAdjustmentState(history[prevIndex]);
|
|
362
|
+
setHistoryIndex(prevIndex);
|
|
363
|
+
}
|
|
364
|
+
}, [history, historyIndex, applyAdjustmentState]);
|
|
365
|
+
const handleRedo = useCallback(() => {
|
|
366
|
+
if (historyIndex < history.length - 1) {
|
|
367
|
+
const nextIndex = historyIndex + 1;
|
|
368
|
+
applyAdjustmentState(history[nextIndex]);
|
|
369
|
+
setHistoryIndex(nextIndex);
|
|
370
|
+
}
|
|
371
|
+
}, [history, historyIndex, applyAdjustmentState]);
|
|
372
|
+
// MARK: - Bulk Editor Functions For Desktop and Mobile
|
|
373
|
+
// const adjustTempBulk = useCallback((uiAmount: number) => {
|
|
374
|
+
// setTempScore(prevScore => {
|
|
375
|
+
// const newScore = clamp(prevScore + uiAmount);
|
|
376
|
+
// console.log("Adjusting temperature. New score:", newScore);
|
|
377
|
+
// return newScore;
|
|
378
|
+
// });
|
|
379
|
+
// }, []);
|
|
380
|
+
// const adjustTintBulk = useCallback((uiAmount: number) => {
|
|
381
|
+
// setTintScore(prevScore => {
|
|
382
|
+
// const newScore = clamp(prevScore + uiAmount);
|
|
383
|
+
// console.log("Adjusting tint. New score:", newScore);
|
|
384
|
+
// return newScore;
|
|
385
|
+
// });
|
|
386
|
+
// }, []);
|
|
387
|
+
// const adjustVibranceBulk = useCallback((uiAmount: number) => {
|
|
388
|
+
// setVibranceScore(prevScore => {
|
|
389
|
+
// const newScore = clamp(prevScore + uiAmount);
|
|
390
|
+
// console.log("Adjusting vibrance. New score:", newScore);
|
|
391
|
+
// return newScore;
|
|
392
|
+
// });
|
|
393
|
+
// }, []);
|
|
394
|
+
// const adjustSaturationBulk = useCallback((uiAmount: number) => {
|
|
395
|
+
// setSaturationScore(prevScore => {
|
|
396
|
+
// const newScore = clamp(prevScore + uiAmount);
|
|
397
|
+
// console.log("Adjusting saturation. New score:", newScore);
|
|
398
|
+
// return newScore;
|
|
399
|
+
// });
|
|
400
|
+
// }, []);
|
|
401
|
+
// const adjustExposureBulk = useCallback((uiAmount: number) => {
|
|
402
|
+
// setExposureScore(prevScore => {
|
|
403
|
+
// const newScore = clamp(prevScore + uiAmount);
|
|
404
|
+
// console.log("Adjusting exposure. New score:", newScore);
|
|
405
|
+
// return newScore;
|
|
406
|
+
// });
|
|
407
|
+
// }, []);
|
|
408
|
+
// const adjustContrastBulk = useCallback((uiAmount: number) => {
|
|
409
|
+
// setContrastScore(prevScore => {
|
|
410
|
+
// const newScore = clamp(prevScore + uiAmount);
|
|
411
|
+
// console.log("Adjusting contrast. New score:", newScore);
|
|
412
|
+
// return newScore;
|
|
413
|
+
// });
|
|
414
|
+
// }, []);
|
|
415
|
+
// const adjustHighlightsBulk = useCallback((uiAmount: number) => {
|
|
416
|
+
// setHighlightsScore(prevScore => {
|
|
417
|
+
// const newScore = clamp(prevScore + uiAmount);
|
|
418
|
+
// console.log("Adjusting highlights. New score:", newScore);
|
|
419
|
+
// return newScore;
|
|
420
|
+
// });
|
|
421
|
+
// }, []);
|
|
422
|
+
// const adjustShadowsBulk = useCallback((uiAmount: number) => {
|
|
423
|
+
// setShadowsScore(prevScore => {
|
|
424
|
+
// const newScore = clamp(prevScore + uiAmount);
|
|
425
|
+
// console.log("Adjusting shadows. New score:", newScore);
|
|
426
|
+
// return newScore;
|
|
427
|
+
// });
|
|
428
|
+
// }, []);
|
|
429
|
+
// const adjustWhitesBulk = useCallback((uiAmount: number) => {
|
|
430
|
+
// setWhitesScore(prevScore => {
|
|
431
|
+
// const newScore = clamp(prevScore + uiAmount);
|
|
432
|
+
// console.log("Adjusting whites. New score:", newScore);
|
|
433
|
+
// return newScore;
|
|
434
|
+
// });
|
|
435
|
+
// }, []);
|
|
436
|
+
// const adjustBlacksBulk = useCallback((uiAmount: number) => {
|
|
437
|
+
// setBlacksScore(prevScore => {
|
|
438
|
+
// const newScore = clamp(prevScore + uiAmount);
|
|
439
|
+
// console.log("Adjusting blacks. New score:", newScore);
|
|
440
|
+
// return newScore;
|
|
441
|
+
// });
|
|
442
|
+
// }, []);
|
|
443
|
+
// const adjustClarityBulk = useCallback((uiAmount: number) => {
|
|
444
|
+
// setClarityScore(prevScore => {
|
|
445
|
+
// const newScore = clamp(prevScore + uiAmount);
|
|
446
|
+
// console.log("Adjusting clarity. New score:", newScore);
|
|
447
|
+
// return newScore;
|
|
448
|
+
// });
|
|
449
|
+
// }, []);
|
|
450
|
+
// const adjustSharpnessBulk = useCallback((uiAmount: number) => {
|
|
451
|
+
// setSharpnessScore(prevScore => {
|
|
452
|
+
// const newScore = clamp(prevScore + uiAmount);
|
|
453
|
+
// console.log("Adjusting sharpness. New score:", newScore);
|
|
454
|
+
// return newScore;
|
|
455
|
+
// });
|
|
456
|
+
// }, []);
|
|
457
|
+
const handleToggleImageSelection = useCallback((imageId) => {
|
|
458
|
+
const newSelectedIds = new Set(selectedImageIds);
|
|
459
|
+
const isCurrentlySelected = newSelectedIds.has(imageId);
|
|
460
|
+
if (isCurrentlySelected) {
|
|
461
|
+
if (newSelectedIds.size > 1) {
|
|
462
|
+
newSelectedIds.delete(imageId);
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
else {
|
|
466
|
+
newSelectedIds.add(imageId);
|
|
467
|
+
// Apply the current UI's adjustments to the newly selected image.
|
|
468
|
+
setAdjustmentsMap(prevMap => {
|
|
469
|
+
const newMap = new Map(prevMap);
|
|
470
|
+
const currentUiState = {
|
|
471
|
+
tempScore, tintScore, vibranceScore, saturationScore,
|
|
472
|
+
exposureScore, highlightsScore, shadowsScore, whitesScore,
|
|
473
|
+
blacksScore, contrastScore, clarityScore, sharpnessScore
|
|
474
|
+
};
|
|
475
|
+
newMap.set(imageId, currentUiState);
|
|
476
|
+
return newMap;
|
|
477
|
+
});
|
|
478
|
+
}
|
|
479
|
+
setSelectedImageIds(newSelectedIds);
|
|
480
|
+
}, [selectedImageIds, tempScore, tintScore, vibranceScore, saturationScore, exposureScore, highlightsScore, shadowsScore, whitesScore, blacksScore, contrastScore, clarityScore, sharpnessScore]);
|
|
481
|
+
const createAbsoluteSetter = (key, setter) => (value) => {
|
|
482
|
+
setter(value); // Update UI slider
|
|
483
|
+
if (isBulkEditing) {
|
|
484
|
+
setAdjustmentsMap(prevMap => {
|
|
485
|
+
const newMap = new Map(prevMap);
|
|
486
|
+
selectedImageIds.forEach(id => {
|
|
487
|
+
const currentState = newMap.get(id) || initialAdjustments;
|
|
488
|
+
newMap.set(id, { ...currentState, [key]: value });
|
|
489
|
+
});
|
|
490
|
+
return newMap;
|
|
491
|
+
});
|
|
492
|
+
}
|
|
493
|
+
};
|
|
494
|
+
const createRelativeAdjuster = (key, uiSetter, amount) => () => {
|
|
495
|
+
uiSetter(prev => clamp(prev + amount));
|
|
496
|
+
if (isBulkEditing) {
|
|
497
|
+
setAdjustmentsMap(prevMap => {
|
|
498
|
+
const newMap = new Map(prevMap);
|
|
499
|
+
selectedImageIds.forEach(id => {
|
|
500
|
+
const currentState = newMap.get(id) || initialAdjustments;
|
|
501
|
+
const currentValue = currentState[key];
|
|
502
|
+
const newValue = clamp(currentValue + amount);
|
|
503
|
+
newMap.set(id, { ...currentState, [key]: newValue });
|
|
504
|
+
});
|
|
505
|
+
console.log("this is UI Setter: ", uiSetter);
|
|
506
|
+
return newMap;
|
|
507
|
+
});
|
|
508
|
+
}
|
|
509
|
+
};
|
|
510
|
+
const setTempScoreAbs = createAbsoluteSetter('tempScore', setTempScore);
|
|
511
|
+
const setTintScoreAbs = createAbsoluteSetter('tintScore', setTintScore);
|
|
512
|
+
const setVibranceScoreAbs = createAbsoluteSetter('vibranceScore', setVibranceScore);
|
|
513
|
+
const setSaturationScoreAbs = createAbsoluteSetter('saturationScore', setSaturationScore);
|
|
514
|
+
const setExposureScoreAbs = createAbsoluteSetter('exposureScore', setExposureScore);
|
|
515
|
+
const setHighlightsScoreAbs = createAbsoluteSetter('highlightsScore', setHighlightsScore);
|
|
516
|
+
const setShadowsScoreAbs = createAbsoluteSetter('shadowsScore', setShadowsScore);
|
|
517
|
+
const setWhitesScoreAbs = createAbsoluteSetter('whitesScore', setWhitesScore);
|
|
518
|
+
const setBlacksScoreAbs = createAbsoluteSetter('blacksScore', setBlacksScore);
|
|
519
|
+
const setContrastScoreAbs = createAbsoluteSetter('contrastScore', setContrastScore);
|
|
520
|
+
const setClarityScoreAbs = createAbsoluteSetter('clarityScore', setClarityScore);
|
|
521
|
+
const setSharpnessScoreAbs = createAbsoluteSetter('sharpnessScore', setSharpnessScore);
|
|
522
|
+
// MARK: - Bulk Editor Handlers
|
|
523
|
+
const handleBulkTempDecreaseMax = createRelativeAdjuster('tempScore', setTempScore, -20);
|
|
524
|
+
const handleBulkTempDecrease = createRelativeAdjuster('tempScore', setTempScore, -5);
|
|
525
|
+
const handleBulkTempIncrease = createRelativeAdjuster('tempScore', setTempScore, 5);
|
|
526
|
+
const handleBulkTempIncreaseMax = createRelativeAdjuster('tempScore', setTempScore, 20);
|
|
527
|
+
const handleBulkTintDecreaseMax = createRelativeAdjuster('tintScore', setTintScore, -20);
|
|
528
|
+
const handleBulkTintDecrease = createRelativeAdjuster('tintScore', setTintScore, -5);
|
|
529
|
+
const handleBulkTintIncrease = createRelativeAdjuster('tintScore', setTintScore, 5);
|
|
530
|
+
const handleBulkTintIncreaseMax = createRelativeAdjuster('tintScore', setTintScore, 20);
|
|
531
|
+
const handleBulkVibranceDecreaseMax = createRelativeAdjuster('vibranceScore', setVibranceScore, -20);
|
|
532
|
+
const handleBulkVibranceDecrease = createRelativeAdjuster('vibranceScore', setVibranceScore, -5);
|
|
533
|
+
const handleBulkVibranceIncrease = createRelativeAdjuster('vibranceScore', setVibranceScore, 5);
|
|
534
|
+
const handleBulkVibranceIncreaseMax = createRelativeAdjuster('vibranceScore', setVibranceScore, 20);
|
|
535
|
+
const handleBulkSaturationDecreaseMax = createRelativeAdjuster('saturationScore', setSaturationScore, -20);
|
|
536
|
+
const handleBulkSaturationDecrease = createRelativeAdjuster('saturationScore', setSaturationScore, -5);
|
|
537
|
+
const handleBulkSaturationIncrease = createRelativeAdjuster('saturationScore', setSaturationScore, 5);
|
|
538
|
+
const handleBulkSaturationIncreaseMax = createRelativeAdjuster('saturationScore', setSaturationScore, 20);
|
|
539
|
+
const handleBulkExposureDecreaseMax = createRelativeAdjuster('exposureScore', setExposureScore, -20);
|
|
540
|
+
const handleBulkExposureDecrease = createRelativeAdjuster('exposureScore', setExposureScore, -5);
|
|
541
|
+
const handleBulkExposureIncrease = createRelativeAdjuster('exposureScore', setExposureScore, 5);
|
|
542
|
+
const handleBulkExposureIncreaseMax = createRelativeAdjuster('exposureScore', setExposureScore, 20);
|
|
543
|
+
const handleBulkContrastDecreaseMax = createRelativeAdjuster('contrastScore', setContrastScore, -20);
|
|
544
|
+
const handleBulkContrastDecrease = createRelativeAdjuster('contrastScore', setContrastScore, -5);
|
|
545
|
+
const handleBulkContrastIncrease = createRelativeAdjuster('contrastScore', setContrastScore, 5);
|
|
546
|
+
const handleBulkContrastIncreaseMax = createRelativeAdjuster('contrastScore', setContrastScore, 20);
|
|
547
|
+
const handleBulkHighlightsDecreaseMax = createRelativeAdjuster('highlightsScore', setHighlightsScore, -20);
|
|
548
|
+
const handleBulkHighlightsDecrease = createRelativeAdjuster('highlightsScore', setHighlightsScore, -5);
|
|
549
|
+
const handleBulkHighlightsIncrease = createRelativeAdjuster('highlightsScore', setHighlightsScore, 5);
|
|
550
|
+
const handleBulkHighlightsIncreaseMax = createRelativeAdjuster('highlightsScore', setHighlightsScore, 20);
|
|
551
|
+
const handleBulkShadowsDecreaseMax = createRelativeAdjuster('shadowsScore', setShadowsScore, -20);
|
|
552
|
+
const handleBulkShadowsDecrease = createRelativeAdjuster('shadowsScore', setShadowsScore, -5);
|
|
553
|
+
const handleBulkShadowsIncrease = createRelativeAdjuster('shadowsScore', setShadowsScore, 5);
|
|
554
|
+
const handleBulkShadowsIncreaseMax = createRelativeAdjuster('shadowsScore', setShadowsScore, 20);
|
|
555
|
+
const handleBulkWhitesDecreaseMax = createRelativeAdjuster('whitesScore', setWhitesScore, -20);
|
|
556
|
+
const handleBulkWhitesDecrease = createRelativeAdjuster('whitesScore', setWhitesScore, -5);
|
|
557
|
+
const handleBulkWhitesIncrease = createRelativeAdjuster('whitesScore', setWhitesScore, 5);
|
|
558
|
+
const handleBulkWhitesIncreaseMax = createRelativeAdjuster('whitesScore', setWhitesScore, 20);
|
|
559
|
+
const handleBulkBlacksDecreaseMax = createRelativeAdjuster('blacksScore', setBlacksScore, -20);
|
|
560
|
+
const handleBulkBlacksDecrease = createRelativeAdjuster('blacksScore', setBlacksScore, -5);
|
|
561
|
+
const handleBulkBlacksIncrease = createRelativeAdjuster('blacksScore', setBlacksScore, 5);
|
|
562
|
+
const handleBulkBlacksIncreaseMax = createRelativeAdjuster('blacksScore', setBlacksScore, 20);
|
|
563
|
+
const handleBulkClarityDecreaseMax = createRelativeAdjuster('clarityScore', setClarityScore, -20);
|
|
564
|
+
const handleBulkClarityDecrease = createRelativeAdjuster('clarityScore', setClarityScore, -5);
|
|
565
|
+
const handleBulkClarityIncrease = createRelativeAdjuster('clarityScore', setClarityScore, 5);
|
|
566
|
+
const handleBulkClarityIncreaseMax = createRelativeAdjuster('clarityScore', setClarityScore, 20);
|
|
567
|
+
const handleBulkSharpnessDecreaseMax = createRelativeAdjuster('sharpnessScore', setSharpnessScore, -20);
|
|
568
|
+
const handleBulkSharpnessDecrease = createRelativeAdjuster('sharpnessScore', setSharpnessScore, -5);
|
|
569
|
+
const handleBulkSharpnessIncrease = createRelativeAdjuster('sharpnessScore', setSharpnessScore, 5);
|
|
570
|
+
const handleBulkSharpnessIncreaseMax = createRelativeAdjuster('sharpnessScore', setSharpnessScore, 20);
|
|
571
|
+
const handleScriptReady = useCallback(async () => {
|
|
572
|
+
console.log("[Editor] Script tag is ready."); // Log entry
|
|
573
|
+
if (typeof window.Module === 'function' && !editorRef.current) {
|
|
574
|
+
console.log("[Editor] window.Module found. Initializing editor..."); // Log entry
|
|
575
|
+
try {
|
|
576
|
+
setEditorStatus("Loading WASM module...");
|
|
577
|
+
const editor = new HonchoEditor();
|
|
578
|
+
await editor.initialize(true);
|
|
579
|
+
editorRef.current = editor;
|
|
580
|
+
setIsEditorReady(true);
|
|
581
|
+
setEditorStatus("Ready! Select an image to start.");
|
|
582
|
+
console.log("[Editor] Initialization successful."); // Log entry
|
|
583
|
+
}
|
|
584
|
+
catch (error) {
|
|
585
|
+
console.error("[Editor] CRITICAL: Editor initialization failed:", error); // Critical error log
|
|
586
|
+
setEditorStatus(`Error: Could not load editor. See device logs.`);
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
else {
|
|
590
|
+
console.warn("[Editor] handleScriptReady called but conditions not met.", {
|
|
591
|
+
isModuleFunction: typeof window.Module === 'function',
|
|
592
|
+
isEditorAlreadyInitialized: !!editorRef.current
|
|
593
|
+
});
|
|
594
|
+
}
|
|
595
|
+
}, []);
|
|
596
|
+
// MARK: - UI Handlers (Moved from page.tsx)
|
|
597
|
+
// Header and Dialog Handlers
|
|
598
|
+
const handleHeaderMenuClick = (event) => setHeaderMenuAnchorEl(event.currentTarget);
|
|
599
|
+
const handleHeaderMenuClose = () => setHeaderMenuAnchorEl(null);
|
|
600
|
+
const handleAlertClose = () => {
|
|
601
|
+
setIsConnectionSlow(false);
|
|
602
|
+
};
|
|
603
|
+
const handleOpenCopyDialog = () => {
|
|
604
|
+
const newColorChecks = {
|
|
605
|
+
temperature: tempScore !== 0,
|
|
606
|
+
tint: tintScore !== 0,
|
|
607
|
+
vibrance: vibranceScore !== 0,
|
|
608
|
+
saturation: saturationScore !== 0,
|
|
609
|
+
};
|
|
610
|
+
const newLightChecks = {
|
|
611
|
+
exposure: exposureScore !== 0,
|
|
612
|
+
contrast: contrastScore !== 0,
|
|
613
|
+
highlights: highlightsScore !== 0,
|
|
614
|
+
shadows: shadowsScore !== 0,
|
|
615
|
+
whites: whitesScore !== 0,
|
|
616
|
+
blacks: blacksScore !== 0,
|
|
617
|
+
};
|
|
618
|
+
const newDetailsChecks = {
|
|
619
|
+
clarity: clarityScore !== 0,
|
|
620
|
+
sharpness: sharpnessScore !== 0,
|
|
621
|
+
};
|
|
622
|
+
setCopyColorChecks(newColorChecks);
|
|
623
|
+
setCopyLightChecks(newLightChecks);
|
|
624
|
+
setCopyDetailsChecks(newDetailsChecks);
|
|
625
|
+
setCopyDialogExpanded({
|
|
626
|
+
color: Object.values(newColorChecks).some(isChecked => isChecked),
|
|
627
|
+
light: Object.values(newLightChecks).some(isChecked => isChecked),
|
|
628
|
+
details: Object.values(newDetailsChecks).some(isChecked => isChecked),
|
|
629
|
+
});
|
|
630
|
+
setCopyDialogOpen(true);
|
|
631
|
+
handleHeaderMenuClose();
|
|
632
|
+
};
|
|
633
|
+
const handleCloseCopyDialog = () => setCopyDialogOpen(false);
|
|
634
|
+
const handleCopyParentChange = (event, setter) => {
|
|
635
|
+
const isChecked = event.target.checked;
|
|
636
|
+
setter((prev) => {
|
|
637
|
+
const newState = {};
|
|
638
|
+
Object.keys(prev).forEach(key => { newState[key] = isChecked; });
|
|
639
|
+
return newState;
|
|
640
|
+
});
|
|
641
|
+
};
|
|
642
|
+
const handleCopyChildChange = (event, setter) => {
|
|
643
|
+
setter((prev) => ({
|
|
644
|
+
...prev,
|
|
645
|
+
[event.target.name]: event.target.checked,
|
|
646
|
+
}));
|
|
647
|
+
};
|
|
648
|
+
const handleToggleCopyDialogExpand = (section) => {
|
|
649
|
+
setCopyDialogExpanded(prev => ({ ...prev, [section]: !prev[section] }));
|
|
650
|
+
};
|
|
651
|
+
const handleCopyEdit = useCallback(() => {
|
|
652
|
+
const adjustmentsToCopy = {};
|
|
653
|
+
// Color Adjustments
|
|
654
|
+
if (copyColorChecks.temperature)
|
|
655
|
+
adjustmentsToCopy.tempScore = tempScore;
|
|
656
|
+
if (copyColorChecks.tint)
|
|
657
|
+
adjustmentsToCopy.tintScore = tintScore;
|
|
658
|
+
if (copyColorChecks.vibrance)
|
|
659
|
+
adjustmentsToCopy.vibranceScore = vibranceScore;
|
|
660
|
+
if (copyColorChecks.saturation)
|
|
661
|
+
adjustmentsToCopy.saturationScore = saturationScore;
|
|
662
|
+
// Light Adjustments
|
|
663
|
+
if (copyLightChecks.exposure)
|
|
664
|
+
adjustmentsToCopy.exposureScore = exposureScore;
|
|
665
|
+
if (copyLightChecks.contrast)
|
|
666
|
+
adjustmentsToCopy.contrastScore = contrastScore;
|
|
667
|
+
if (copyLightChecks.highlights)
|
|
668
|
+
adjustmentsToCopy.highlightsScore = highlightsScore;
|
|
669
|
+
if (copyLightChecks.shadows)
|
|
670
|
+
adjustmentsToCopy.shadowsScore = shadowsScore;
|
|
671
|
+
if (copyLightChecks.whites)
|
|
672
|
+
adjustmentsToCopy.whitesScore = whitesScore;
|
|
673
|
+
if (copyLightChecks.blacks)
|
|
674
|
+
adjustmentsToCopy.blacksScore = blacksScore;
|
|
675
|
+
// Details Adjustments
|
|
676
|
+
if (copyDetailsChecks.clarity)
|
|
677
|
+
adjustmentsToCopy.clarityScore = clarityScore;
|
|
678
|
+
if (copyDetailsChecks.sharpness)
|
|
679
|
+
adjustmentsToCopy.sharpnessScore = sharpnessScore;
|
|
680
|
+
// Combine with existing copied adjustments to not lose unchecked values from a previous copy
|
|
681
|
+
setCopiedAdjustments(prev => ({ ...initialAdjustments, ...prev, ...adjustmentsToCopy }));
|
|
682
|
+
console.log("Copied selected adjustments:", adjustmentsToCopy);
|
|
683
|
+
}, [
|
|
684
|
+
copyColorChecks, copyLightChecks, copyDetailsChecks,
|
|
685
|
+
tempScore, tintScore, vibranceScore, saturationScore, exposureScore, contrastScore,
|
|
686
|
+
highlightsScore, shadowsScore, whitesScore, blacksScore, clarityScore, sharpnessScore
|
|
687
|
+
]);
|
|
688
|
+
const handleConfirmCopy = () => { handleCopyEdit(); handleCloseCopyDialog(); setShowCopyAlert(true); };
|
|
689
|
+
const handlePasteEdit = useCallback(() => {
|
|
690
|
+
if (copiedAdjustments) {
|
|
691
|
+
applyAdjustmentState(copiedAdjustments);
|
|
692
|
+
}
|
|
693
|
+
}, [copiedAdjustments, applyAdjustmentState]);
|
|
694
|
+
// Panel Handlers
|
|
695
|
+
const handleColorAccordionChange = (panel) => (_, isExpanded) => {
|
|
696
|
+
setColorAdjustmentExpandedPanels(prev => isExpanded ? [...new Set([...prev, panel])] : prev.filter(p => p !== panel));
|
|
697
|
+
};
|
|
698
|
+
const handlePresetAccordionChange = (panel) => (_, isExpanded) => {
|
|
699
|
+
setPresetExpandedPanels(prev => isExpanded ? [...new Set([...prev, panel])] : prev.filter(p => p !== panel));
|
|
700
|
+
};
|
|
701
|
+
// MARK: - Preset Handlers
|
|
702
|
+
// Also it calls for the backend endpoint
|
|
703
|
+
const fetchPresets = useCallback(async () => {
|
|
704
|
+
if (!controller)
|
|
705
|
+
return;
|
|
706
|
+
try {
|
|
707
|
+
const fetchedPresets = await controller.getPresets();
|
|
708
|
+
setPresets(fetchedPresets);
|
|
709
|
+
}
|
|
710
|
+
catch (error) {
|
|
711
|
+
console.error("Failed to fetch presets:", error);
|
|
712
|
+
}
|
|
713
|
+
}, [controller]);
|
|
714
|
+
const handleSelectMobilePreset = (presetId) => setSelectedMobilePreset(presetId);
|
|
715
|
+
const handleSelectDesktopPreset = (presetId) => setSelectedDesktopPreset(presetId);
|
|
716
|
+
const handlePresetMenuClick = (event, presetId) => {
|
|
717
|
+
event.stopPropagation();
|
|
718
|
+
setPresetMenuAnchorEl(event.currentTarget);
|
|
719
|
+
setActivePresetMenuId(presetId);
|
|
720
|
+
};
|
|
721
|
+
const handlePresetMenuClose = () => { setPresetMenuAnchorEl(null); setActivePresetMenuId(null); };
|
|
722
|
+
const handleRemovePreset = () => { console.log(`Remove: ${activePresetMenuId}`); handlePresetMenuClose(); };
|
|
723
|
+
const handleRenamePreset = useCallback(async (newName) => {
|
|
724
|
+
if (!controller || !activePresetMenuId)
|
|
725
|
+
return;
|
|
726
|
+
try {
|
|
727
|
+
await controller.renamePreset(activePresetMenuId, newName);
|
|
728
|
+
// On success, update the preset in local state
|
|
729
|
+
setPresets(prev => prev.map(p => p.id === activePresetMenuId ? { ...p, name: newName } : p));
|
|
730
|
+
}
|
|
731
|
+
catch (error) {
|
|
732
|
+
console.error("Failed to rename preset:", error);
|
|
733
|
+
}
|
|
734
|
+
handlePresetMenuClose();
|
|
735
|
+
}, [controller, activePresetMenuId]);
|
|
736
|
+
const handleDeletePreset = useCallback(async () => {
|
|
737
|
+
if (!controller || !activePresetMenuId)
|
|
738
|
+
return;
|
|
739
|
+
try {
|
|
740
|
+
await controller.deletePreset(activePresetMenuId);
|
|
741
|
+
// On success, remove the preset from local state
|
|
742
|
+
setPresets(prevPresets => prevPresets.filter(p => p.id !== activePresetMenuId));
|
|
743
|
+
}
|
|
744
|
+
catch (error) {
|
|
745
|
+
console.error("Failed to delete preset:", error);
|
|
746
|
+
}
|
|
747
|
+
handlePresetMenuClose(); // Close the options menu
|
|
748
|
+
}, [controller, activePresetMenuId]);
|
|
749
|
+
// Preset Modal Handlers
|
|
750
|
+
const handleOpenPresetModal = () => { setIsPresetCreated(false); setPresetModalOpen(true); };
|
|
751
|
+
const handleClosePresetModal = () => setPresetModalOpen(false);
|
|
752
|
+
const handleCreatePreset = useCallback(async () => {
|
|
753
|
+
if (!controller)
|
|
754
|
+
return;
|
|
755
|
+
const currentAdjustments = { tempScore, tintScore, vibranceScore, exposureScore, highlightsScore, shadowsScore, whitesScore, blacksScore, saturationScore, contrastScore, clarityScore, sharpnessScore };
|
|
756
|
+
try {
|
|
757
|
+
const newPreset = await controller.createPreset(presetName, currentAdjustments);
|
|
758
|
+
if (newPreset) {
|
|
759
|
+
// Add the new preset returned from the API to our local state
|
|
760
|
+
setPresets(prevPresets => [...prevPresets, newPreset]);
|
|
761
|
+
}
|
|
762
|
+
}
|
|
763
|
+
catch (error) {
|
|
764
|
+
console.error("Failed to create preset:", error);
|
|
765
|
+
}
|
|
766
|
+
console.log("Creating preset:", presetName);
|
|
767
|
+
const newPreset = { id: `preset${presets.length + 1}`, name: presetName };
|
|
768
|
+
setPresets(prevPresets => [...prevPresets, newPreset]);
|
|
769
|
+
setIsPresetCreated(true);
|
|
770
|
+
handleClosePresetModal();
|
|
771
|
+
setTimeout(() => setIsPresetCreated(false), 1000);
|
|
772
|
+
}, [controller, presetName, tempScore, tintScore, exposureScore, highlightsScore, shadowsScore, whitesScore, blacksScore, saturationScore, contrastScore, clarityScore, sharpnessScore]);
|
|
773
|
+
const handleOpenPresetModalMobile = () => { setIsPresetCreated(false); setPresetModalOpenMobile(true); };
|
|
774
|
+
const handleClosePresetModalMobile = () => setPresetModalOpenMobile(false);
|
|
775
|
+
const handleCreatePresetMobile = () => {
|
|
776
|
+
console.log("Creating mobile preset:", presetName);
|
|
777
|
+
const newPreset = { id: `preset${presets.length + 1}`, name: presetName };
|
|
778
|
+
setPresets(prevPresets => [...prevPresets, newPreset]);
|
|
779
|
+
setIsPresetCreated(true);
|
|
780
|
+
handleClosePresetModalMobile();
|
|
781
|
+
setTimeout(() => setIsPresetCreated(false), 1000);
|
|
782
|
+
};
|
|
783
|
+
const handleNameChange = (event) => setPresetName(event.target.value);
|
|
784
|
+
// Watermark Handlers
|
|
785
|
+
const handleOpenWatermarkView = () => setIsCreatingWatermark(true);
|
|
786
|
+
const handleSaveWatermark = () => setIsCreatingWatermark(false);
|
|
787
|
+
const handleCancelWatermark = () => setIsCreatingWatermark(false);
|
|
788
|
+
const handleOpenRenameModal = useCallback(() => {
|
|
789
|
+
if (!activePresetMenuId)
|
|
790
|
+
return;
|
|
791
|
+
const preset = presets.find(p => p.id === activePresetMenuId);
|
|
792
|
+
if (preset) {
|
|
793
|
+
setPresetToRename(preset);
|
|
794
|
+
setNewPresetName(preset.name); // Pre-fill the input with the current name
|
|
795
|
+
setRenameModalOpen(true);
|
|
796
|
+
}
|
|
797
|
+
handlePresetMenuClose(); // Close the small options menu
|
|
798
|
+
}, [activePresetMenuId, presets]);
|
|
799
|
+
const handleCloseRenameModal = () => {
|
|
800
|
+
setRenameModalOpen(false);
|
|
801
|
+
setPresetToRename(null);
|
|
802
|
+
setNewPresetName("");
|
|
803
|
+
};
|
|
804
|
+
const handleConfirmRename = useCallback(async () => {
|
|
805
|
+
if (!presetToRename || !newPresetName)
|
|
806
|
+
return;
|
|
807
|
+
try {
|
|
808
|
+
await controller.renamePreset(presetToRename.id, newPresetName);
|
|
809
|
+
// On success, update the preset in local state
|
|
810
|
+
setPresets(prev => prev.map(p => p.id === presetToRename.id ? { ...p, name: newPresetName } : p));
|
|
811
|
+
}
|
|
812
|
+
catch (error) {
|
|
813
|
+
console.error("Failed to rename preset:", error);
|
|
814
|
+
}
|
|
815
|
+
handleCloseRenameModal();
|
|
816
|
+
}, [controller, presetToRename, newPresetName]);
|
|
817
|
+
// Bulk Editing Handlers
|
|
818
|
+
const toggleBulkEditing = () => {
|
|
819
|
+
setIsBulkEditing(prev => {
|
|
820
|
+
const isNowBulk = !prev;
|
|
821
|
+
setSelectedImages(isNowBulk ? 'Selected' : 'Select');
|
|
822
|
+
return isNowBulk;
|
|
823
|
+
});
|
|
824
|
+
};
|
|
825
|
+
const handleSelectBulkPreset = (event) => setSelectedBulkPreset(event.target.value);
|
|
826
|
+
// MARK : Image original and canvas
|
|
827
|
+
const handleShowOriginal = useCallback(() => {
|
|
828
|
+
if (!editorRef.current || !isImageLoaded)
|
|
829
|
+
return;
|
|
830
|
+
console.log("Showing original image...");
|
|
831
|
+
// 1. Set the flag to true to pause history recording
|
|
832
|
+
setIsViewingOriginal(true);
|
|
833
|
+
// 2. Apply the initial state to the view
|
|
834
|
+
applyAdjustmentState(initialAdjustments);
|
|
835
|
+
}, [isImageLoaded, applyAdjustmentState]);
|
|
836
|
+
const handleShowEdited = useCallback(() => {
|
|
837
|
+
if (!editorRef.current || !isImageLoaded)
|
|
838
|
+
return;
|
|
839
|
+
console.log("Restoring edited image...");
|
|
840
|
+
const latestState = history[historyIndex];
|
|
841
|
+
if (latestState) {
|
|
842
|
+
// 3. Re-apply the latest state from history
|
|
843
|
+
applyAdjustmentState(latestState);
|
|
844
|
+
}
|
|
845
|
+
// 4. Set the flag back to false AFTER the state has been restored.
|
|
846
|
+
// A small timeout ensures this runs after the re-render.
|
|
847
|
+
setTimeout(() => setIsViewingOriginal(false), 0);
|
|
848
|
+
}, [isImageLoaded, history, historyIndex, applyAdjustmentState]);
|
|
849
|
+
// MARK: - Zoom Handlers
|
|
850
|
+
const handleZoomAction = useCallback((action) => {
|
|
851
|
+
let newZoom = zoomLevel;
|
|
852
|
+
const zoomStep = 1.25;
|
|
853
|
+
switch (action) {
|
|
854
|
+
case 'in':
|
|
855
|
+
newZoom *= zoomStep;
|
|
856
|
+
break;
|
|
857
|
+
case 'out':
|
|
858
|
+
newZoom /= zoomStep;
|
|
859
|
+
break;
|
|
860
|
+
case 'fit':
|
|
861
|
+
newZoom = 1;
|
|
862
|
+
break;
|
|
863
|
+
case '50%':
|
|
864
|
+
newZoom = 0.5;
|
|
865
|
+
break;
|
|
866
|
+
case '100%':
|
|
867
|
+
newZoom = 1;
|
|
868
|
+
break;
|
|
869
|
+
case '200%':
|
|
870
|
+
newZoom = 2;
|
|
871
|
+
break;
|
|
872
|
+
}
|
|
873
|
+
setZoomLevel(Math.max(0.1, Math.min(newZoom, 8)));
|
|
874
|
+
}, [zoomLevel]);
|
|
875
|
+
const handleWheelZoom = useCallback((event) => {
|
|
876
|
+
if (!isImageLoaded)
|
|
877
|
+
return;
|
|
878
|
+
event.preventDefault(); // Prevent page from scrolling
|
|
879
|
+
const zoomFactor = 1.1;
|
|
880
|
+
let newZoom = zoomLevel;
|
|
881
|
+
if (event.deltaY < 0) {
|
|
882
|
+
newZoom *= zoomFactor; // Scroll up to zoom in
|
|
883
|
+
}
|
|
884
|
+
else {
|
|
885
|
+
newZoom /= zoomFactor; // Scroll down to zoom out
|
|
886
|
+
}
|
|
887
|
+
setZoomLevel(Math.max(0.1, Math.min(newZoom, 8)));
|
|
888
|
+
}, [zoomLevel, isImageLoaded]);
|
|
889
|
+
useEffect(() => {
|
|
890
|
+
if (canvasRef.current) {
|
|
891
|
+
canvasRef.current.style.transition = 'transform 0.1s ease-out';
|
|
892
|
+
canvasRef.current.style.transform = `scale(${zoomLevel})`;
|
|
893
|
+
}
|
|
894
|
+
}, [zoomLevel]);
|
|
895
|
+
// MARK: - Effects
|
|
896
|
+
// Preset Image List
|
|
897
|
+
useEffect(() => {
|
|
898
|
+
fetchPresets();
|
|
899
|
+
}, [controller, fetchPresets]);
|
|
900
|
+
// Image Load
|
|
901
|
+
useEffect(() => {
|
|
902
|
+
if (isImageLoaded && editorRef.current && canvasRef.current) {
|
|
903
|
+
const { width, height } = editorRef.current.getImageSize();
|
|
904
|
+
canvasRef.current.width = width;
|
|
905
|
+
canvasRef.current.height = height;
|
|
906
|
+
updateCanvas();
|
|
907
|
+
setEditorStatus("Image loaded successfully!");
|
|
908
|
+
}
|
|
909
|
+
}, [isImageLoaded, updateCanvas]);
|
|
910
|
+
// Adjustment USE EFFECTS
|
|
911
|
+
useEffect(() => { if (isImageLoaded) {
|
|
912
|
+
editorRef.current?.setExposure(exposureScore);
|
|
913
|
+
updateCanvas();
|
|
914
|
+
} }, [exposureScore, isImageLoaded, updateCanvas]);
|
|
915
|
+
useEffect(() => { if (isImageLoaded) {
|
|
916
|
+
editorRef.current?.setVibrance(vibranceScore);
|
|
917
|
+
updateCanvas();
|
|
918
|
+
} }, [vibranceScore, isImageLoaded, updateCanvas]);
|
|
919
|
+
useEffect(() => { if (isImageLoaded) {
|
|
920
|
+
editorRef.current?.setContrast(contrastScore);
|
|
921
|
+
updateCanvas();
|
|
922
|
+
} }, [contrastScore, isImageLoaded, updateCanvas]);
|
|
923
|
+
useEffect(() => { if (isImageLoaded) {
|
|
924
|
+
editorRef.current?.setHighlights(highlightsScore);
|
|
925
|
+
updateCanvas();
|
|
926
|
+
} }, [highlightsScore, isImageLoaded, updateCanvas]);
|
|
927
|
+
useEffect(() => { if (isImageLoaded) {
|
|
928
|
+
editorRef.current?.setShadows(shadowsScore);
|
|
929
|
+
updateCanvas();
|
|
930
|
+
} }, [shadowsScore, isImageLoaded, updateCanvas]);
|
|
931
|
+
useEffect(() => { if (isImageLoaded) {
|
|
932
|
+
editorRef.current?.setSaturation(saturationScore);
|
|
933
|
+
updateCanvas();
|
|
934
|
+
} }, [saturationScore, isImageLoaded, updateCanvas]);
|
|
935
|
+
useEffect(() => { if (isImageLoaded) {
|
|
936
|
+
editorRef.current?.setTemperature(tempScore);
|
|
937
|
+
updateCanvas();
|
|
938
|
+
} }, [tempScore, isImageLoaded, updateCanvas]);
|
|
939
|
+
useEffect(() => { if (isImageLoaded) {
|
|
940
|
+
editorRef.current?.setTint(tintScore);
|
|
941
|
+
updateCanvas();
|
|
942
|
+
} }, [tintScore, isImageLoaded, updateCanvas]);
|
|
943
|
+
useEffect(() => { if (isImageLoaded) {
|
|
944
|
+
editorRef.current?.setBlacks(blacksScore);
|
|
945
|
+
updateCanvas();
|
|
946
|
+
} }, [blacksScore, isImageLoaded, updateCanvas]);
|
|
947
|
+
useEffect(() => { if (isImageLoaded) {
|
|
948
|
+
editorRef.current?.setWhites(whitesScore);
|
|
949
|
+
updateCanvas();
|
|
950
|
+
} }, [whitesScore, isImageLoaded, updateCanvas]);
|
|
951
|
+
useEffect(() => { if (isImageLoaded) {
|
|
952
|
+
editorRef.current?.setClarity(clarityScore);
|
|
953
|
+
updateCanvas();
|
|
954
|
+
} }, [clarityScore, isImageLoaded, updateCanvas]);
|
|
955
|
+
useEffect(() => { if (isImageLoaded) {
|
|
956
|
+
editorRef.current?.setSharpness(sharpnessScore);
|
|
957
|
+
updateCanvas();
|
|
958
|
+
} }, [sharpnessScore, isImageLoaded, updateCanvas]);
|
|
959
|
+
useEffect(() => {
|
|
960
|
+
// 5. Add a check to ignore state changes while viewing the original
|
|
961
|
+
if (!isImageLoaded || isViewingOriginal)
|
|
962
|
+
return;
|
|
963
|
+
const newState = { tempScore, tintScore, vibranceScore, exposureScore, highlightsScore, shadowsScore, whitesScore, blacksScore, saturationScore, contrastScore, clarityScore, sharpnessScore };
|
|
964
|
+
if (JSON.stringify(history[historyIndex]) === JSON.stringify(newState))
|
|
965
|
+
return;
|
|
966
|
+
const newHistory = history.slice(0, historyIndex + 1);
|
|
967
|
+
setHistory([...newHistory, newState]);
|
|
968
|
+
setHistoryIndex(newHistory.length);
|
|
969
|
+
}, [
|
|
970
|
+
tempScore, tintScore, vibranceScore, exposureScore, highlightsScore, shadowsScore,
|
|
971
|
+
whitesScore, blacksScore, saturationScore, contrastScore, clarityScore, sharpnessScore,
|
|
972
|
+
isImageLoaded, history, historyIndex,
|
|
973
|
+
isViewingOriginal
|
|
974
|
+
]);
|
|
975
|
+
useEffect(() => {
|
|
976
|
+
if (showCopyAlert) {
|
|
977
|
+
const timer = setTimeout(() => setShowCopyAlert(false), 2000);
|
|
978
|
+
return () => clearTimeout(timer);
|
|
979
|
+
}
|
|
980
|
+
}, [showCopyAlert]);
|
|
981
|
+
useEffect(() => {
|
|
982
|
+
const handleOnline = () => setIsOnline(true);
|
|
983
|
+
const handleOffline = () => setIsOnline(false);
|
|
984
|
+
window.addEventListener('online', handleOnline);
|
|
985
|
+
window.addEventListener('offline', handleOffline);
|
|
986
|
+
return () => {
|
|
987
|
+
window.removeEventListener('online', handleOnline);
|
|
988
|
+
window.removeEventListener('offline', handleOffline);
|
|
989
|
+
};
|
|
990
|
+
}, []);
|
|
991
|
+
useEffect(() => {
|
|
992
|
+
// The function returned by useEffect is the cleanup function.
|
|
993
|
+
// It will run only when the component that uses this hook unmounts.
|
|
994
|
+
return () => {
|
|
995
|
+
if (editorRef.current) {
|
|
996
|
+
console.log("Cleaning up Honcho Editor instance...");
|
|
997
|
+
editorRef.current.cleanup(); // This calls the C++ cleanup function
|
|
998
|
+
}
|
|
999
|
+
};
|
|
1000
|
+
}, []);
|
|
1001
|
+
return {
|
|
1002
|
+
// Refs
|
|
1003
|
+
canvasRef,
|
|
1004
|
+
canvasContainerRef,
|
|
1005
|
+
fileInputRef,
|
|
1006
|
+
displayedToken,
|
|
1007
|
+
handleBack: controller.handleBack,
|
|
1008
|
+
onGetImage: controller.onGetImage,
|
|
1009
|
+
getImageList: controller.getImageList,
|
|
1010
|
+
syncConfig: controller.syncConfig,
|
|
1011
|
+
getPresets: controller.getPresets,
|
|
1012
|
+
createPreset: controller.createPreset,
|
|
1013
|
+
deletePreset: controller.deletePreset,
|
|
1014
|
+
renamePreset: controller.renamePreset,
|
|
1015
|
+
// Refs for mobile panel
|
|
1016
|
+
panelRef,
|
|
1017
|
+
contentRef,
|
|
1018
|
+
// State for mobile panel
|
|
1019
|
+
panelHeight,
|
|
1020
|
+
// Handlers for mobile panel
|
|
1021
|
+
handleDragStart,
|
|
1022
|
+
handleContentHeightChange,
|
|
1023
|
+
// Status & State
|
|
1024
|
+
editorStatus,
|
|
1025
|
+
isEditorReady,
|
|
1026
|
+
isImageLoaded,
|
|
1027
|
+
isPasteAvailable: copiedAdjustments !== null,
|
|
1028
|
+
isOnline,
|
|
1029
|
+
isConnectionSlow,
|
|
1030
|
+
showCopyAlert,
|
|
1031
|
+
isCopyDialogOpen,
|
|
1032
|
+
isPublished,
|
|
1033
|
+
activePanel,
|
|
1034
|
+
activeSubPanel,
|
|
1035
|
+
headerMenuAnchorEl,
|
|
1036
|
+
anchorMenuZoom,
|
|
1037
|
+
colorAdjustmentExpandedPanels,
|
|
1038
|
+
presetExpandedPanels,
|
|
1039
|
+
isCreatingWatermark,
|
|
1040
|
+
isPresetModalOpen,
|
|
1041
|
+
isPresetModalOpenMobile,
|
|
1042
|
+
presetName,
|
|
1043
|
+
isPresetCreated,
|
|
1044
|
+
selectedMobilePreset,
|
|
1045
|
+
selectedDesktopPreset,
|
|
1046
|
+
selectedBulkPreset,
|
|
1047
|
+
presetMenuAnchorEl,
|
|
1048
|
+
activePresetMenuId,
|
|
1049
|
+
currentAspectRatio,
|
|
1050
|
+
currentSquareRatio,
|
|
1051
|
+
currentWideRatio,
|
|
1052
|
+
angelScore,
|
|
1053
|
+
widthSizePX,
|
|
1054
|
+
heightSizePX,
|
|
1055
|
+
isBulkEditing,
|
|
1056
|
+
selectedImages,
|
|
1057
|
+
colorAdjustments,
|
|
1058
|
+
lightAdjustments,
|
|
1059
|
+
detailsAdjustments,
|
|
1060
|
+
handleShowOriginal,
|
|
1061
|
+
handleShowEdited,
|
|
1062
|
+
handleWheelZoom,
|
|
1063
|
+
handleZoomAction,
|
|
1064
|
+
zoomLevelText: `${Math.round(zoomLevel * 100)}%`,
|
|
1065
|
+
presets,
|
|
1066
|
+
// Functions
|
|
1067
|
+
handleScriptReady,
|
|
1068
|
+
handleFileChange,
|
|
1069
|
+
handleAlertClose,
|
|
1070
|
+
loadImageFromId,
|
|
1071
|
+
loadImageFromUrl,
|
|
1072
|
+
handleRevert,
|
|
1073
|
+
handleUndo,
|
|
1074
|
+
handleRedo,
|
|
1075
|
+
handleOpenCopyDialog,
|
|
1076
|
+
handleCloseCopyDialog,
|
|
1077
|
+
copyColorChecks,
|
|
1078
|
+
setCopyColorChecks,
|
|
1079
|
+
copyLightChecks,
|
|
1080
|
+
setCopyLightChecks,
|
|
1081
|
+
copyDetailsChecks,
|
|
1082
|
+
setCopyDetailsChecks,
|
|
1083
|
+
copyDialogExpanded,
|
|
1084
|
+
handleCopyParentChange,
|
|
1085
|
+
handleCopyChildChange,
|
|
1086
|
+
handleToggleCopyDialogExpand,
|
|
1087
|
+
handleConfirmCopy,
|
|
1088
|
+
handleCopyEdit,
|
|
1089
|
+
handlePasteEdit,
|
|
1090
|
+
// adjustClarityBulk,
|
|
1091
|
+
// adjustSharpnessBulk,
|
|
1092
|
+
// Setters & Handlers
|
|
1093
|
+
setActivePanel,
|
|
1094
|
+
setActiveSubPanel,
|
|
1095
|
+
setHeaderMenuAnchorEl,
|
|
1096
|
+
setAnchorMenuZoom,
|
|
1097
|
+
handleHeaderMenuClick,
|
|
1098
|
+
handleHeaderMenuClose,
|
|
1099
|
+
setColorAdjustments,
|
|
1100
|
+
setLightAdjustments,
|
|
1101
|
+
setDetailsAdjustments,
|
|
1102
|
+
handleColorAccordionChange,
|
|
1103
|
+
handlePresetAccordionChange,
|
|
1104
|
+
handleSelectMobilePreset,
|
|
1105
|
+
handleSelectDesktopPreset,
|
|
1106
|
+
handlePresetMenuClick,
|
|
1107
|
+
handlePresetMenuClose,
|
|
1108
|
+
handleCreatePreset,
|
|
1109
|
+
handleRemovePreset,
|
|
1110
|
+
handleRenamePreset,
|
|
1111
|
+
handleDeletePreset,
|
|
1112
|
+
handleOpenPresetModal,
|
|
1113
|
+
handleClosePresetModal,
|
|
1114
|
+
handleOpenPresetModalMobile,
|
|
1115
|
+
handleClosePresetModalMobile,
|
|
1116
|
+
handleCreatePresetMobile,
|
|
1117
|
+
setPresetName,
|
|
1118
|
+
handleNameChange,
|
|
1119
|
+
isRenameModalOpen,
|
|
1120
|
+
presetToRename,
|
|
1121
|
+
newPresetName,
|
|
1122
|
+
setNewPresetName,
|
|
1123
|
+
handleOpenRenameModal,
|
|
1124
|
+
handleCloseRenameModal,
|
|
1125
|
+
handleConfirmRename,
|
|
1126
|
+
handleOpenWatermarkView,
|
|
1127
|
+
handleSaveWatermark,
|
|
1128
|
+
handleCancelWatermark,
|
|
1129
|
+
toggleBulkEditing,
|
|
1130
|
+
handleSelectBulkPreset,
|
|
1131
|
+
// Adjustment State & Setters
|
|
1132
|
+
tempScore, setTempScore: setTempScoreAbs,
|
|
1133
|
+
tintScore, setTintScore: setTintScoreAbs,
|
|
1134
|
+
vibranceScore, setVibranceScore: setVibranceScoreAbs,
|
|
1135
|
+
saturationScore, setSaturationScore: setSaturationScoreAbs,
|
|
1136
|
+
exposureScore, setExposureScore: setExposureScoreAbs,
|
|
1137
|
+
highlightsScore, setHighlightsScore: setHighlightsScoreAbs,
|
|
1138
|
+
shadowsScore, setShadowsScore: setShadowsScoreAbs,
|
|
1139
|
+
whitesScore, setWhitesScore: setWhitesScoreAbs,
|
|
1140
|
+
blacksScore, setBlacksScore: setBlacksScoreAbs,
|
|
1141
|
+
contrastScore, setContrastScore: setContrastScoreAbs,
|
|
1142
|
+
clarityScore, setClarityScore: setClarityScoreAbs,
|
|
1143
|
+
sharpnessScore, setSharpnessScore: setSharpnessScoreAbs,
|
|
1144
|
+
// Bulk Adjustment Handlers
|
|
1145
|
+
// Note: These handlers are for image list
|
|
1146
|
+
imageList,
|
|
1147
|
+
adjustmentsMap,
|
|
1148
|
+
selectedImageIds,
|
|
1149
|
+
handleToggleImageSelection,
|
|
1150
|
+
// Note: These handlers are for bulk adjustments
|
|
1151
|
+
// Adjustment Colors
|
|
1152
|
+
handleBulkTempDecreaseMax,
|
|
1153
|
+
handleBulkTempDecrease,
|
|
1154
|
+
handleBulkTempIncrease,
|
|
1155
|
+
handleBulkTempIncreaseMax,
|
|
1156
|
+
handleBulkTintDecreaseMax,
|
|
1157
|
+
handleBulkTintDecrease,
|
|
1158
|
+
handleBulkTintIncrease,
|
|
1159
|
+
handleBulkTintIncreaseMax,
|
|
1160
|
+
handleBulkVibranceDecreaseMax,
|
|
1161
|
+
handleBulkVibranceDecrease,
|
|
1162
|
+
handleBulkVibranceIncrease,
|
|
1163
|
+
handleBulkVibranceIncreaseMax,
|
|
1164
|
+
handleBulkSaturationDecreaseMax,
|
|
1165
|
+
handleBulkSaturationDecrease,
|
|
1166
|
+
handleBulkSaturationIncrease,
|
|
1167
|
+
handleBulkSaturationIncreaseMax,
|
|
1168
|
+
// Adjustment Light
|
|
1169
|
+
handleBulkExposureDecreaseMax,
|
|
1170
|
+
handleBulkExposureDecrease,
|
|
1171
|
+
handleBulkExposureIncrease,
|
|
1172
|
+
handleBulkExposureIncreaseMax,
|
|
1173
|
+
handleBulkContrastDecreaseMax,
|
|
1174
|
+
handleBulkContrastDecrease,
|
|
1175
|
+
handleBulkContrastIncrease,
|
|
1176
|
+
handleBulkContrastIncreaseMax,
|
|
1177
|
+
handleBulkHighlightsDecreaseMax,
|
|
1178
|
+
handleBulkHighlightsDecrease,
|
|
1179
|
+
handleBulkHighlightsIncrease,
|
|
1180
|
+
handleBulkHighlightsIncreaseMax,
|
|
1181
|
+
handleBulkShadowsDecreaseMax,
|
|
1182
|
+
handleBulkShadowsDecrease,
|
|
1183
|
+
handleBulkShadowsIncrease,
|
|
1184
|
+
handleBulkShadowsIncreaseMax,
|
|
1185
|
+
handleBulkWhitesDecreaseMax,
|
|
1186
|
+
handleBulkWhitesDecrease,
|
|
1187
|
+
handleBulkWhitesIncrease,
|
|
1188
|
+
handleBulkWhitesIncreaseMax,
|
|
1189
|
+
handleBulkBlacksDecreaseMax,
|
|
1190
|
+
handleBulkBlacksDecrease,
|
|
1191
|
+
handleBulkBlacksIncrease,
|
|
1192
|
+
handleBulkBlacksIncreaseMax,
|
|
1193
|
+
// Adjustment Details
|
|
1194
|
+
handleBulkClarityDecreaseMax,
|
|
1195
|
+
handleBulkClarityDecrease,
|
|
1196
|
+
handleBulkClarityIncrease,
|
|
1197
|
+
handleBulkClarityIncreaseMax,
|
|
1198
|
+
handleBulkSharpnessDecreaseMax,
|
|
1199
|
+
handleBulkSharpnessDecrease,
|
|
1200
|
+
handleBulkSharpnessIncrease,
|
|
1201
|
+
handleBulkSharpnessIncreaseMax,
|
|
1202
|
+
};
|
|
1203
|
+
}
|