@umituz/react-native-video-editor 1.0.1 → 1.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/package.json +6 -1
  2. package/src/domain/entities/index.ts +5 -3
  3. package/src/domain/entities/video-project.types.ts +1 -1
  4. package/src/index.ts +25 -1
  5. package/src/infrastructure/constants/animation-layer.constants.ts +1 -1
  6. package/src/infrastructure/services/image-layer-operations.service.ts +1 -1
  7. package/src/infrastructure/services/layer-manipulation.service.ts +1 -1
  8. package/src/infrastructure/services/layer-operations/layer-delete.service.ts +1 -1
  9. package/src/infrastructure/services/layer-operations/layer-duplicate.service.ts +1 -1
  10. package/src/infrastructure/services/layer-operations/layer-order.service.ts +1 -1
  11. package/src/infrastructure/services/layer-operations/layer-transform.service.ts +1 -1
  12. package/src/infrastructure/services/layer-operations.service.ts +1 -1
  13. package/src/infrastructure/services/scene-operations.service.ts +1 -1
  14. package/src/infrastructure/services/shape-layer-operations.service.ts +1 -1
  15. package/src/infrastructure/services/text-layer-operations.service.ts +1 -1
  16. package/src/player/index.ts +31 -0
  17. package/src/player/infrastructure/services/player-control.service.ts +95 -0
  18. package/src/player/presentation/components/VideoPlayer.tsx +135 -0
  19. package/src/player/presentation/hooks/useVideoPlayerControl.ts +82 -0
  20. package/src/player/presentation/hooks/useVideoVisibility.ts +62 -0
  21. package/src/player/types/index.ts +74 -0
  22. package/src/presentation/components/AnimationEditor.tsx +1 -1
  23. package/src/presentation/components/AudioEditor.tsx +1 -1
  24. package/src/presentation/components/DraggableLayer.tsx +1 -1
  25. package/src/presentation/components/EditorPreviewArea.tsx +1 -1
  26. package/src/presentation/components/EditorTimeline.tsx +1 -1
  27. package/src/presentation/components/EditorToolPanel.tsx +1 -1
  28. package/src/presentation/components/ExportDialog.tsx +1 -1
  29. package/src/presentation/components/ImageLayerEditor.tsx +1 -1
  30. package/src/presentation/components/LayerActionsMenu.tsx +1 -1
  31. package/src/presentation/components/ShapeLayerEditor.tsx +1 -1
  32. package/src/presentation/components/TextLayerEditor.tsx +1 -1
  33. package/src/presentation/components/animation-layer/AnimationTypeSelector.tsx +1 -1
  34. package/src/presentation/components/draggable-layer/LayerContent.tsx +1 -1
  35. package/src/presentation/components/export/ExportActions.tsx +2 -2
  36. package/src/presentation/components/export/ExportProgress.tsx +1 -1
  37. package/src/presentation/components/export/ProjectInfoBox.tsx +1 -1
  38. package/src/presentation/hooks/useAnimationLayerForm.ts +1 -1
  39. package/src/presentation/hooks/useAudioLayerForm.ts +1 -1
  40. package/src/presentation/hooks/useEditorActions.tsx +1 -1
  41. package/src/presentation/hooks/useEditorHistory.ts +1 -1
  42. package/src/presentation/hooks/useEditorLayers.ts +1 -1
  43. package/src/presentation/hooks/useEditorPlayback.ts +1 -1
  44. package/src/presentation/hooks/useEditorScenes.ts +1 -1
  45. package/src/presentation/hooks/useExport.ts +34 -19
  46. package/src/presentation/hooks/useExportActions.tsx +1 -1
  47. package/src/presentation/hooks/useExportForm.ts +1 -1
  48. package/src/presentation/hooks/useImageLayerForm.ts +1 -1
  49. package/src/presentation/hooks/useImageLayerOperations.ts +1 -1
  50. package/src/presentation/hooks/useLayerActions.tsx +1 -1
  51. package/src/presentation/hooks/useLayerManipulation.ts +1 -1
  52. package/src/presentation/hooks/useShapeLayerForm.ts +1 -1
  53. package/src/presentation/hooks/useTextLayerForm.ts +1 -1
  54. package/src/presentation/hooks/useTextLayerOperations.ts +1 -1
  55. package/src/infrastructure/services/export-orchestrator.service.ts +0 -122
@@ -0,0 +1,74 @@
1
+ /**
2
+ * Video Player Types
3
+ * Core type definitions for video playback functionality
4
+ */
5
+
6
+ import type { VideoPlayer } from "expo-video";
7
+ import type { ViewStyle } from "react-native";
8
+
9
+ /**
10
+ * Configuration for video player initialization
11
+ */
12
+ export interface VideoPlayerConfig {
13
+ readonly source: string | null;
14
+ readonly loop?: boolean;
15
+ readonly muted?: boolean;
16
+ readonly autoPlay?: boolean;
17
+ }
18
+
19
+ /**
20
+ * Current state of the video player
21
+ */
22
+ export interface VideoPlayerState {
23
+ readonly isPlaying: boolean;
24
+ readonly isPlayerValid: boolean;
25
+ readonly isLoading: boolean;
26
+ }
27
+
28
+ /**
29
+ * Video player control actions
30
+ */
31
+ export interface VideoPlayerControls {
32
+ readonly play: () => void;
33
+ readonly pause: () => void;
34
+ readonly toggle: () => void;
35
+ }
36
+
37
+ /**
38
+ * Combined hook return type
39
+ */
40
+ export interface UseVideoPlayerControlResult {
41
+ readonly player: VideoPlayer | null;
42
+ readonly state: VideoPlayerState;
43
+ readonly controls: VideoPlayerControls;
44
+ }
45
+
46
+ /**
47
+ * Visibility hook configuration
48
+ */
49
+ export interface VideoVisibilityConfig {
50
+ readonly isVisible: boolean;
51
+ readonly player: VideoPlayer | null;
52
+ readonly isPlayerValid: boolean;
53
+ readonly onPlayingChange?: (isPlaying: boolean) => void;
54
+ }
55
+
56
+ /**
57
+ * Video player component props
58
+ */
59
+ export interface VideoPlayerProps {
60
+ readonly source: string | null;
61
+ readonly isVisible?: boolean;
62
+ readonly loop?: boolean;
63
+ readonly muted?: boolean;
64
+ readonly autoPlay?: boolean;
65
+ readonly showControls?: boolean;
66
+ readonly nativeControls?: boolean;
67
+ readonly onPlayingChange?: (isPlaying: boolean) => void;
68
+ readonly onError?: (error: Error) => void;
69
+ readonly style?: ViewStyle;
70
+ readonly contentFit?: "contain" | "cover" | "fill";
71
+ readonly thumbnailUrl?: string;
72
+ }
73
+
74
+ export type { VideoPlayer } from "expo-video";
@@ -6,7 +6,7 @@
6
6
  import React from "react";
7
7
  import { View, ScrollView, StyleSheet } from "react-native";
8
8
  import { useAppDesignTokens } from "@umituz/react-native-design-system";
9
- import type { Animation } from "@domains/video";
9
+ import type { Animation } from "../../../domain/entities";
10
10
  import { useAnimationLayerForm } from "../../hooks/useAnimationLayerForm";
11
11
  import {
12
12
  DURATIONS,
@@ -10,7 +10,7 @@ import {
10
10
  AtomicText,
11
11
  useAppDesignTokens,
12
12
  } from "@umituz/react-native-design-system";
13
- import type { Audio } from "@domains/video";
13
+ import type { Audio } from "../../../domain/entities";
14
14
  import { useAudioLayerForm } from "../../hooks/useAudioLayerForm";
15
15
  import { AUDIO_FILE_TYPES } from "../../constants/audio-layer.constants";
16
16
  import {
@@ -8,7 +8,7 @@ import { StyleSheet } from "react-native";
8
8
  import { GestureDetector } from "react-native-gesture-handler";
9
9
  import Animated, { useAnimatedStyle } from "react-native-reanimated";
10
10
  import { useAppDesignTokens } from "@umituz/react-native-design-system";
11
- import type { Layer } from "@domains/video";
11
+ import type { Layer } from "../../../domain/entities";
12
12
  import { useDraggableLayerGestures } from "../../hooks/useDraggableLayerGestures";
13
13
  import { LayerContent } from "./draggable-layer/LayerContent";
14
14
  import { ResizeHandles } from "./draggable-layer/ResizeHandles";
@@ -11,7 +11,7 @@ import {
11
11
  useAppDesignTokens,
12
12
  } from "@umituz/react-native-design-system";
13
13
  import { DraggableLayer } from "./DraggableLayer";
14
- import type { Scene, Layer, ImageLayer } from "@domains/video";
14
+ import type { Scene, Layer, ImageLayer } from "../../../domain/entities";
15
15
 
16
16
  const { width } = Dimensions.get("window");
17
17
  const PREVIEW_ASPECT_RATIO = 16 / 9;
@@ -11,7 +11,7 @@ import {
11
11
  useAppDesignTokens,
12
12
  } from "@umituz/react-native-design-system";
13
13
  import { useLocalization } from "@umituz/react-native-localization";
14
- import type { VideoProject, Scene } from "@domains/video";
14
+ import type { VideoProject, Scene } from "../../../domain/entities";
15
15
 
16
16
  export interface EditorTimelineProps {
17
17
  project: VideoProject;
@@ -17,7 +17,7 @@ import {
17
17
  useAppDesignTokens,
18
18
  } from "@umituz/react-native-design-system";
19
19
  import { useLocalization } from "@umituz/react-native-localization";
20
- import type { Audio } from "@domains/video";
20
+ import type { Audio } from "../../../domain/entities";
21
21
 
22
22
  export interface EditorToolPanelProps {
23
23
  onAddText: () => void;
@@ -6,7 +6,7 @@
6
6
  import React, { useCallback } from "react";
7
7
  import { View, ScrollView, StyleSheet } from "react-native";
8
8
  import { useLocalization } from "@umituz/react-native-localization";
9
- import type { ExportSettings, VideoProject } from "@domains/video";
9
+ import type { ExportSettings, VideoProject } from "../../../domain/entities";
10
10
  import { useExportForm } from "../../hooks/useExportForm";
11
11
  import { useExport } from "../../hooks/useExport";
12
12
  import {
@@ -6,7 +6,7 @@
6
6
  import React, { useCallback } from "react";
7
7
  import { View, ScrollView, StyleSheet, Alert } from "react-native";
8
8
  import { useImagePicker } from "@/domains/media";
9
- import type { ImageLayer } from "@domains/video";
9
+ import type { ImageLayer } from "../../../domain/entities";
10
10
  import { useImageLayerForm } from "../../hooks/useImageLayerForm";
11
11
  import { IMAGE_PICKER_OPTIONS } from "../../constants/image-layer.constants";
12
12
  import {
@@ -10,7 +10,7 @@ import {
10
10
  AtomicIcon,
11
11
  useAppDesignTokens,
12
12
  } from "@umituz/react-native-design-system";
13
- import type { Layer, ImageLayer } from "@domains/video";
13
+ import type { Layer, ImageLayer } from "../../../domain/entities";
14
14
 
15
15
  export interface LayerActionsMenuProps {
16
16
  layer: Layer;
@@ -10,7 +10,7 @@ import {
10
10
  AtomicIcon,
11
11
  useAppDesignTokens,
12
12
  } from "@umituz/react-native-design-system";
13
- import type { ShapeLayer } from "@domains/video";
13
+ import type { ShapeLayer } from "../../../domain/entities";
14
14
  import { useShapeLayerForm } from "../../hooks/useShapeLayerForm";
15
15
  import {
16
16
  BORDER_WIDTHS,
@@ -6,7 +6,7 @@
6
6
  import React from "react";
7
7
  import { View, ScrollView, StyleSheet } from "react-native";
8
8
  import { useLocalization } from "@umituz/react-native-localization";
9
- import type { TextLayer } from "@domains/video";
9
+ import type { TextLayer } from "../../../domain/entities";
10
10
  import { useTextLayerForm } from "../../hooks/useTextLayerForm";
11
11
  import {
12
12
  FONT_FAMILIES,
@@ -11,7 +11,7 @@ import {
11
11
  useAppDesignTokens,
12
12
  } from "@umituz/react-native-design-system";
13
13
  import { ANIMATION_TYPES } from "../../../constants/animation-layer.constants";
14
- import type { AnimationType } from "@domains/video";
14
+ import type { AnimationType } from "../../../domain/entities";
15
15
 
16
16
  interface AnimationTypeSelectorProps {
17
17
  selectedType: AnimationType;
@@ -9,7 +9,7 @@ import {
9
9
  AtomicIcon,
10
10
  useAppDesignTokens,
11
11
  } from "@umituz/react-native-design-system";
12
- import type { Layer, TextLayer, ImageLayer, ShapeLayer } from "@domains/video";
12
+ import type { Layer, TextLayer, ImageLayer, ShapeLayer } from "../../../domain/entities";
13
13
 
14
14
  interface LayerContentProps {
15
15
  layer: Layer;
@@ -8,11 +8,11 @@ import {
8
8
  View,
9
9
  StyleSheet,
10
10
  TouchableOpacity,
11
- ActivityIndicator,
12
11
  } from "react-native";
13
12
  import {
14
13
  AtomicText,
15
14
  AtomicIcon,
15
+ AtomicSpinner,
16
16
  useAppDesignTokens,
17
17
  } from "@umituz/react-native-design-system";
18
18
 
@@ -64,7 +64,7 @@ export const ExportActions: React.FC<ExportActionsProps> = ({
64
64
  disabled={isExporting}
65
65
  >
66
66
  {isExporting ? (
67
- <ActivityIndicator color="#FFFFFF" size="small" />
67
+ <AtomicSpinner size="sm" color="white" />
68
68
  ) : (
69
69
  <AtomicIcon name="Download" size="sm" color="onSurface" />
70
70
  )}
@@ -9,7 +9,7 @@ import {
9
9
  AtomicText,
10
10
  useAppDesignTokens,
11
11
  } from "@umituz/react-native-design-system";
12
- import type { ExportProgress as ExportProgressType } from "@domains/video/infrastructure/services/video-export.service";
12
+ import type { ExportProgress as ExportProgressType } from "../../hooks/useExport";
13
13
 
14
14
  interface ExportProgressProps {
15
15
  progress: ExportProgressType;
@@ -10,7 +10,7 @@ import {
10
10
  AtomicIcon,
11
11
  useAppDesignTokens,
12
12
  } from "@umituz/react-native-design-system";
13
- import type { VideoProject } from "@domains/video";
13
+ import type { VideoProject } from "../../../domain/entities";
14
14
 
15
15
  interface ProjectInfoBoxProps {
16
16
  project: VideoProject;
@@ -4,7 +4,7 @@
4
4
  */
5
5
 
6
6
  import { useState, useCallback } from "react";
7
- import type { Animation, AnimationType } from "@domains/video";
7
+ import type { Animation, AnimationType } from "../../../domain/entities";
8
8
  import type { Easing } from "../constants/animation-layer.constants";
9
9
 
10
10
  export interface AnimationLayerFormState {
@@ -4,7 +4,7 @@
4
4
  */
5
5
 
6
6
  import { useState, useCallback } from "react";
7
- import type { Audio } from "@domains/video";
7
+ import type { Audio } from "../../../domain/entities";
8
8
 
9
9
  export interface AudioLayerFormState {
10
10
  audioUri: string;
@@ -3,7 +3,7 @@
3
3
  * Single Responsibility: Compose editor action handlers
4
4
  */
5
5
 
6
- import type { VideoProject } from "@domains/video";
6
+ import type { VideoProject } from "../../../domain/entities";
7
7
  import type { UseEditorLayersReturn } from "./useEditorLayers";
8
8
  import type { UseEditorScenesReturn } from "./useEditorScenes";
9
9
  import type { UseEditorBottomSheetReturn } from "./useEditorBottomSheet";
@@ -15,7 +15,7 @@ const useHistoryStore = () => ({
15
15
  canUndo: () => false,
16
16
  canRedo: () => false,
17
17
  });
18
- import type { VideoProject } from "@domains/video";
18
+ import type { VideoProject } from "../../../domain/entities";
19
19
 
20
20
  export interface UseEditorHistoryParams {
21
21
  project: VideoProject | undefined;
@@ -13,7 +13,7 @@ import type {
13
13
  AddShapeLayerData,
14
14
  LayerOrderAction,
15
15
  } from "../types";
16
- import type { TextLayer, ImageLayer, Animation } from "@domains/video";
16
+ import type { TextLayer, ImageLayer, Animation } from "../../../domain/entities";
17
17
 
18
18
  export interface UseEditorLayersParams {
19
19
  projectId: string;
@@ -4,7 +4,7 @@
4
4
  */
5
5
 
6
6
  import { useState, useEffect, useCallback } from "react";
7
- import type { Scene } from "@domains/video";
7
+ import type { Scene } from "../../../domain/entities";
8
8
 
9
9
  export interface UseEditorPlaybackParams {
10
10
  currentScene: Scene | undefined;
@@ -6,7 +6,7 @@
6
6
  import { useCallback } from "react";
7
7
  import { Alert } from "react-native";
8
8
  import { sceneOperationsService } from "../infrastructure/services/scene-operations.service";
9
- import type { Audio } from "@domains/video";
9
+ import type { Audio } from "../../../domain/entities";
10
10
 
11
11
  export interface UseEditorScenesParams {
12
12
  scenes: any[];
@@ -1,12 +1,34 @@
1
1
  /**
2
2
  * useExport Hook
3
3
  * Manages export state and operations
4
+ * Package-driven: Export function is injected from app
4
5
  */
5
6
 
6
- import { useState, useCallback, useEffect } from "react";
7
- import type { ExportSettings, VideoProject } from "@domains/video";
8
- import type { ExportProgress } from "@domains/video/infrastructure/services/video-export.service";
9
- import { exportOrchestratorService } from "../infrastructure/services/export-orchestrator.service";
7
+ import { useState, useCallback } from "react";
8
+ import type { ExportSettings, VideoProject } from "../../domain/entities";
9
+
10
+ export interface ExportProgress {
11
+ status: "preparing" | "encoding" | "saving" | "complete" | "error";
12
+ phase: string;
13
+ progress: number;
14
+ message?: string;
15
+ currentFrame?: number;
16
+ totalFrames?: number;
17
+ }
18
+
19
+ export interface ExportResult {
20
+ success: boolean;
21
+ uri?: string;
22
+ error?: string;
23
+ }
24
+
25
+ export interface UseExportConfig {
26
+ exportFunction: (
27
+ project: VideoProject,
28
+ settings: ExportSettings,
29
+ onProgress: (progress: ExportProgress) => void,
30
+ ) => Promise<ExportResult>;
31
+ }
10
32
 
11
33
  export interface UseExportReturn {
12
34
  isExporting: boolean;
@@ -14,43 +36,36 @@ export interface UseExportReturn {
14
36
  exportVideo: (
15
37
  project: VideoProject,
16
38
  settings: ExportSettings,
17
- ) => Promise<{ success: boolean; uri?: string; error?: string }>;
39
+ ) => Promise<ExportResult>;
18
40
  resetExport: () => void;
19
41
  }
20
42
 
21
43
  /**
22
44
  * Hook for managing export operations
45
+ * @param config - Configuration with export function injected from app
23
46
  */
24
- export function useExport(): UseExportReturn {
47
+ export function useExport(config: UseExportConfig): UseExportReturn {
25
48
  const [isExporting, setIsExporting] = useState(false);
26
49
  const [exportProgress, setExportProgress] = useState<ExportProgress | null>(
27
50
  null,
28
51
  );
29
52
 
30
- useEffect(() => {
31
- exportOrchestratorService.requestNotificationPermissions();
32
- }, []);
33
-
34
53
  const exportVideo = useCallback(
35
54
  async (
36
55
  project: VideoProject,
37
56
  settings: ExportSettings,
38
- ): Promise<{ success: boolean; uri?: string; error?: string }> => {
57
+ ): Promise<ExportResult> => {
39
58
  setIsExporting(true);
40
59
  setExportProgress(null);
41
60
 
42
- const result = await exportOrchestratorService.exportVideo(
43
- project,
44
- settings,
45
- (progress) => {
46
- setExportProgress(progress);
47
- },
48
- );
61
+ const result = await config.exportFunction(project, settings, (progress) => {
62
+ setExportProgress(progress);
63
+ });
49
64
 
50
65
  setIsExporting(false);
51
66
  return result;
52
67
  },
53
- [],
68
+ [config],
54
69
  );
55
70
 
56
71
  const resetExport = useCallback(() => {
@@ -5,7 +5,7 @@
5
5
 
6
6
  import { useCallback } from "react";
7
7
  import { ExportDialog } from "../presentation/components/ExportDialog";
8
- import type { VideoProject, ExportSettings } from "@domains/video";
8
+ import type { VideoProject, ExportSettings } from "../../../domain/entities";
9
9
  import type { UseEditorBottomSheetReturn } from "./useEditorBottomSheet";
10
10
 
11
11
  export interface UseExportActionsParams {
@@ -4,7 +4,7 @@
4
4
  */
5
5
 
6
6
  import { useState, useCallback, useMemo } from "react";
7
- import type { ExportSettings, VideoProject } from "@domains/video";
7
+ import type { ExportSettings, VideoProject } from "../../../domain/entities";
8
8
  import type {
9
9
  Resolution,
10
10
  Quality,
@@ -4,7 +4,7 @@
4
4
  */
5
5
 
6
6
  import { useState, useCallback } from "react";
7
- import type { ImageLayer } from "@domains/video";
7
+ import type { ImageLayer } from "../../../domain/entities";
8
8
 
9
9
  export interface ImageLayerFormState {
10
10
  imageUri: string;
@@ -7,7 +7,7 @@ import { useCallback } from "react";
7
7
  import { Alert } from "react-native";
8
8
  import { layerOperationsService } from "../infrastructure/services/layer-operations.service";
9
9
  import type { AddImageLayerData } from "../types";
10
- import type { ImageLayer } from "@domains/video";
10
+ import type { ImageLayer } from "../../../domain/entities";
11
11
 
12
12
  export interface UseImageLayerOperationsParams {
13
13
  scenes: any[];
@@ -8,7 +8,7 @@ import { TextLayerEditor } from "../presentation/components/TextLayerEditor";
8
8
  import { ImageLayerEditor } from "../presentation/components/ImageLayerEditor";
9
9
  import { ShapeLayerEditor } from "../presentation/components/ShapeLayerEditor";
10
10
  import { AnimationEditor } from "../presentation/components/AnimationEditor";
11
- import type { ImageLayer } from "@domains/video";
11
+ import type { ImageLayer } from "../../../domain/entities";
12
12
  import type { UseEditorLayersReturn } from "./useEditorLayers";
13
13
  import type { UseEditorBottomSheetReturn } from "./useEditorBottomSheet";
14
14
 
@@ -7,7 +7,7 @@ import { useCallback } from "react";
7
7
  import { Alert } from "react-native";
8
8
  import { layerOperationsService } from "../infrastructure/services/layer-operations.service";
9
9
  import type { LayerOrderAction } from "../types";
10
- import type { Animation } from "@domains/video";
10
+ import type { Animation } from "../../../domain/entities";
11
11
 
12
12
  export interface UseLayerManipulationParams {
13
13
  scenes: any[];
@@ -5,7 +5,7 @@
5
5
 
6
6
  import { useState, useCallback } from "react";
7
7
  import { useAppDesignTokens } from "@umituz/react-native-design-system";
8
- import type { ShapeLayer } from "@domains/video";
8
+ import type { ShapeLayer } from "../../../domain/entities";
9
9
  import type { ShapeType } from "../constants/shape-layer.constants";
10
10
 
11
11
  export interface ShapeLayerFormState {
@@ -5,7 +5,7 @@
5
5
 
6
6
  import { useState, useCallback } from "react";
7
7
  import { useAppDesignTokens } from "@umituz/react-native-design-system";
8
- import type { TextLayer } from "@domains/video";
8
+ import type { TextLayer } from "../../../domain/entities";
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 { layerOperationsService } from "../infrastructure/services/layer-operations.service";
9
9
  import type { AddTextLayerData } from "../types";
10
- import type { TextLayer } from "@domains/video";
10
+ import type { TextLayer } from "../../../domain/entities";
11
11
 
12
12
  export interface UseTextLayerOperationsParams {
13
13
  scenes: any[];
@@ -1,122 +0,0 @@
1
- /**
2
- * Export Orchestrator Service
3
- * Handles export business logic and notifications
4
- */
5
-
6
- import * as Device from "expo-device";
7
- import { Alert } from "react-native";
8
- import { notificationService } from "@umituz/react-native-notifications";
9
- import {
10
- videoExportService,
11
- ExportProgress,
12
- } from "@domains/video/infrastructure/services/video-export.service";
13
- import type { ExportSettings, VideoProject } from "@domains/video";
14
-
15
- export interface ExportResult {
16
- success: boolean;
17
- uri?: string;
18
- error?: string;
19
- }
20
-
21
- export interface ExportOrchestratorService {
22
- exportVideo: (
23
- project: VideoProject,
24
- settings: ExportSettings,
25
- onProgress: (progress: ExportProgress) => void,
26
- ) => Promise<ExportResult>;
27
- requestNotificationPermissions: () => Promise<void>;
28
- }
29
-
30
- class ExportOrchestratorServiceImpl implements ExportOrchestratorService {
31
- async requestNotificationPermissions(): Promise<void> {
32
- if (Device.isDevice) {
33
- await notificationService.requestPermissions();
34
- }
35
- }
36
-
37
- async exportVideo(
38
- project: VideoProject,
39
- settings: ExportSettings,
40
- onProgress: (progress: ExportProgress) => void,
41
- ): Promise<ExportResult> {
42
- const projectToExport: VideoProject = {
43
- ...project,
44
- exportSettings: settings,
45
- };
46
-
47
- try {
48
- const result = await videoExportService.exportVideo(
49
- projectToExport,
50
- onProgress,
51
- );
52
-
53
- if (result.success) {
54
- await this.showSuccessNotification(project.title, result.uri);
55
- this.showSuccessAlert();
56
- return { success: true, uri: result.uri };
57
- } else {
58
- await this.showFailureNotification(project.title, result.error);
59
- this.showFailureAlert(result.error);
60
- return { success: false, error: result.error };
61
- }
62
- } catch (error) {
63
- await this.showFailureNotification(
64
- project.title,
65
- "An unexpected error occurred",
66
- );
67
- this.showFailureAlert("An unexpected error occurred");
68
- return {
69
- success: false,
70
- error: error instanceof Error ? error.message : "Unknown error",
71
- };
72
- }
73
- }
74
-
75
- private async showSuccessNotification(
76
- projectTitle: string,
77
- uri?: string,
78
- ): Promise<void> {
79
- if (!Device.isDevice) return;
80
-
81
- try {
82
- await notificationService.notifications.scheduleNotification({
83
- title: "Export Complete",
84
- body: `${projectTitle} has been exported successfully!`,
85
- trigger: { type: "date", date: new Date() },
86
- data: { uri: uri || "" },
87
- });
88
- } catch (error) {
89
- // Silent failure - notification is optional
90
- }
91
- }
92
-
93
- private async showFailureNotification(
94
- projectTitle: string,
95
- error?: string,
96
- ): Promise<void> {
97
- if (!Device.isDevice) return;
98
-
99
- try {
100
- await notificationService.notifications.scheduleNotification({
101
- title: "Export Failed",
102
- body: `Failed to export ${projectTitle}: ${error || "Unknown error"}`,
103
- trigger: { type: "date", date: new Date() },
104
- });
105
- } catch (error) {
106
- // Silent failure - notification is optional
107
- }
108
- }
109
-
110
- private showSuccessAlert(): void {
111
- Alert.alert(
112
- "Export Complete",
113
- "Your video has been exported successfully!",
114
- );
115
- }
116
-
117
- private showFailureAlert(error?: string): void {
118
- Alert.alert("Export Failed", error || "An error occurred during export");
119
- }
120
- }
121
-
122
- export const exportOrchestratorService = new ExportOrchestratorServiceImpl();