@umituz/react-native-video-editor 1.1.47 → 1.1.49
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/package.json +5 -1
- package/src/VideoEditor.tsx +1 -1
- package/src/domain/entities/video-project.types.ts +49 -0
- package/src/index.ts +28 -27
- package/src/infrastructure/constants/animation-layer.constants.ts +1 -1
- package/src/infrastructure/constants/filter.constants.ts +1 -1
- package/src/infrastructure/services/image-layer-operations.service.ts +24 -6
- package/src/infrastructure/services/layer-manipulation.service.ts +6 -8
- package/src/infrastructure/services/layer-operations/layer-delete.service.ts +2 -2
- package/src/infrastructure/services/layer-operations/layer-duplicate.service.ts +2 -2
- package/src/infrastructure/services/layer-operations/layer-order.service.ts +16 -2
- package/src/infrastructure/services/layer-operations/layer-transform.service.ts +15 -6
- package/src/infrastructure/services/layer-operations.service.ts +2 -2
- package/src/infrastructure/services/scene-operations.service.ts +2 -2
- package/src/infrastructure/services/shape-layer-operations.service.ts +5 -5
- package/src/infrastructure/services/text-layer-operations.service.ts +13 -4
- package/src/infrastructure/utils/srt.utils.ts +8 -1
- package/src/player/index.ts +0 -3
- package/src/player/presentation/components/FullScreenVideoPlayer.tsx +0 -1
- package/src/player/presentation/components/VideoPlayer.tsx +8 -7
- package/src/player/presentation/components/VideoPlayerOverlay.tsx +1 -1
- package/src/player/presentation/hooks/useVideoPlaybackProgress.ts +0 -1
- package/src/player/presentation/hooks/useVideoPlayerControl.ts +6 -4
- package/src/player/{types/index.ts → types.ts} +3 -2
- package/src/presentation/components/AnimationEditor.tsx +4 -6
- package/src/presentation/components/AudioEditor.tsx +6 -8
- package/src/presentation/components/DraggableLayer.tsx +1 -1
- package/src/presentation/components/EditorPreviewArea.tsx +1 -1
- package/src/presentation/components/EditorTimeline.tsx +1 -1
- package/src/presentation/components/ExportDialog.tsx +7 -9
- package/src/presentation/components/ImageLayerEditor.tsx +4 -6
- package/src/presentation/components/LayerActionsMenu.tsx +1 -1
- package/src/presentation/components/ShapeLayerEditor.tsx +5 -7
- package/src/presentation/components/SubtitleListPanel.tsx +1 -1
- package/src/presentation/components/TextLayerEditor.tsx +8 -10
- package/src/presentation/components/VideoFilterPicker.tsx +1 -1
- package/src/presentation/components/animation-layer/AnimationTypeSelector.tsx +2 -2
- package/src/presentation/components/draggable-layer/LayerContent.tsx +1 -1
- package/src/presentation/components/export/ProjectInfoBox.tsx +1 -1
- package/src/presentation/components/shape-layer/ShapeTypeSelector.tsx +1 -1
- package/src/presentation/hooks/useAnimationLayerForm.ts +1 -1
- package/src/presentation/hooks/useAudioLayerForm.ts +1 -1
- package/src/presentation/hooks/useDraggableLayerGestures.ts +21 -4
- package/src/presentation/hooks/useEditorActions.tsx +1 -1
- package/src/presentation/hooks/useEditorHistory.ts +5 -4
- package/src/presentation/hooks/useEditorLayers.ts +2 -2
- package/src/presentation/hooks/useEditorPlayback.ts +1 -1
- package/src/presentation/hooks/useEditorScenes.ts +1 -1
- package/src/presentation/hooks/useExport.ts +1 -1
- package/src/presentation/hooks/useExportActions.tsx +1 -1
- package/src/presentation/hooks/useExportForm.ts +1 -1
- package/src/presentation/hooks/useImageLayerForm.ts +1 -1
- package/src/presentation/hooks/useImageLayerOperations.ts +1 -1
- package/src/presentation/hooks/useLayerActions.tsx +3 -5
- package/src/presentation/hooks/useLayerManipulation.ts +1 -1
- package/src/presentation/hooks/useMenuActions.tsx +1 -1
- package/src/presentation/hooks/useSceneActions.tsx +1 -1
- package/src/presentation/hooks/useShapeLayerForm.ts +1 -1
- package/src/presentation/hooks/useShapeLayerOperations.ts +1 -1
- package/src/presentation/hooks/useTextLayerForm.ts +1 -1
- package/src/presentation/hooks/useTextLayerOperations.ts +1 -1
- package/src/domain/entities/index.ts +0 -52
- package/src/infrastructure/constants/index.ts +0 -15
- package/src/infrastructure/services/layer-operations/index.ts +0 -9
- package/src/presentation/components/animation-layer/index.ts +0 -8
- package/src/presentation/components/audio-layer/index.ts +0 -10
- package/src/presentation/components/export/index.ts +0 -11
- package/src/presentation/components/image-layer/index.ts +0 -8
- package/src/presentation/components/index.ts +0 -24
- package/src/presentation/components/shape-layer/index.ts +0 -9
- package/src/presentation/components/text-layer/index.ts +0 -12
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
import React from "react";
|
|
7
7
|
import { View, ScrollView, StyleSheet } from "react-native";
|
|
8
8
|
|
|
9
|
-
import type { Animation } from "../../domain/entities";
|
|
9
|
+
import type { Animation } from "../../domain/entities/video-project.types";
|
|
10
10
|
import { useAnimationLayerForm } from "../hooks/useAnimationLayerForm";
|
|
11
11
|
import {
|
|
12
12
|
DURATIONS,
|
|
@@ -16,11 +16,9 @@ import {
|
|
|
16
16
|
} from "../../infrastructure/constants/animation-layer.constants";
|
|
17
17
|
import { ValueSelector } from "./shape-layer/ValueSelector";
|
|
18
18
|
import { OptionSelector } from "./text-layer/OptionSelector";
|
|
19
|
-
import {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
} from "./animation-layer";
|
|
23
|
-
import { AnimationInfoBanner } from "./animation-layer";
|
|
19
|
+
import { AnimationTypeSelector } from "./animation-layer/AnimationTypeSelector";
|
|
20
|
+
import { AnimationEditorActions } from "./animation-layer/AnimationEditorActions";
|
|
21
|
+
import { AnimationInfoBanner } from "./animation-layer/AnimationInfoBanner";
|
|
24
22
|
|
|
25
23
|
interface AnimationEditorProps {
|
|
26
24
|
animation?: Animation;
|
|
@@ -9,16 +9,14 @@ import * as DocumentPicker from "expo-document-picker";
|
|
|
9
9
|
import { AtomicText } from "@umituz/react-native-design-system/atoms";
|
|
10
10
|
import { useAppDesignTokens } from "@umituz/react-native-design-system/theme";
|
|
11
11
|
import { useLocalization } from "@umituz/react-native-settings";
|
|
12
|
-
import type { Audio } from "../../domain/entities";
|
|
12
|
+
import type { Audio } from "../../domain/entities/video-project.types";
|
|
13
13
|
import { useAudioLayerForm } from "../hooks/useAudioLayerForm";
|
|
14
14
|
import { AUDIO_FILE_TYPES } from "../../infrastructure/constants/audio-layer.constants";
|
|
15
|
-
import {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
AudioEditorActions,
|
|
21
|
-
} from "./audio-layer";
|
|
15
|
+
import { AudioFileSelector } from "./audio-layer/AudioFileSelector";
|
|
16
|
+
import { VolumeSelector } from "./audio-layer/VolumeSelector";
|
|
17
|
+
import { FadeEffectsSelector } from "./audio-layer/FadeEffectsSelector";
|
|
18
|
+
import { InfoBanner } from "./audio-layer/InfoBanner";
|
|
19
|
+
import { AudioEditorActions } from "./audio-layer/AudioEditorActions";
|
|
22
20
|
|
|
23
21
|
interface AudioEditorProps {
|
|
24
22
|
audio?: Audio;
|
|
@@ -7,7 +7,7 @@ import React from "react";
|
|
|
7
7
|
import { View, StyleSheet } from "react-native";
|
|
8
8
|
import { GestureDetector } from "react-native-gesture-handler";
|
|
9
9
|
import { useAppDesignTokens } from "@umituz/react-native-design-system/theme";
|
|
10
|
-
import type { Layer } from "../../domain/entities";
|
|
10
|
+
import type { Layer } from "../../domain/entities/video-project.types";
|
|
11
11
|
import { useDraggableLayerGestures } from "../hooks/useDraggableLayerGestures";
|
|
12
12
|
import { LayerContent } from "./draggable-layer/LayerContent";
|
|
13
13
|
import { ResizeHandles } from "./draggable-layer/ResizeHandles";
|
|
@@ -8,7 +8,7 @@ import { View, TouchableOpacity, Dimensions } from "react-native";
|
|
|
8
8
|
import { AtomicText, AtomicIcon } from "@umituz/react-native-design-system/atoms";
|
|
9
9
|
import { useAppDesignTokens } from "@umituz/react-native-design-system/theme";
|
|
10
10
|
import { DraggableLayer } from "./DraggableLayer";
|
|
11
|
-
import type { Scene, Layer } from "../../domain/entities";
|
|
11
|
+
import type { Scene, Layer } from "../../domain/entities/video-project.types";
|
|
12
12
|
import { createPreviewStyles } from "./EditorPreviewArea.styles";
|
|
13
13
|
|
|
14
14
|
const { width } = Dimensions.get("window");
|
|
@@ -8,7 +8,7 @@ import { View, ScrollView, TouchableOpacity, StyleSheet } from "react-native";
|
|
|
8
8
|
import { AtomicText, AtomicIcon } from "@umituz/react-native-design-system/atoms";
|
|
9
9
|
import { useAppDesignTokens } from "@umituz/react-native-design-system/theme";
|
|
10
10
|
import { useLocalization } from "@umituz/react-native-settings";
|
|
11
|
-
import type { VideoProject, Scene } from "../../domain/entities";
|
|
11
|
+
import type { VideoProject, Scene } from "../../domain/entities/video-project.types";
|
|
12
12
|
|
|
13
13
|
interface EditorTimelineProps {
|
|
14
14
|
project: VideoProject;
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
import React, { useCallback } from "react";
|
|
7
7
|
import { View, ScrollView, StyleSheet, Alert } from "react-native";
|
|
8
8
|
import { useLocalization } from "@umituz/react-native-settings";
|
|
9
|
-
import type { ExportSettings, VideoProject } from "../../domain/entities";
|
|
9
|
+
import type { ExportSettings, VideoProject } from "../../domain/entities/video-project.types";
|
|
10
10
|
import { useExportForm } from "../hooks/useExportForm";
|
|
11
11
|
import { useExport, type UseExportConfig, type ExportResult } from "../hooks/useExport";
|
|
12
12
|
import {
|
|
@@ -14,14 +14,12 @@ import {
|
|
|
14
14
|
QUALITIES,
|
|
15
15
|
FORMATS,
|
|
16
16
|
} from "../../infrastructure/constants/export.constants";
|
|
17
|
-
import {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
ExportActions,
|
|
24
|
-
} from "./export";
|
|
17
|
+
import { ProjectInfoBox } from "./export/ProjectInfoBox";
|
|
18
|
+
import { OptionSelectorRow } from "./export/OptionSelectorRow";
|
|
19
|
+
import { WatermarkToggle } from "./export/WatermarkToggle";
|
|
20
|
+
import { ExportProgress } from "./export/ExportProgress";
|
|
21
|
+
import { ExportInfoBanner } from "./export/ExportInfoBanner";
|
|
22
|
+
import { ExportActions } from "./export/ExportActions";
|
|
25
23
|
|
|
26
24
|
interface ExportDialogProps {
|
|
27
25
|
readonly project: VideoProject;
|
|
@@ -5,13 +5,11 @@
|
|
|
5
5
|
|
|
6
6
|
import React, { useCallback } from "react";
|
|
7
7
|
import { View, ScrollView, StyleSheet, Alert } from "react-native";
|
|
8
|
-
import type { ImageLayer } from "../../domain/entities";
|
|
8
|
+
import type { ImageLayer } from "../../domain/entities/video-project.types";
|
|
9
9
|
import { useImageLayerForm } from "../hooks/useImageLayerForm";
|
|
10
|
-
import {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
OpacitySelector,
|
|
14
|
-
} from "./image-layer";
|
|
10
|
+
import { ImagePreview } from "./image-layer/ImagePreview";
|
|
11
|
+
import { ImageSelectionButtons } from "./image-layer/ImageSelectionButtons";
|
|
12
|
+
import { OpacitySelector } from "./image-layer/OpacitySelector";
|
|
15
13
|
import { EditorActions } from "./text-layer/EditorActions";
|
|
16
14
|
|
|
17
15
|
interface ImagePickerResult {
|
|
@@ -8,7 +8,7 @@ import { View, TouchableOpacity, StyleSheet } from "react-native";
|
|
|
8
8
|
import { AtomicText, AtomicIcon } from "@umituz/react-native-design-system/atoms";
|
|
9
9
|
import { useAppDesignTokens } from "@umituz/react-native-design-system/theme";
|
|
10
10
|
import { useLocalization } from "@umituz/react-native-settings";
|
|
11
|
-
import type { Layer } from "../../domain/entities";
|
|
11
|
+
import type { Layer } from "../../domain/entities/video-project.types";
|
|
12
12
|
|
|
13
13
|
interface LayerActionsMenuProps {
|
|
14
14
|
layer: Layer;
|
|
@@ -5,18 +5,16 @@
|
|
|
5
5
|
|
|
6
6
|
import React from "react";
|
|
7
7
|
import { View, ScrollView, StyleSheet } from "react-native";
|
|
8
|
-
import type { ShapeLayer } from "../../domain/entities";
|
|
8
|
+
import type { ShapeLayer } from "../../domain/entities/video-project.types";
|
|
9
9
|
import { useShapeLayerForm } from "../hooks/useShapeLayerForm";
|
|
10
10
|
import {
|
|
11
11
|
BORDER_WIDTHS,
|
|
12
12
|
OPACITY_OPTIONS,
|
|
13
13
|
} from "../../infrastructure/constants/shape-layer.constants";
|
|
14
|
-
import {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
ShapePreview,
|
|
19
|
-
} from "./shape-layer";
|
|
14
|
+
import { ShapeTypeSelector } from "./shape-layer/ShapeTypeSelector";
|
|
15
|
+
import { ColorPickerHorizontal } from "./shape-layer/ColorPickerHorizontal";
|
|
16
|
+
import { ValueSelector } from "./shape-layer/ValueSelector";
|
|
17
|
+
import { ShapePreview } from "./shape-layer/ShapePreview";
|
|
20
18
|
import { EditorActions } from "./text-layer/EditorActions";
|
|
21
19
|
|
|
22
20
|
interface ShapeLayerEditorProps {
|
|
@@ -6,21 +6,19 @@
|
|
|
6
6
|
import React from "react";
|
|
7
7
|
import { View, ScrollView, StyleSheet } from "react-native";
|
|
8
8
|
import { useLocalization } from "@umituz/react-native-settings";
|
|
9
|
-
import type { TextLayer } from "../../domain/entities";
|
|
9
|
+
import type { TextLayer } from "../../domain/entities/video-project.types";
|
|
10
10
|
import { useTextLayerForm } from "../hooks/useTextLayerForm";
|
|
11
11
|
import {
|
|
12
12
|
FONT_FAMILIES,
|
|
13
13
|
FONT_WEIGHTS,
|
|
14
14
|
} from "../../infrastructure/constants/text-layer.constants";
|
|
15
|
-
import {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
EditorActions,
|
|
23
|
-
} from "./text-layer";
|
|
15
|
+
import { TextInputSection } from "./text-layer/TextInputSection";
|
|
16
|
+
import { FontSizeSelector } from "./text-layer/FontSizeSelector";
|
|
17
|
+
import { OptionSelector } from "./text-layer/OptionSelector";
|
|
18
|
+
import { TextAlignSelector } from "./text-layer/TextAlignSelector";
|
|
19
|
+
import { ColorPicker } from "./text-layer/ColorPicker";
|
|
20
|
+
import { TextPreview } from "./text-layer/TextPreview";
|
|
21
|
+
import { EditorActions } from "./text-layer/EditorActions";
|
|
24
22
|
|
|
25
23
|
interface TextLayerEditorProps {
|
|
26
24
|
layer?: TextLayer;
|
|
@@ -8,7 +8,7 @@ import { View, ScrollView, TouchableOpacity, StyleSheet } from "react-native";
|
|
|
8
8
|
import { AtomicText, AtomicIcon } from "@umituz/react-native-design-system/atoms";
|
|
9
9
|
import { useAppDesignTokens } from "@umituz/react-native-design-system/theme";
|
|
10
10
|
import { FILTER_PRESETS } from "../../infrastructure/constants/filter.constants";
|
|
11
|
-
import type { FilterPreset } from "../../domain/entities";
|
|
11
|
+
import type { FilterPreset } from "../../domain/entities/video-project.types";
|
|
12
12
|
|
|
13
13
|
interface VideoFilterPickerProps {
|
|
14
14
|
activeFilter: FilterPreset;
|
|
@@ -8,7 +8,7 @@ import { View, ScrollView, StyleSheet, TouchableOpacity } from "react-native";
|
|
|
8
8
|
import { AtomicText, AtomicIcon } from "@umituz/react-native-design-system/atoms";
|
|
9
9
|
import { useAppDesignTokens } from "@umituz/react-native-design-system/theme";
|
|
10
10
|
import { ANIMATION_TYPES } from "../../../infrastructure/constants/animation-layer.constants";
|
|
11
|
-
import type { AnimationType } from "../../../domain/entities";
|
|
11
|
+
import type { AnimationType } from "../../../domain/entities/video-project.types";
|
|
12
12
|
|
|
13
13
|
interface AnimationTypeSelectorProps {
|
|
14
14
|
selectedType: AnimationType;
|
|
@@ -58,7 +58,7 @@ export const AnimationTypeSelector: React.FC<AnimationTypeSelectorProps> = ({
|
|
|
58
58
|
onPress={() => onTypeChange(anim.type)}
|
|
59
59
|
>
|
|
60
60
|
<AtomicIcon
|
|
61
|
-
name={anim.icon as
|
|
61
|
+
name={anim.icon as "Ban" | "Eye" | "MoveRight" | "ArrowUp" | "Maximize2" | "RotateCw"}
|
|
62
62
|
size="md"
|
|
63
63
|
color={selectedType === anim.type ? "onSurface" : "primary"}
|
|
64
64
|
/>
|
|
@@ -7,7 +7,7 @@ import React from "react";
|
|
|
7
7
|
import { View, Image, Text as RNText, StyleSheet } from "react-native";
|
|
8
8
|
import { AtomicIcon } from "@umituz/react-native-design-system/atoms";
|
|
9
9
|
import { useAppDesignTokens } from "@umituz/react-native-design-system/theme";
|
|
10
|
-
import type { Layer, TextLayer, ImageLayer, ShapeLayer } from "../../../domain/entities";
|
|
10
|
+
import type { Layer, TextLayer, ImageLayer, ShapeLayer } from "../../../domain/entities/video-project.types";
|
|
11
11
|
|
|
12
12
|
interface LayerContentProps {
|
|
13
13
|
layer: Layer;
|
|
@@ -7,7 +7,7 @@ import React from "react";
|
|
|
7
7
|
import { View, StyleSheet } from "react-native";
|
|
8
8
|
import { AtomicText, AtomicIcon } from "@umituz/react-native-design-system/atoms";
|
|
9
9
|
import { useAppDesignTokens } from "@umituz/react-native-design-system/theme";
|
|
10
|
-
import type { VideoProject } from "../../../domain/entities";
|
|
10
|
+
import type { VideoProject } from "../../../domain/entities/video-project.types";
|
|
11
11
|
|
|
12
12
|
interface ProjectInfoBoxProps {
|
|
13
13
|
project: VideoProject;
|
|
@@ -56,7 +56,7 @@ export const ShapeTypeSelector: React.FC<ShapeTypeSelectorProps> = ({
|
|
|
56
56
|
onPress={() => onShapeChange(s.type)}
|
|
57
57
|
>
|
|
58
58
|
<AtomicIcon
|
|
59
|
-
name={s.icon as
|
|
59
|
+
name={s.icon as "Square" | "Circle" | "Triangle"}
|
|
60
60
|
size="lg"
|
|
61
61
|
color={selectedShape === s.type ? "onSurface" : "primary"}
|
|
62
62
|
/>
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import { useState, useCallback } from "react";
|
|
7
|
-
import type { Animation, AnimationType } from "../../domain/entities";
|
|
7
|
+
import type { Animation, AnimationType } from "../../domain/entities/video-project.types";
|
|
8
8
|
import type { Easing } from "../../infrastructure/constants/animation-layer.constants";
|
|
9
9
|
|
|
10
10
|
interface AnimationLayerFormState {
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* Manages gesture handling for draggable layers
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import { useState, useRef, useCallback } from "react";
|
|
6
|
+
import { useState, useRef, useCallback, useEffect } from "react";
|
|
7
7
|
import { Gesture } from "react-native-gesture-handler";
|
|
8
8
|
|
|
9
9
|
interface UseDraggableLayerGesturesParams {
|
|
@@ -56,6 +56,17 @@ export function useDraggableLayerGestures({
|
|
|
56
56
|
|
|
57
57
|
const startRef = useRef({ x: initialX, y: initialY, width: initialWidth, height: initialHeight });
|
|
58
58
|
|
|
59
|
+
// Sync state when initial values change (e.g., layer props update from parent)
|
|
60
|
+
useEffect(() => {
|
|
61
|
+
setState({
|
|
62
|
+
x: initialX,
|
|
63
|
+
y: initialY,
|
|
64
|
+
width: initialWidth,
|
|
65
|
+
height: initialHeight,
|
|
66
|
+
});
|
|
67
|
+
startRef.current = { x: initialX, y: initialY, width: initialWidth, height: initialHeight };
|
|
68
|
+
}, [initialX, initialY, initialWidth, initialHeight]);
|
|
69
|
+
|
|
59
70
|
const clamp = useCallback((value: number, min: number, max: number) => {
|
|
60
71
|
return Math.max(min, Math.min(max, value));
|
|
61
72
|
}, []);
|
|
@@ -110,13 +121,19 @@ export function useDraggableLayerGestures({
|
|
|
110
121
|
})
|
|
111
122
|
.onEnd(() => {
|
|
112
123
|
setState((prev) => {
|
|
124
|
+
// Clamp position to canvas bounds
|
|
125
|
+
const clampedX = Math.max(0, Math.min(prev.x, canvasWidth - prev.width));
|
|
126
|
+
const clampedY = Math.max(0, Math.min(prev.y, canvasHeight - prev.height));
|
|
127
|
+
|
|
113
128
|
const newWidth = (prev.width / canvasWidth) * 100;
|
|
114
129
|
const newHeight = (prev.height / canvasHeight) * 100;
|
|
115
|
-
const newX = (
|
|
116
|
-
const newY = (
|
|
130
|
+
const newX = (clampedX / canvasWidth) * 100;
|
|
131
|
+
const newY = (clampedY / canvasHeight) * 100;
|
|
132
|
+
|
|
117
133
|
onSizeChange(newWidth, newHeight);
|
|
118
134
|
onPositionChange(newX, newY);
|
|
119
|
-
|
|
135
|
+
|
|
136
|
+
return { ...prev, x: clampedX, y: clampedY };
|
|
120
137
|
});
|
|
121
138
|
});
|
|
122
139
|
};
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* Single Responsibility: Compose editor action handlers
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import type { VideoProject, Scene, ExportSettings, Layer } from "../../domain/entities";
|
|
6
|
+
import type { VideoProject, Scene, ExportSettings, Layer } from "../../domain/entities/video-project.types";
|
|
7
7
|
import type { UseEditorLayersReturn } from "./useEditorLayers";
|
|
8
8
|
import type { UseEditorScenesReturn } from "./useEditorScenes";
|
|
9
9
|
import type { UseEditorBottomSheetReturn } from "./useEditorBottomSheet";
|
|
@@ -4,11 +4,10 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import { useCallback, useState } from "react";
|
|
7
|
-
import type { VideoProject } from "../../domain/entities";
|
|
7
|
+
import type { VideoProject } from "../../domain/entities/video-project.types";
|
|
8
8
|
|
|
9
9
|
interface UseEditorHistoryParams {
|
|
10
10
|
project: VideoProject | undefined;
|
|
11
|
-
projectId: string; // Kept for interface compatibility, used for reset if needed
|
|
12
11
|
onUpdateProject: (updates: Partial<VideoProject>) => void;
|
|
13
12
|
}
|
|
14
13
|
|
|
@@ -32,12 +31,14 @@ export function useEditorHistory({
|
|
|
32
31
|
const updateWithHistory = useCallback(
|
|
33
32
|
(updates: Partial<VideoProject>, _action: string) => {
|
|
34
33
|
if (project) {
|
|
34
|
+
// Deep clone the project to avoid reference issues
|
|
35
|
+
const clonedProject = JSON.parse(JSON.stringify(project)) as VideoProject;
|
|
35
36
|
setHistory((prev) => {
|
|
36
|
-
const next = [...prev,
|
|
37
|
+
const next = [...prev, clonedProject];
|
|
37
38
|
return next.length > MAX_HISTORY_SIZE ? next.slice(-MAX_HISTORY_SIZE) : next;
|
|
38
39
|
});
|
|
39
40
|
setFuture([]);
|
|
40
|
-
|
|
41
|
+
|
|
41
42
|
onUpdateProject(updates);
|
|
42
43
|
}
|
|
43
44
|
},
|
|
@@ -13,8 +13,8 @@ import type {
|
|
|
13
13
|
AddShapeLayerData,
|
|
14
14
|
LayerOrderAction,
|
|
15
15
|
Scene,
|
|
16
|
-
} from "../../domain/entities";
|
|
17
|
-
import type { TextLayer, ImageLayer, Animation } from "../../domain/entities";
|
|
16
|
+
} from "../../domain/entities/video-project.types";
|
|
17
|
+
import type { TextLayer, ImageLayer, Animation } from "../../domain/entities/video-project.types";
|
|
18
18
|
|
|
19
19
|
interface UseEditorLayersParams {
|
|
20
20
|
projectId: string;
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import { useState, useEffect, useCallback } from "react";
|
|
7
|
-
import type { Scene } from "../../domain/entities";
|
|
7
|
+
import type { Scene } from "../../domain/entities/video-project.types";
|
|
8
8
|
|
|
9
9
|
interface UseEditorPlaybackParams {
|
|
10
10
|
currentScene: Scene | undefined;
|
|
@@ -7,7 +7,7 @@ import { useCallback } from "react";
|
|
|
7
7
|
import { Alert } from "react-native";
|
|
8
8
|
import { useLocalization } from "@umituz/react-native-settings";
|
|
9
9
|
import { sceneOperationsService } from "../../infrastructure/services/scene-operations.service";
|
|
10
|
-
import type { Scene, Audio } from "../../domain/entities";
|
|
10
|
+
import type { Scene, Audio } from "../../domain/entities/video-project.types";
|
|
11
11
|
|
|
12
12
|
interface UseEditorScenesParams {
|
|
13
13
|
scenes: Scene[];
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
import { useState, useCallback } from "react";
|
|
8
|
-
import type { ExportSettings, VideoProject } from "../../domain/entities";
|
|
8
|
+
import type { ExportSettings, VideoProject } from "../../domain/entities/video-project.types";
|
|
9
9
|
|
|
10
10
|
export interface ExportProgress {
|
|
11
11
|
status: "preparing" | "encoding" | "saving" | "complete" | "error";
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
import { useCallback } from "react";
|
|
7
7
|
import { ExportDialog } from "../components/ExportDialog";
|
|
8
|
-
import type { VideoProject, ExportSettings } from "../../domain/entities";
|
|
8
|
+
import type { VideoProject, ExportSettings } from "../../domain/entities/video-project.types";
|
|
9
9
|
import type { UseEditorBottomSheetReturn } from "./useEditorBottomSheet";
|
|
10
10
|
|
|
11
11
|
interface UseExportActionsParams {
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import { useState, useCallback, useMemo } from "react";
|
|
7
|
-
import type { ExportSettings, VideoProject } from "../../domain/entities";
|
|
7
|
+
import type { ExportSettings, VideoProject } from "../../domain/entities/video-project.types";
|
|
8
8
|
import type {
|
|
9
9
|
Resolution,
|
|
10
10
|
Quality,
|
|
@@ -7,7 +7,7 @@ import { useCallback } from "react";
|
|
|
7
7
|
import { Alert } from "react-native";
|
|
8
8
|
import { useLocalization } from "@umituz/react-native-settings";
|
|
9
9
|
import { layerOperationsService } from "../../infrastructure/services/layer-operations.service";
|
|
10
|
-
import type { AddImageLayerData, Scene, ImageLayer } from "../../domain/entities";
|
|
10
|
+
import type { AddImageLayerData, Scene, ImageLayer } from "../../domain/entities/video-project.types";
|
|
11
11
|
|
|
12
12
|
interface UseImageLayerOperationsParams {
|
|
13
13
|
scenes: Scene[];
|
|
@@ -9,7 +9,7 @@ import { TextLayerEditor } from "../components/TextLayerEditor";
|
|
|
9
9
|
import { ImageLayerEditor } from "../components/ImageLayerEditor";
|
|
10
10
|
import { ShapeLayerEditor } from "../components/ShapeLayerEditor";
|
|
11
11
|
import { AnimationEditor } from "../components/AnimationEditor";
|
|
12
|
-
import type { Scene,
|
|
12
|
+
import type { Scene, Layer } from "../../domain/entities/video-project.types";
|
|
13
13
|
import type { UseEditorLayersReturn } from "./useEditorLayers";
|
|
14
14
|
import type { UseEditorBottomSheetReturn } from "./useEditorBottomSheet";
|
|
15
15
|
|
|
@@ -91,10 +91,8 @@ export function useLayerActions({
|
|
|
91
91
|
const handleEditImageLayer = useCallback(
|
|
92
92
|
(layerId: string) => {
|
|
93
93
|
if (!currentScene) return;
|
|
94
|
-
const layer = currentScene.layers.find((l: Layer) => l.id === layerId)
|
|
95
|
-
|
|
96
|
-
| undefined;
|
|
97
|
-
if (!layer) return;
|
|
94
|
+
const layer = currentScene.layers.find((l: Layer) => l.id === layerId);
|
|
95
|
+
if (!layer || layer.type !== "image") return;
|
|
98
96
|
|
|
99
97
|
openBottomSheet({
|
|
100
98
|
title: t("editor.layers.image.edit"),
|
|
@@ -7,7 +7,7 @@ import { useCallback } from "react";
|
|
|
7
7
|
import { Alert } from "react-native";
|
|
8
8
|
import { useLocalization } from "@umituz/react-native-settings";
|
|
9
9
|
import { layerOperationsService } from "../../infrastructure/services/layer-operations.service";
|
|
10
|
-
import type { Scene, LayerOrderAction, Animation } from "../../domain/entities";
|
|
10
|
+
import type { Scene, LayerOrderAction, Animation } from "../../domain/entities/video-project.types";
|
|
11
11
|
|
|
12
12
|
interface UseLayerManipulationParams {
|
|
13
13
|
scenes: Scene[];
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
import { useCallback } from "react";
|
|
7
7
|
import { LayerActionsMenu } from "../components/LayerActionsMenu";
|
|
8
|
-
import type { Layer } from "../../domain/entities";
|
|
8
|
+
import type { Layer } from "../../domain/entities/video-project.types";
|
|
9
9
|
import type { UseEditorLayersReturn } from "./useEditorLayers";
|
|
10
10
|
import type { UseEditorBottomSheetReturn } from "./useEditorBottomSheet";
|
|
11
11
|
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
import { useCallback } from "react";
|
|
7
7
|
import { AudioEditor } from "../components/AudioEditor";
|
|
8
8
|
import { SceneActionsMenu } from "../components/SceneActionsMenu";
|
|
9
|
-
import type { Scene } from "../../domain/entities";
|
|
9
|
+
import type { Scene } from "../../domain/entities/video-project.types";
|
|
10
10
|
import type { UseEditorScenesReturn } from "./useEditorScenes";
|
|
11
11
|
import type { UseEditorBottomSheetReturn } from "./useEditorBottomSheet";
|
|
12
12
|
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
import { useState, useCallback } from "react";
|
|
7
7
|
import { useAppDesignTokens } from "@umituz/react-native-design-system/theme";
|
|
8
|
-
import type { ShapeLayer } from "../../domain/entities";
|
|
8
|
+
import type { ShapeLayer } from "../../domain/entities/video-project.types";
|
|
9
9
|
import type { ShapeType } from "../../infrastructure/constants/shape-layer.constants";
|
|
10
10
|
|
|
11
11
|
export interface ShapeLayerFormState {
|
|
@@ -7,7 +7,7 @@ import { useCallback } from "react";
|
|
|
7
7
|
import { Alert } from "react-native";
|
|
8
8
|
import { useLocalization } from "@umituz/react-native-settings";
|
|
9
9
|
import { layerOperationsService } from "../../infrastructure/services/layer-operations.service";
|
|
10
|
-
import type { AddShapeLayerData, Scene } from "../../domain/entities";
|
|
10
|
+
import type { AddShapeLayerData, Scene } from "../../domain/entities/video-project.types";
|
|
11
11
|
|
|
12
12
|
interface UseShapeLayerOperationsParams {
|
|
13
13
|
scenes: Scene[];
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
import { useState, useCallback } from "react";
|
|
7
7
|
import { useAppDesignTokens } from "@umituz/react-native-design-system/theme";
|
|
8
|
-
import type { TextLayer } from "../../domain/entities";
|
|
8
|
+
import type { TextLayer } from "../../domain/entities/video-project.types";
|
|
9
9
|
|
|
10
10
|
export interface TextLayerFormState {
|
|
11
11
|
text: string;
|
|
@@ -7,7 +7,7 @@ import { useCallback } from "react";
|
|
|
7
7
|
import { Alert } from "react-native";
|
|
8
8
|
import { useLocalization } from "@umituz/react-native-settings";
|
|
9
9
|
import { layerOperationsService } from "../../infrastructure/services/layer-operations.service";
|
|
10
|
-
import type { AddTextLayerData, Scene, TextLayer } from "../../domain/entities";
|
|
10
|
+
import type { AddTextLayerData, Scene, TextLayer } from "../../domain/entities/video-project.types";
|
|
11
11
|
|
|
12
12
|
interface UseTextLayerOperationsParams {
|
|
13
13
|
scenes: Scene[];
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Editor Domain Types
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
export * from "./video-project.types";
|
|
6
|
-
|
|
7
|
-
import type { VideoProject, Scene } from "./video-project.types";
|
|
8
|
-
|
|
9
|
-
export interface EditorState {
|
|
10
|
-
project: VideoProject | null;
|
|
11
|
-
currentSceneIndex: number;
|
|
12
|
-
selectedLayerId: string | null;
|
|
13
|
-
isPlaying: boolean;
|
|
14
|
-
currentTime: number;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export interface LayerOperationResult {
|
|
18
|
-
success: boolean;
|
|
19
|
-
updatedScenes: Scene[];
|
|
20
|
-
error?: string;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export interface SceneOperationResult {
|
|
24
|
-
success: boolean;
|
|
25
|
-
updatedScenes: Scene[];
|
|
26
|
-
newSceneIndex?: number;
|
|
27
|
-
error?: string;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
export type LayerOrderAction = "front" | "back" | "up" | "down";
|
|
31
|
-
|
|
32
|
-
export interface AddTextLayerData {
|
|
33
|
-
content?: string;
|
|
34
|
-
fontSize?: number;
|
|
35
|
-
fontFamily?: string;
|
|
36
|
-
fontWeight?: string;
|
|
37
|
-
color?: string;
|
|
38
|
-
textAlign?: "left" | "center" | "right";
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
export interface AddImageLayerData {
|
|
42
|
-
uri?: string;
|
|
43
|
-
opacity?: number;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
export interface AddShapeLayerData {
|
|
47
|
-
shape?: string;
|
|
48
|
-
opacity?: number;
|
|
49
|
-
fillColor?: string;
|
|
50
|
-
borderColor?: string;
|
|
51
|
-
borderWidth?: number;
|
|
52
|
-
}
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Editor Constants
|
|
3
|
-
* Barrel file for editor constants
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
export * from "./text-layer.constants";
|
|
7
|
-
export * from "./audio-layer.constants";
|
|
8
|
-
export * from "./shape-layer.constants";
|
|
9
|
-
export * from "./animation-layer.constants";
|
|
10
|
-
export * from "./image-layer.constants";
|
|
11
|
-
export * from "./export.constants";
|
|
12
|
-
export * from "./filter.constants";
|
|
13
|
-
export * from "./speed.constants";
|
|
14
|
-
export * from "./collage.constants";
|
|
15
|
-
export * from "./subtitle.constants";
|