File size: 4,727 Bytes
763be49
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115

import { useState, useEffect, useCallback } from 'react';
import { saveCanvasState as dbSaveCanvasState, loadCanvasState as dbLoadCanvasState, LoadedCanvasState } from '../services/dbService';
import { MAX_HISTORY_STEPS, DEFAULT_CANVAS_WIDTH, DEFAULT_CANVAS_HEIGHT } from '../constants';
import { getBlankCanvasDataURL } from '../utils/canvasUtils';

export interface CanvasHistoryHook {
  historyStack: string[];
  currentHistoryIndex: number;
  canvasWidth: number;
  canvasHeight: number;
  isLoading: boolean;
  currentDataURL: string | null;
  handleDrawEnd: (dataURL: string, newWidth?: number, newHeight?: number) => void;
  handleUndo: () => void;
  handleRedo: () => void;
  updateCanvasState: (dataURL: string, width: number, height: number) => void;
}


export const useCanvasHistory = (): CanvasHistoryHook => {
  const [historyStack, setHistoryStack] = useState<string[]>([]);
  const [currentHistoryIndex, setCurrentHistoryIndex] = useState<number>(-1);
  const [canvasWidth, setCanvasWidth] = useState<number>(DEFAULT_CANVAS_WIDTH);
  const [canvasHeight, setCanvasHeight] = useState<number>(DEFAULT_CANVAS_HEIGHT);
  const [isLoading, setIsLoading] = useState<boolean>(true);

  const currentDataURL = historyStack.length > 0 && currentHistoryIndex >= 0 ? historyStack[currentHistoryIndex] : null;

  const loadInitialCanvas = useCallback(async () => {
    setIsLoading(true);
    const savedState: LoadedCanvasState | null = await dbLoadCanvasState();
    if (savedState && savedState.dataURL) { // Ensure dataURL exists
      setCanvasWidth(savedState.width);
      setCanvasHeight(savedState.height);
      setHistoryStack([savedState.dataURL]);
      setCurrentHistoryIndex(0);
    } else {
      const initialWidth = DEFAULT_CANVAS_WIDTH;
      const initialHeight = DEFAULT_CANVAS_HEIGHT;
      setCanvasWidth(initialWidth);
      setCanvasHeight(initialHeight);
      const blankCanvas = getBlankCanvasDataURL(initialWidth, initialHeight);
      setHistoryStack([blankCanvas]);
      setCurrentHistoryIndex(0);
      await dbSaveCanvasState(blankCanvas, initialWidth, initialHeight);
    }
    setIsLoading(false);
  }, []);

  useEffect(() => {
    loadInitialCanvas();
  }, [loadInitialCanvas]);

  const handleDrawEnd = useCallback((dataURL: string, newWidth?: number, newHeight?: number) => {
    const effectiveWidth = newWidth ?? canvasWidth;
    const effectiveHeight = newHeight ?? canvasHeight;

    if (newWidth && newWidth !== canvasWidth) setCanvasWidth(newWidth);
    if (newHeight && newHeight !== canvasHeight) setCanvasHeight(newHeight);
    
    setHistoryStack(prevStack => {
      // If currentHistoryIndex is not at the end, it means we've undone some steps.
      // New drawing should overwrite the "redo" history.
      const newStackBase = prevStack.slice(0, currentHistoryIndex + 1);
      let newStack = [...newStackBase, dataURL];
      
      if (newStack.length > MAX_HISTORY_STEPS) {
        newStack = newStack.slice(newStack.length - MAX_HISTORY_STEPS);
      }
      // Update currentHistoryIndex to point to the new state (end of the new stack)
      setCurrentHistoryIndex(newStack.length - 1);
      return newStack;
    });
    dbSaveCanvasState(dataURL, effectiveWidth, effectiveHeight);
  }, [currentHistoryIndex, canvasWidth, canvasHeight]); // Added canvasWidth, canvasHeight as they are used for effective dimensions.

  const updateCanvasState = useCallback((dataURL: string, width: number, height: number) => {
      // This function is for direct updates, like loading an image or AI result
      handleDrawEnd(dataURL, width, height);
  }, [handleDrawEnd]);


  const handleUndo = () => {
    if (currentHistoryIndex > 0) {
      setCurrentHistoryIndex(prevIndex => prevIndex - 1);
      // Autosave current state when undoing to ensure persistence of the "undone to" state.
      // This is implicit as currentDataURL will update, and if the app were to reload,
      // it should load the state at currentHistoryIndex.
      // The currentDataURL used by CanvasComponent will be historyStack[newIndex].
      // dbSaveCanvasState(historyStack[currentHistoryIndex - 1], canvasWidth, canvasHeight); // This might be too aggressive, rely on drawEnd
    }
  };

  const handleRedo = () => {
    if (currentHistoryIndex < historyStack.length - 1) {
      setCurrentHistoryIndex(prevIndex => prevIndex + 1);
      // dbSaveCanvasState(historyStack[currentHistoryIndex + 1], canvasWidth, canvasHeight); // Same as undo, might be too aggressive
    }
  };

  return {
    historyStack,
    currentHistoryIndex,
    canvasWidth,
    canvasHeight,
    isLoading,
    currentDataURL,
    handleDrawEnd,
    handleUndo,
    handleRedo,
    updateCanvasState,
  };
};