@umituz/react-native-ai-generation-content 1.61.63 → 1.61.65

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 (114) hide show
  1. package/package.json +1 -1
  2. package/src/core/index.ts +1 -1
  3. package/src/domain/entities/index.ts +1 -1
  4. package/src/domain/interfaces/ai-provider.interface.ts +1 -1
  5. package/src/domain/interfaces/index.ts +1 -1
  6. package/src/domains/background/domain/entities/index.ts +1 -0
  7. package/src/domains/background/domain/interfaces/index.ts +1 -0
  8. package/src/{domain → domains/background/domain}/interfaces/provider-job-manager.interface.ts +1 -1
  9. package/src/domains/background/domain/types/background-generation.types.ts +28 -0
  10. package/src/domains/background/infrastructure/executors/backgroundJobExecutor.ts +105 -0
  11. package/src/{infrastructure → domains/background/infrastructure}/services/job-poller-factory.ts +1 -1
  12. package/src/{infrastructure → domains/background/infrastructure}/services/job-poller.service.ts +1 -1
  13. package/src/{infrastructure → domains/background/infrastructure}/services/job-poller.types.ts +2 -2
  14. package/src/{infrastructure → domains/background/infrastructure}/utils/polling-interval.util.ts +1 -1
  15. package/src/{infrastructure → domains/background/infrastructure}/utils/status-checker.util.ts +1 -1
  16. package/src/domains/background/presentation/hooks/use-background-generation.ts +97 -0
  17. package/src/domains/creations/presentation/components/PendingJobsSection.tsx +1 -1
  18. package/src/{features → domains}/image-to-video/domain/constants/index.ts +0 -5
  19. package/src/{features → domains}/image-to-video/domain/types/index.ts +0 -3
  20. package/src/{features → domains}/image-to-video/index.ts +0 -7
  21. package/src/{features → domains}/image-to-video/presentation/components/index.ts +0 -4
  22. package/src/domains/image-to-video/presentation/hooks/imageToVideoStrategy.ts +77 -0
  23. package/src/domains/image-to-video/presentation/hooks/useImageToVideoFeature.ts +102 -0
  24. package/src/domains/scenarios/presentation/containers/CategoryNavigationContainer.tsx +4 -80
  25. package/src/{features → domains}/text-to-image/infrastructure/services/text-to-image-executor.ts +2 -82
  26. package/src/domains/text-to-image/infrastructure/utils/imageResultExtractor.ts +58 -0
  27. package/src/domains/text-to-video/presentation/hooks/textToVideoStrategy.ts +75 -0
  28. package/src/domains/text-to-video/presentation/hooks/useTextToVideoFeature.ts +120 -0
  29. package/src/exports/features.ts +15 -16
  30. package/src/presentation/components/PendingJobCard.tsx +1 -1
  31. package/src/features/image-to-video/domain/constants/music.constants.ts +0 -53
  32. package/src/features/image-to-video/domain/types/music.types.ts +0 -21
  33. package/src/features/image-to-video/presentation/components/MusicMoodSelector.tsx +0 -181
  34. package/src/features/image-to-video/presentation/hooks/useImageToVideoFeature.ts +0 -186
  35. package/src/features/text-to-video/presentation/hooks/useTextToVideoFeature.ts +0 -186
  36. package/src/presentation/hooks/use-background-generation.ts +0 -185
  37. /package/src/{domain → domains/background/domain}/entities/job.types.ts +0 -0
  38. /package/src/{infrastructure → domains/background/infrastructure}/utils/result-validator.util.ts +0 -0
  39. /package/src/{presentation → domains/background/presentation}/hooks/use-pending-jobs.ts +0 -0
  40. /package/src/{features → domains}/image-to-video/README.md +0 -0
  41. /package/src/{features → domains}/image-to-video/domain/constants/animation.constants.ts +0 -0
  42. /package/src/{features → domains}/image-to-video/domain/constants/duration.constants.ts +0 -0
  43. /package/src/{features → domains}/image-to-video/domain/constants/form.constants.ts +0 -0
  44. /package/src/{features → domains}/image-to-video/domain/index.ts +0 -0
  45. /package/src/{features → domains}/image-to-video/domain/types/animation.types.ts +0 -0
  46. /package/src/{features → domains}/image-to-video/domain/types/config.types.ts +0 -0
  47. /package/src/{features → domains}/image-to-video/domain/types/duration.types.ts +0 -0
  48. /package/src/{features → domains}/image-to-video/domain/types/form.types.ts +0 -0
  49. /package/src/{features → domains}/image-to-video/domain/types/image-to-video.types.ts +0 -0
  50. /package/src/{features → domains}/image-to-video/infrastructure/index.ts +0 -0
  51. /package/src/{features → domains}/image-to-video/infrastructure/services/image-to-video-executor.ts +0 -0
  52. /package/src/{features → domains}/image-to-video/infrastructure/services/index.ts +0 -0
  53. /package/src/{features → domains}/image-to-video/presentation/components/AddMoreCard.tsx +0 -0
  54. /package/src/{features → domains}/image-to-video/presentation/components/AnimationStyleSelector.tsx +0 -0
  55. /package/src/{features → domains}/image-to-video/presentation/components/DurationSelector.tsx +0 -0
  56. /package/src/{features → domains}/image-to-video/presentation/components/EmptyGridState.tsx +0 -0
  57. /package/src/{features → domains}/image-to-video/presentation/components/GridImageItem.tsx +0 -0
  58. /package/src/{features → domains}/image-to-video/presentation/components/ImageSelectionGrid.styles.ts +0 -0
  59. /package/src/{features → domains}/image-to-video/presentation/components/ImageSelectionGrid.tsx +0 -0
  60. /package/src/{features → domains}/image-to-video/presentation/components/ImageSelectionGrid.types.ts +0 -0
  61. /package/src/{features → domains}/image-to-video/presentation/hooks/image-to-video-feature.types.ts +0 -0
  62. /package/src/{features → domains}/image-to-video/presentation/hooks/index.ts +0 -0
  63. /package/src/{features → domains}/image-to-video/presentation/hooks/useFormState.ts +0 -0
  64. /package/src/{features → domains}/image-to-video/presentation/hooks/useGeneration.ts +0 -0
  65. /package/src/{features → domains}/image-to-video/presentation/hooks/useImageToVideoForm.ts +0 -0
  66. /package/src/{features → domains}/image-to-video/presentation/index.ts +0 -0
  67. /package/src/{features → domains}/image-to-video/presentation/screens/ImageToVideoWizardFlow.tsx +0 -0
  68. /package/src/{features → domains}/shared/index.ts +0 -0
  69. /package/src/{features → domains}/shared/presentation/components/AutoSkipPreview.tsx +0 -0
  70. /package/src/{features → domains}/shared/presentation/components/index.ts +0 -0
  71. /package/src/{features → domains}/shared/presentation/utils/index.ts +0 -0
  72. /package/src/{features → domains}/shared/presentation/utils/wizard-flow.utils.ts +0 -0
  73. /package/src/{features → domains}/text-to-image/README.md +0 -0
  74. /package/src/{features → domains}/text-to-image/domain/constants/index.ts +0 -0
  75. /package/src/{features → domains}/text-to-image/domain/constants/options.constants.ts +0 -0
  76. /package/src/{features → domains}/text-to-image/domain/constants/styles.constants.ts +0 -0
  77. /package/src/{features → domains}/text-to-image/domain/index.ts +0 -0
  78. /package/src/{features → domains}/text-to-image/domain/types/config.types.ts +0 -0
  79. /package/src/{features → domains}/text-to-image/domain/types/form.types.ts +0 -0
  80. /package/src/{features → domains}/text-to-image/domain/types/index.ts +0 -0
  81. /package/src/{features → domains}/text-to-image/domain/types/text-to-image.types.ts +0 -0
  82. /package/src/{features → domains}/text-to-image/index.ts +0 -0
  83. /package/src/{features → domains}/text-to-image/infrastructure/index.ts +0 -0
  84. /package/src/{features → domains}/text-to-image/infrastructure/services/index.ts +0 -0
  85. /package/src/{features → domains}/text-to-image/presentation/components/index.ts +0 -0
  86. /package/src/{features → domains}/text-to-image/presentation/hooks/index.ts +0 -0
  87. /package/src/{features → domains}/text-to-image/presentation/hooks/useFormState.ts +0 -0
  88. /package/src/{features → domains}/text-to-image/presentation/hooks/useGeneration.ts +0 -0
  89. /package/src/{features → domains}/text-to-image/presentation/hooks/useTextToImageForm.ts +0 -0
  90. /package/src/{features → domains}/text-to-image/presentation/index.ts +0 -0
  91. /package/src/{features → domains}/text-to-image/presentation/screens/TextToImageWizardFlow.tsx +0 -0
  92. /package/src/{features → domains}/text-to-image/presentation/screens/TextToImageWizardFlow.types.ts +0 -0
  93. /package/src/{features → domains}/text-to-video/README.md +0 -0
  94. /package/src/{features → domains}/text-to-video/domain/index.ts +0 -0
  95. /package/src/{features → domains}/text-to-video/domain/types/callback.types.ts +0 -0
  96. /package/src/{features → domains}/text-to-video/domain/types/component.types.ts +0 -0
  97. /package/src/{features → domains}/text-to-video/domain/types/config.types.ts +0 -0
  98. /package/src/{features → domains}/text-to-video/domain/types/index.ts +0 -0
  99. /package/src/{features → domains}/text-to-video/domain/types/request.types.ts +0 -0
  100. /package/src/{features → domains}/text-to-video/domain/types/state.types.ts +0 -0
  101. /package/src/{features → domains}/text-to-video/index.ts +0 -0
  102. /package/src/{features → domains}/text-to-video/infrastructure/index.ts +0 -0
  103. /package/src/{features → domains}/text-to-video/infrastructure/services/index.ts +0 -0
  104. /package/src/{features → domains}/text-to-video/infrastructure/services/text-to-video-executor.ts +0 -0
  105. /package/src/{features → domains}/text-to-video/presentation/components/FrameSelector.tsx +0 -0
  106. /package/src/{features → domains}/text-to-video/presentation/components/GenerationTabs.tsx +0 -0
  107. /package/src/{features → domains}/text-to-video/presentation/components/HeroSection.tsx +0 -0
  108. /package/src/{features → domains}/text-to-video/presentation/components/HintCarousel.tsx +0 -0
  109. /package/src/{features → domains}/text-to-video/presentation/components/OptionsPanel.tsx +0 -0
  110. /package/src/{features → domains}/text-to-video/presentation/components/index.ts +0 -0
  111. /package/src/{features → domains}/text-to-video/presentation/hooks/index.ts +0 -0
  112. /package/src/{features → domains}/text-to-video/presentation/hooks/useTextToVideoForm.ts +0 -0
  113. /package/src/{features → domains}/text-to-video/presentation/index.ts +0 -0
  114. /package/src/{features → domains}/text-to-video/presentation/screens/TextToVideoWizardFlow.tsx +0 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@umituz/react-native-ai-generation-content",
3
- "version": "1.61.63",
3
+ "version": "1.61.65",
4
4
  "description": "Provider-agnostic AI generation orchestration for React Native with result preview components",
5
5
  "main": "src/index.ts",
6
6
  "types": "src/index.ts",
package/src/core/index.ts CHANGED
@@ -57,7 +57,7 @@ export type {
57
57
  // Segregated provider sub-interfaces
58
58
  export type { IAIProviderLifecycle } from "../domain/interfaces/provider-lifecycle.interface";
59
59
  export type { IAIProviderCapabilities } from "../domain/interfaces/provider-capabilities.interface";
60
- export type { IAIProviderJobManager } from "../domain/interfaces/provider-job-manager.interface";
60
+ export type { IAIProviderJobManager } from "../domains/background/domain/interfaces/provider-job-manager.interface";
61
61
  export type { IAIProviderExecutor } from "../domain/interfaces/provider-executor.interface";
62
62
  export type { IAIProviderImageFeatures } from "../domain/interfaces/provider-image-features.interface";
63
63
  export type { IAIProviderVideoFeatures } from "../domain/interfaces/provider-video-features.interface";
@@ -6,6 +6,6 @@
6
6
  export * from "./error.types";
7
7
  export * from "./generation.types";
8
8
  export * from "./polling.types";
9
- export * from "./job.types";
9
+ export * from "../../domains/background/domain/entities/job.types";
10
10
  export * from "./processing-modes.types";
11
11
  export * from "./flow-config.types";
@@ -155,7 +155,7 @@ export interface VideoFeatureInputData {
155
155
 
156
156
  import type { IAIProviderLifecycle } from "./provider-lifecycle.interface";
157
157
  import type { IAIProviderCapabilities } from "./provider-capabilities.interface";
158
- import type { IAIProviderJobManager } from "./provider-job-manager.interface";
158
+ import type { IAIProviderJobManager } from "../../domains/background/domain/interfaces/provider-job-manager.interface";
159
159
  import type { IAIProviderExecutor } from "./provider-executor.interface";
160
160
  import type { IAIProviderImageFeatures } from "./provider-image-features.interface";
161
161
  import type { IAIProviderVideoFeatures } from "./provider-video-features.interface";
@@ -9,7 +9,7 @@ export * from "./app-services.interface";
9
9
  // Interface Segregation - Split provider interfaces
10
10
  export type { IAIProviderLifecycle } from "./provider-lifecycle.interface";
11
11
  export type { IAIProviderCapabilities } from "./provider-capabilities.interface";
12
- export type { IAIProviderJobManager } from "./provider-job-manager.interface";
12
+ export type { IAIProviderJobManager } from "../../domains/background/domain/interfaces/provider-job-manager.interface";
13
13
  export type { IAIProviderExecutor } from "./provider-executor.interface";
14
14
  export type { IAIProviderImageFeatures } from "./provider-image-features.interface";
15
15
  export type { IAIProviderVideoFeatures } from "./provider-video-features.interface";
@@ -0,0 +1 @@
1
+ export * from "./job.types";
@@ -0,0 +1 @@
1
+ export * from "./provider-job-manager.interface";
@@ -3,7 +3,7 @@
3
3
  * Single Responsibility: Async job submission, status checking, and result retrieval
4
4
  */
5
5
 
6
- import type { JobSubmission, JobStatus } from "./ai-provider.interface";
6
+ import type { JobSubmission, JobStatus } from "../../../../domain/interfaces/ai-provider.interface";
7
7
 
8
8
  export interface IAIProviderJobManager {
9
9
  /**
@@ -0,0 +1,28 @@
1
+ import type {
2
+ BackgroundJob,
3
+ BackgroundQueueConfig,
4
+ JobExecutorConfig,
5
+ } from "../entities/job.types";
6
+ import type { executeDirectGeneration } from "../../infrastructure/executors/backgroundJobExecutor";
7
+
8
+ export type { DirectExecutionResult } from "../../infrastructure/executors/backgroundJobExecutor";
9
+
10
+ export interface UseBackgroundGenerationOptions<TInput, TResult>
11
+ extends Partial<BackgroundQueueConfig> {
12
+ readonly executor: JobExecutorConfig<TInput, TResult>;
13
+ readonly onJobComplete?: (job: BackgroundJob<TInput, TResult>) => void;
14
+ readonly onJobError?: (job: BackgroundJob<TInput, TResult>) => void;
15
+ readonly onAllComplete?: () => void;
16
+ readonly onProgress?: (progress: number) => void;
17
+ }
18
+
19
+ export interface UseBackgroundGenerationReturn<TInput, TResult> {
20
+ readonly startJob: (input: TInput, type: string) => Promise<string>;
21
+ readonly executeDirectly: (input: TInput) => ReturnType<typeof executeDirectGeneration<TInput, TResult>>;
22
+ readonly cancelJob: (id: string) => void;
23
+ readonly pendingJobs: BackgroundJob<TInput, TResult>[];
24
+ readonly activeJobCount: number;
25
+ readonly hasActiveJobs: boolean;
26
+ readonly isProcessing: boolean;
27
+ readonly progress: number;
28
+ }
@@ -0,0 +1,105 @@
1
+ import type { BackgroundJob, JobExecutorConfig } from "../../domain/entities/job.types";
2
+
3
+ export interface DirectExecutionResult<TResult> {
4
+ readonly success: boolean;
5
+ readonly result?: TResult;
6
+ readonly error?: string;
7
+ }
8
+
9
+ interface DirectExecutionParams<TInput, TResult> {
10
+ input: TInput;
11
+ executor: JobExecutorConfig<TInput, TResult>;
12
+ onProgress?: (progress: number) => void;
13
+ setProgress: (progress: number) => void;
14
+ setIsProcessing: (isProcessing: boolean) => void;
15
+ }
16
+
17
+ export const executeDirectGeneration = async <TInput, TResult>(
18
+ params: DirectExecutionParams<TInput, TResult>,
19
+ ): Promise<DirectExecutionResult<TResult>> => {
20
+ const { input, executor, onProgress, setProgress, setIsProcessing } = params;
21
+
22
+ setIsProcessing(true);
23
+ setProgress(0);
24
+
25
+ try {
26
+ const result = await executor.execute(input, (p) => {
27
+ setProgress(p);
28
+ onProgress?.(p);
29
+ });
30
+
31
+ setProgress(100);
32
+ return { success: true, result };
33
+ } catch (error) {
34
+ const errorMsg = error instanceof Error ? error.message : String(error);
35
+ return { success: false, error: errorMsg };
36
+ } finally {
37
+ setIsProcessing(false);
38
+ }
39
+ };
40
+
41
+ interface QueuedExecutionParams<TInput, TResult> {
42
+ jobId: string;
43
+ input: TInput;
44
+ executor: JobExecutorConfig<TInput, TResult>;
45
+ updateJob: (params: { id: string; updates: Partial<BackgroundJob<TInput, TResult>> }) => void;
46
+ removeJob: (id: string) => void;
47
+ getJob: (id: string) => BackgroundJob<TInput, TResult> | undefined;
48
+ activeJobsRef: React.MutableRefObject<Set<string>>;
49
+ onJobComplete?: (job: BackgroundJob<TInput, TResult>) => void;
50
+ onJobError?: (job: BackgroundJob<TInput, TResult>) => void;
51
+ onAllComplete?: () => void;
52
+ }
53
+
54
+ export const executeQueuedJob = async <TInput, TResult>(
55
+ params: QueuedExecutionParams<TInput, TResult>,
56
+ ): Promise<void> => {
57
+ const {
58
+ jobId,
59
+ input,
60
+ executor,
61
+ updateJob,
62
+ removeJob,
63
+ getJob,
64
+ activeJobsRef,
65
+ onJobComplete,
66
+ onJobError,
67
+ onAllComplete,
68
+ } = params;
69
+
70
+ try {
71
+ updateJob({ id: jobId, updates: { status: "processing", progress: 10 } });
72
+
73
+ const result = await executor.execute(input, (p) => {
74
+ updateJob({ id: jobId, updates: { progress: p } });
75
+ });
76
+
77
+ updateJob({
78
+ id: jobId,
79
+ updates: { status: "completed", progress: 100, result, completedAt: new Date() },
80
+ });
81
+
82
+ const completedJob = getJob(jobId);
83
+ if (completedJob) {
84
+ await executor.onComplete?.(completedJob);
85
+ onJobComplete?.(completedJob);
86
+ }
87
+
88
+ removeJob(jobId);
89
+ } catch (error) {
90
+ const errorMsg = error instanceof Error ? error.message : String(error);
91
+
92
+ updateJob({ id: jobId, updates: { status: "failed", error: errorMsg, progress: 0 } });
93
+
94
+ const failedJob = getJob(jobId);
95
+ if (failedJob) {
96
+ await executor.onError?.(failedJob, error instanceof Error ? error : new Error(errorMsg));
97
+ onJobError?.(failedJob);
98
+ }
99
+ } finally {
100
+ activeJobsRef.current.delete(jobId);
101
+ if (activeJobsRef.current.size === 0) {
102
+ onAllComplete?.();
103
+ }
104
+ }
105
+ };
@@ -3,7 +3,7 @@
3
3
  * Creates pre-configured job poller instances
4
4
  */
5
5
 
6
- import type { PollingConfig } from "../../domain/entities";
6
+ import type { PollingConfig } from "../../../../domain/entities/polling.types";
7
7
  import type { PollJobOptions } from "./job-poller.types";
8
8
  import { pollJob } from "./job-poller.service";
9
9
 
@@ -4,7 +4,7 @@
4
4
  * Reports only real status - no fake progress
5
5
  */
6
6
 
7
- import { DEFAULT_POLLING_CONFIG } from "../../domain/entities";
7
+ import { DEFAULT_POLLING_CONFIG } from "../../../../domain/entities/polling.types";
8
8
  import { calculatePollingInterval } from "../utils/polling-interval.util";
9
9
  import { checkStatusForErrors, isJobComplete } from "../utils/status-checker.util";
10
10
  import { validateResult } from "../utils/result-validator.util";
@@ -2,8 +2,8 @@
2
2
  * Job Poller Type Definitions
3
3
  */
4
4
 
5
- import type { IAIProvider, JobStatus } from "../../domain/interfaces";
6
- import type { PollingConfig } from "../../domain/entities";
5
+ import type { IAIProvider, JobStatus } from "../../../../domain/interfaces/ai-provider.interface";
6
+ import type { PollingConfig } from "../../../../domain/entities/polling.types";
7
7
 
8
8
  export interface PollJobOptions {
9
9
  provider: IAIProvider;
@@ -6,7 +6,7 @@
6
6
  import {
7
7
  DEFAULT_POLLING_CONFIG,
8
8
  type PollingConfig,
9
- } from "../../domain/entities";
9
+ } from "../../../../domain/entities/polling.types";
10
10
 
11
11
  export interface IntervalOptions {
12
12
  attempt: number;
@@ -3,7 +3,7 @@
3
3
  * Checks job status responses for errors
4
4
  */
5
5
 
6
- import type { JobStatus, AILogEntry } from "../../domain/interfaces";
6
+ import type { JobStatus, AILogEntry } from "../../../../domain/interfaces/ai-provider.interface";
7
7
 
8
8
  export interface StatusCheckResult {
9
9
  status: string;
@@ -0,0 +1,97 @@
1
+ import { useCallback, useRef, useState } from "react";
2
+ import { usePendingJobs } from "./use-pending-jobs";
3
+ import { executeDirectGeneration, executeQueuedJob } from "../../infrastructure/executors/backgroundJobExecutor";
4
+ import { DEFAULT_QUEUE_CONFIG } from "../../domain/entities/job.types";
5
+ import type {
6
+ UseBackgroundGenerationOptions,
7
+ UseBackgroundGenerationReturn,
8
+ } from "../../domain/types/background-generation.types";
9
+
10
+ export type { DirectExecutionResult, UseBackgroundGenerationOptions, UseBackgroundGenerationReturn } from "../../domain/types/background-generation.types";
11
+
12
+ export function useBackgroundGeneration<TInput = unknown, TResult = unknown>(
13
+ options: UseBackgroundGenerationOptions<TInput, TResult>,
14
+ ): UseBackgroundGenerationReturn<TInput, TResult> {
15
+ const config = { ...DEFAULT_QUEUE_CONFIG, ...options };
16
+ const activeJobsRef = useRef<Set<string>>(new Set());
17
+ const jobInputsRef = useRef<Map<string, { input: TInput; type: string }>>(
18
+ new Map(),
19
+ );
20
+
21
+ const [isProcessing, setIsProcessing] = useState(false);
22
+ const [progress, setProgress] = useState(0);
23
+
24
+ const { jobs, addJobAsync, updateJob, removeJob, getJob } = usePendingJobs<
25
+ TInput,
26
+ TResult
27
+ >({
28
+ queryKey: config.queryKey,
29
+ });
30
+
31
+ const { executor, onProgress, onJobComplete, onJobError, onAllComplete } = options;
32
+
33
+ const executeDirectly = useCallback(
34
+ (input: TInput) =>
35
+ executeDirectGeneration({ input, executor, onProgress, setProgress, setIsProcessing }),
36
+ [executor, onProgress],
37
+ );
38
+
39
+ const executeJob = useCallback(
40
+ (jobId: string, input: TInput) =>
41
+ executeQueuedJob({
42
+ jobId,
43
+ input,
44
+ executor,
45
+ updateJob,
46
+ removeJob,
47
+ getJob,
48
+ activeJobsRef,
49
+ onJobComplete,
50
+ onJobError,
51
+ onAllComplete,
52
+ }),
53
+ [executor, onJobComplete, onJobError, onAllComplete, updateJob, removeJob, getJob],
54
+ );
55
+
56
+ const startJob = useCallback(
57
+ async (input: TInput, type: string): Promise<string> => {
58
+ const jobId = `job-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;
59
+
60
+ jobInputsRef.current.set(jobId, { input, type });
61
+
62
+ await addJobAsync({
63
+ id: jobId,
64
+ input,
65
+ type,
66
+ status: "queued",
67
+ progress: 0,
68
+ });
69
+
70
+ activeJobsRef.current.add(jobId);
71
+ void executeJob(jobId, input);
72
+
73
+ return jobId;
74
+ },
75
+ [addJobAsync, executeJob],
76
+ );
77
+
78
+ const cancelJob = useCallback(
79
+ (id: string) => {
80
+ activeJobsRef.current.delete(id);
81
+ jobInputsRef.current.delete(id);
82
+ removeJob(id);
83
+ },
84
+ [removeJob],
85
+ );
86
+
87
+ return {
88
+ startJob,
89
+ executeDirectly,
90
+ cancelJob,
91
+ pendingJobs: jobs,
92
+ activeJobCount: activeJobsRef.current.size,
93
+ hasActiveJobs: activeJobsRef.current.size > 0,
94
+ isProcessing,
95
+ progress,
96
+ };
97
+ }
@@ -6,7 +6,7 @@
6
6
  import React from "react";
7
7
  import { View, StyleSheet } from "react-native";
8
8
  import { AtomicText, useAppDesignTokens } from "@umituz/react-native-design-system";
9
- import type { BackgroundJob } from "../../../../domain/entities/job.types";
9
+ import type { BackgroundJob } from "../../../background/domain/entities/job.types";
10
10
  import { PendingJobCard } from "../../../../presentation/components/PendingJobCard";
11
11
 
12
12
  export interface PendingJobsSectionProps {
@@ -7,11 +7,6 @@ export {
7
7
  DEFAULT_ANIMATION_STYLE_ID,
8
8
  } from "./animation.constants";
9
9
 
10
- export {
11
- DEFAULT_MUSIC_MOODS,
12
- DEFAULT_MUSIC_MOOD_ID,
13
- } from "./music.constants";
14
-
15
10
  export {
16
11
  DEFAULT_DURATION_OPTIONS,
17
12
  DEFAULT_VIDEO_DURATION,
@@ -1,9 +1,6 @@
1
1
  // Animation Types
2
2
  export type { AnimationStyle, AnimationStyleId } from "./animation.types";
3
3
 
4
- // Music Types
5
- export type { MusicMood, MusicMoodId } from "./music.types";
6
-
7
4
  // Duration Types
8
5
  export type { VideoDuration, DurationOption } from "./duration.types";
9
6
 
@@ -10,9 +10,6 @@
10
10
  // Animation Types
11
11
  export type { AnimationStyle, AnimationStyleId } from "./domain";
12
12
 
13
- // Music Types
14
- export type { MusicMood, MusicMoodId } from "./domain";
15
-
16
13
  // Duration Types
17
14
  export type { VideoDuration, DurationOption } from "./domain";
18
15
 
@@ -54,8 +51,6 @@ export type {
54
51
  export {
55
52
  DEFAULT_ANIMATION_STYLES as IMAGE_TO_VIDEO_ANIMATION_STYLES,
56
53
  DEFAULT_ANIMATION_STYLE_ID as IMAGE_TO_VIDEO_DEFAULT_ANIMATION,
57
- DEFAULT_MUSIC_MOODS as IMAGE_TO_VIDEO_MUSIC_MOODS,
58
- DEFAULT_MUSIC_MOOD_ID as IMAGE_TO_VIDEO_DEFAULT_MUSIC,
59
54
  DEFAULT_DURATION_OPTIONS as IMAGE_TO_VIDEO_DURATION_OPTIONS,
60
55
  DEFAULT_VIDEO_DURATION as IMAGE_TO_VIDEO_DEFAULT_DURATION,
61
56
  DEFAULT_FORM_VALUES as IMAGE_TO_VIDEO_FORM_DEFAULTS,
@@ -101,7 +96,6 @@ export type {
101
96
  export {
102
97
  ImageToVideoAnimationStyleSelector,
103
98
  ImageToVideoDurationSelector,
104
- ImageToVideoMusicMoodSelector,
105
99
  ImageToVideoSelectionGrid,
106
100
  ImageToVideoGenerateButton,
107
101
  } from "./presentation";
@@ -109,7 +103,6 @@ export {
109
103
  export type {
110
104
  ImageToVideoAnimationStyleSelectorProps,
111
105
  ImageToVideoDurationSelectorProps,
112
- ImageToVideoMusicMoodSelectorProps,
113
106
  ImageToVideoSelectionGridProps,
114
107
  ImageToVideoSelectionGridTranslations,
115
108
  ImageToVideoGenerateButtonProps,
@@ -10,10 +10,6 @@ export type { AnimationStyleSelectorProps as ImageToVideoAnimationStyleSelectorP
10
10
  export { DurationSelector as ImageToVideoDurationSelector } from "./DurationSelector";
11
11
  export type { DurationSelectorProps as ImageToVideoDurationSelectorProps } from "./DurationSelector";
12
12
 
13
- // Music Mood Selector
14
- export { MusicMoodSelector as ImageToVideoMusicMoodSelector } from "./MusicMoodSelector";
15
- export type { MusicMoodSelectorProps as ImageToVideoMusicMoodSelectorProps } from "./MusicMoodSelector";
16
-
17
13
  // Image Selection Grid
18
14
  export { ImageSelectionGrid as ImageToVideoSelectionGrid } from "./ImageSelectionGrid";
19
15
  export type {
@@ -0,0 +1,77 @@
1
+ import { executeImageToVideo } from "../../infrastructure/services";
2
+ import type { GenerationStrategy } from "../../../../presentation/hooks/generation";
3
+ import type {
4
+ ImageToVideoConfig,
5
+ ImageToVideoCallbacks,
6
+ ImageToVideoResult,
7
+ ImageToVideoOptions,
8
+ ImageToVideoInputBuilder,
9
+ ImageToVideoResultExtractor,
10
+ } from "../../domain/types";
11
+
12
+ interface VideoGenerationInput {
13
+ imageUrl: string;
14
+ prompt: string;
15
+ options?: ImageToVideoOptions;
16
+ creationId: string;
17
+ }
18
+
19
+ interface CreateStrategyParams {
20
+ config: ImageToVideoConfig;
21
+ callbacks: ImageToVideoCallbacks;
22
+ buildInput: ImageToVideoInputBuilder;
23
+ extractResult?: ImageToVideoResultExtractor;
24
+ userId: string;
25
+ currentPrompt: string;
26
+ creationIdRef: React.MutableRefObject<string>;
27
+ updateState: (videoUrl: string | null, thumbnailUrl: string | null) => void;
28
+ }
29
+
30
+ export const createImageToVideoStrategy = (
31
+ params: CreateStrategyParams,
32
+ ): GenerationStrategy<VideoGenerationInput, ImageToVideoResult> => {
33
+ const { config, callbacks, buildInput, extractResult, userId, currentPrompt, creationIdRef, updateState } = params;
34
+
35
+ return {
36
+ execute: async (input) => {
37
+ creationIdRef.current = input.creationId;
38
+
39
+ callbacks.onGenerationStart?.({
40
+ creationId: input.creationId,
41
+ type: "image-to-video",
42
+ imageUrl: input.imageUrl,
43
+ prompt: input.prompt,
44
+ metadata: input.options as Record<string, unknown> | undefined,
45
+ }).catch(() => {});
46
+
47
+ const result = await executeImageToVideo(
48
+ { imageUrl: input.imageUrl, prompt: input.prompt, userId, options: input.options },
49
+ { model: config.model, buildInput, extractResult },
50
+ );
51
+
52
+ if (!result.success || !result.videoUrl) {
53
+ throw new Error(result.error || "Generation failed");
54
+ }
55
+
56
+ updateState(result.videoUrl ?? null, result.thumbnailUrl ?? null);
57
+
58
+ return {
59
+ success: true,
60
+ videoUrl: result.videoUrl,
61
+ thumbnailUrl: result.thumbnailUrl,
62
+ };
63
+ },
64
+ getCreditCost: () => config.creditCost,
65
+ save: async (result) => {
66
+ if (result.success && result.videoUrl && creationIdRef.current) {
67
+ await callbacks.onCreationSave?.({
68
+ creationId: creationIdRef.current,
69
+ type: "image-to-video",
70
+ videoUrl: result.videoUrl,
71
+ thumbnailUrl: result.thumbnailUrl,
72
+ prompt: currentPrompt,
73
+ });
74
+ }
75
+ },
76
+ };
77
+ };
@@ -0,0 +1,102 @@
1
+ import { useState, useCallback, useMemo, useRef } from "react";
2
+ import { useGenerationOrchestrator } from "../../../../presentation/hooks/generation";
3
+ import { createImageToVideoStrategy } from "./imageToVideoStrategy";
4
+ import type {
5
+ UseImageToVideoFeatureProps,
6
+ UseImageToVideoFeatureReturn,
7
+ INITIAL_STATE,
8
+ DEFAULT_ALERT_MESSAGES,
9
+ } from "./image-to-video-feature.types";
10
+
11
+ export type {
12
+ UseImageToVideoFeatureProps,
13
+ UseImageToVideoFeatureReturn,
14
+ } from "./image-to-video-feature.types";
15
+
16
+ export function useImageToVideoFeature(props: UseImageToVideoFeatureProps): UseImageToVideoFeatureReturn {
17
+ const { config, callbacks, userId } = props;
18
+ const [state, setState] = useState(INITIAL_STATE);
19
+ const creationIdRef = useRef("");
20
+
21
+ const updateState = useCallback((videoUrl: string | null, thumbnailUrl: string | null) => {
22
+ setState((prev) => ({ ...prev, videoUrl, thumbnailUrl }));
23
+ }, []);
24
+
25
+ const strategy = useMemo(
26
+ () =>
27
+ createImageToVideoStrategy({
28
+ config,
29
+ callbacks,
30
+ buildInput: config.buildInput,
31
+ extractResult: config.extractResult,
32
+ userId,
33
+ currentPrompt: state.motionPrompt || "",
34
+ creationIdRef,
35
+ updateState,
36
+ }),
37
+ [config, callbacks, userId, state.motionPrompt, updateState],
38
+ );
39
+
40
+ const orchestrator = useGenerationOrchestrator(strategy, {
41
+ userId,
42
+ alertMessages: DEFAULT_ALERT_MESSAGES,
43
+ onCreditsExhausted: () => callbacks.onShowPaywall?.(config.creditCost ?? 0),
44
+ onSuccess: (result) => {
45
+ config.onProcessingComplete?.();
46
+ callbacks.onGenerate?.(result);
47
+ },
48
+ onError: (err) => {
49
+ config.onProcessingError?.(err.message);
50
+ callbacks.onError?.(err.message);
51
+ },
52
+ });
53
+
54
+ const setImageUri = useCallback((imageUri: string) => {
55
+ setState((prev) => ({ ...prev, imageUri, error: null }));
56
+ }, []);
57
+
58
+ const setMotionPrompt = useCallback((motionPrompt: string) => {
59
+ setState((prev) => ({ ...prev, motionPrompt, error: null }));
60
+ }, []);
61
+
62
+ const generate = useCallback(
63
+ async (params?: any) => {
64
+ const imageUri = params?.imageUri || state.imageUri;
65
+ if (!imageUri) {
66
+ const error = "Image is required";
67
+ setState((prev) => ({ ...prev, error }));
68
+ return { success: false, error };
69
+ }
70
+
71
+ setState((prev) => ({ ...prev, isProcessing: true, error: null }));
72
+
73
+ try {
74
+ const result = await orchestrator.generate({
75
+ imageUrl: imageUri,
76
+ prompt: state.motionPrompt || "",
77
+ options: params,
78
+ creationId: `image-to-video-${Date.now()}`,
79
+ });
80
+ setState((prev) => ({ ...prev, isProcessing: false }));
81
+ return result;
82
+ } catch (error) {
83
+ const message = error instanceof Error ? error.message : "Generation failed";
84
+ setState((prev) => ({ ...prev, isProcessing: false, error: message }));
85
+ return { success: false, error: message };
86
+ }
87
+ },
88
+ [state.imageUri, state.motionPrompt, orchestrator],
89
+ );
90
+
91
+ const reset = useCallback(() => setState(INITIAL_STATE), []);
92
+
93
+ return {
94
+ state,
95
+ setImageUri,
96
+ setMotionPrompt,
97
+ generate,
98
+ reset,
99
+ isReady: !orchestrator.isGenerating && !state.isProcessing,
100
+ canGenerate: !orchestrator.isGenerating && !state.isProcessing && !!state.imageUri,
101
+ };
102
+ }