@umituz/react-native-ai-generation-content 1.33.2 → 1.34.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/domains/generation/infrastructure/executors/video-executor.ts +2 -6
- package/src/domains/generation/wizard/presentation/components/GenericWizardFlow.tsx +23 -0
- package/src/domains/generation/wizard/presentation/components/WizardStepRenderer.tsx +7 -1
- package/src/domains/generation/wizard/presentation/components/WizardStepRenderer.types.ts +2 -0
- package/src/domains/generation/wizard/presentation/screens/GeneratingScreen.tsx +44 -4
- package/src/presentation/layouts/DualImageFeatureLayout.tsx +17 -2
- package/src/presentation/layouts/DualImageVideoFeatureLayout.tsx +17 -2
- package/src/presentation/layouts/SingleImageFeatureLayout.tsx +18 -2
- package/src/presentation/layouts/SingleImageWithPromptFeatureLayout.tsx +17 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@umituz/react-native-ai-generation-content",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.34.0",
|
|
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",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Video Generation Executor
|
|
3
|
-
* Generic executor for all video generation features
|
|
3
|
+
* Generic executor for all video generation features (provider-agnostic)
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import type {
|
|
@@ -41,16 +41,12 @@ export class VideoExecutor
|
|
|
41
41
|
return { success: false, error: "AI provider not initialized" };
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
-
options?.onProgress?.(5);
|
|
45
|
-
|
|
46
44
|
const modelInput = this.buildModelInput(input);
|
|
47
45
|
|
|
48
46
|
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
49
47
|
console.log("[VideoExecutor] Model input prepared");
|
|
50
48
|
}
|
|
51
49
|
|
|
52
|
-
options?.onProgress?.(10);
|
|
53
|
-
|
|
54
50
|
const result = await provider.subscribe(model, modelInput, {
|
|
55
51
|
timeoutMs: options?.timeoutMs ?? 300000,
|
|
56
52
|
onQueueUpdate: (status) => {
|
|
@@ -101,7 +97,7 @@ export class VideoExecutor
|
|
|
101
97
|
}
|
|
102
98
|
}
|
|
103
99
|
|
|
104
|
-
private buildModelInput(input: VideoGenerationInput) {
|
|
100
|
+
private buildModelInput(input: VideoGenerationInput): Record<string, unknown> {
|
|
105
101
|
const { sourceImageBase64, targetImageBase64, prompt } = input;
|
|
106
102
|
|
|
107
103
|
const formatBase64 = (base64: string): string => {
|
|
@@ -66,6 +66,7 @@ export const GenericWizardFlow: React.FC<GenericWizardFlowProps> = ({
|
|
|
66
66
|
const [currentCreation, setCurrentCreation] = useState<Creation | null>(null);
|
|
67
67
|
const [showRatingPicker, setShowRatingPicker] = useState(false);
|
|
68
68
|
const [hasRated, setHasRated] = useState(false);
|
|
69
|
+
const [isGeneratingDismissed, setIsGeneratingDismissed] = useState(false);
|
|
69
70
|
const prevStepIdRef = useRef<string | undefined>(undefined);
|
|
70
71
|
|
|
71
72
|
const repository = useMemo(() => createCreationsRepository("creations"), []);
|
|
@@ -133,10 +134,31 @@ export const GenericWizardFlow: React.FC<GenericWizardFlowProps> = ({
|
|
|
133
134
|
if (prevStepIdRef.current !== currentStepId) {
|
|
134
135
|
prevStepIdRef.current = currentStepId;
|
|
135
136
|
onStepChange(currentStep.id, currentStep.type);
|
|
137
|
+
// Reset dismissed state when entering generating step
|
|
138
|
+
if (currentStep.type === StepType.GENERATING) {
|
|
139
|
+
setIsGeneratingDismissed(false);
|
|
140
|
+
}
|
|
136
141
|
}
|
|
137
142
|
}
|
|
138
143
|
}, [currentStep, currentStepIndex, onStepChange]);
|
|
139
144
|
|
|
145
|
+
// Handle dismiss generating - go back but generation continues in background
|
|
146
|
+
const handleDismissGenerating = useCallback(() => {
|
|
147
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
148
|
+
console.log("[GenericWizardFlow] Dismissing generating screen - generation continues in background");
|
|
149
|
+
}
|
|
150
|
+
setIsGeneratingDismissed(true);
|
|
151
|
+
// Show alert that generation continues
|
|
152
|
+
alert.show(
|
|
153
|
+
AlertType.INFO,
|
|
154
|
+
AlertMode.TOAST,
|
|
155
|
+
t("generator.backgroundTitle"),
|
|
156
|
+
t("generator.backgroundMessage")
|
|
157
|
+
);
|
|
158
|
+
// Go back to previous step (or close)
|
|
159
|
+
onBack?.();
|
|
160
|
+
}, [alert, t, onBack]);
|
|
161
|
+
|
|
140
162
|
const handleBack = useCallback(() => {
|
|
141
163
|
if (currentStepIndex === 0) {
|
|
142
164
|
onBack?.();
|
|
@@ -209,6 +231,7 @@ export const GenericWizardFlow: React.FC<GenericWizardFlowProps> = ({
|
|
|
209
231
|
onShare={handleShare}
|
|
210
232
|
onRate={handleOpenRatingPicker}
|
|
211
233
|
onTryAgain={onTryAgain}
|
|
234
|
+
onDismissGenerating={handleDismissGenerating}
|
|
212
235
|
t={t}
|
|
213
236
|
renderPreview={renderPreview}
|
|
214
237
|
renderGenerating={renderGenerating}
|
|
@@ -28,6 +28,7 @@ export const WizardStepRenderer: React.FC<WizardStepRendererProps> = ({
|
|
|
28
28
|
onShare,
|
|
29
29
|
onRate,
|
|
30
30
|
onTryAgain,
|
|
31
|
+
onDismissGenerating,
|
|
31
32
|
t,
|
|
32
33
|
renderPreview,
|
|
33
34
|
renderGenerating,
|
|
@@ -61,7 +62,12 @@ export const WizardStepRenderer: React.FC<WizardStepRendererProps> = ({
|
|
|
61
62
|
case StepType.GENERATING: {
|
|
62
63
|
if (renderGenerating) return renderGenerating(generationProgress);
|
|
63
64
|
return (
|
|
64
|
-
<GeneratingScreen
|
|
65
|
+
<GeneratingScreen
|
|
66
|
+
progress={generationProgress}
|
|
67
|
+
scenario={scenario}
|
|
68
|
+
t={t}
|
|
69
|
+
onDismiss={onDismissGenerating}
|
|
70
|
+
/>
|
|
65
71
|
);
|
|
66
72
|
}
|
|
67
73
|
|
|
@@ -18,6 +18,8 @@ export interface WizardStepRendererProps {
|
|
|
18
18
|
readonly onShare: () => void;
|
|
19
19
|
readonly onRate?: () => void;
|
|
20
20
|
readonly onTryAgain?: () => void;
|
|
21
|
+
/** Called when user dismisses generating screen - generation continues in background */
|
|
22
|
+
readonly onDismissGenerating?: () => void;
|
|
21
23
|
readonly t: (key: string) => string;
|
|
22
24
|
readonly renderPreview?: (onContinue: () => void) => React.ReactElement | null;
|
|
23
25
|
readonly renderGenerating?: (progress: number) => React.ReactElement | null;
|
|
@@ -2,11 +2,12 @@
|
|
|
2
2
|
* Generic Generating Screen
|
|
3
3
|
* Shows indeterminate progress while AI generates content
|
|
4
4
|
* Uses status messages instead of fake percentages (UX best practice)
|
|
5
|
+
* Supports background generation - user can dismiss and generation continues
|
|
5
6
|
*/
|
|
6
7
|
|
|
7
8
|
import React, { useMemo } from "react";
|
|
8
|
-
import { View, StyleSheet, ActivityIndicator } from "react-native";
|
|
9
|
-
import { useAppDesignTokens, AtomicText } from "@umituz/react-native-design-system";
|
|
9
|
+
import { View, StyleSheet, ActivityIndicator, TouchableOpacity } from "react-native";
|
|
10
|
+
import { useAppDesignTokens, AtomicText, AtomicIcon } from "@umituz/react-native-design-system";
|
|
10
11
|
import { useGenerationPhase } from "../hooks/useGenerationPhase";
|
|
11
12
|
import { IndeterminateProgressBar } from "../components/IndeterminateProgressBar";
|
|
12
13
|
|
|
@@ -20,17 +21,19 @@ export interface GeneratingScreenProps {
|
|
|
20
21
|
readonly title?: string;
|
|
21
22
|
readonly waitMessage?: string;
|
|
22
23
|
readonly hint?: string;
|
|
24
|
+
readonly backgroundHint?: string;
|
|
23
25
|
};
|
|
24
26
|
};
|
|
25
27
|
readonly t: (key: string) => string;
|
|
26
|
-
|
|
28
|
+
/** Called when user dismisses the screen - generation continues in background */
|
|
29
|
+
readonly onDismiss?: () => void;
|
|
27
30
|
}
|
|
28
31
|
|
|
29
32
|
export const GeneratingScreen: React.FC<GeneratingScreenProps> = ({
|
|
30
33
|
progress: _progress,
|
|
31
34
|
scenario,
|
|
32
35
|
t,
|
|
33
|
-
|
|
36
|
+
onDismiss,
|
|
34
37
|
}) => {
|
|
35
38
|
const tokens = useAppDesignTokens();
|
|
36
39
|
const phase = useGenerationPhase();
|
|
@@ -48,6 +51,7 @@ export const GeneratingScreen: React.FC<GeneratingScreenProps> = ({
|
|
|
48
51
|
title: custom?.title || t("generator.title"),
|
|
49
52
|
waitMessage: custom?.waitMessage || t("generator.waitMessage"),
|
|
50
53
|
hint: custom?.hint || t("generator.hint"),
|
|
54
|
+
backgroundHint: custom?.backgroundHint || t("generator.backgroundHint"),
|
|
51
55
|
};
|
|
52
56
|
}, [scenario, t]);
|
|
53
57
|
|
|
@@ -66,6 +70,17 @@ export const GeneratingScreen: React.FC<GeneratingScreenProps> = ({
|
|
|
66
70
|
|
|
67
71
|
return (
|
|
68
72
|
<View style={[styles.container, { backgroundColor: tokens.colors.backgroundPrimary }]}>
|
|
73
|
+
{/* Close button - allows user to dismiss and continue in background */}
|
|
74
|
+
{onDismiss && (
|
|
75
|
+
<TouchableOpacity
|
|
76
|
+
style={styles.closeButton}
|
|
77
|
+
onPress={onDismiss}
|
|
78
|
+
hitSlop={{ top: 10, bottom: 10, left: 10, right: 10 }}
|
|
79
|
+
>
|
|
80
|
+
<AtomicIcon name="close" size="md" customColor={tokens.colors.textSecondary} />
|
|
81
|
+
</TouchableOpacity>
|
|
82
|
+
)}
|
|
83
|
+
|
|
69
84
|
<View style={styles.content}>
|
|
70
85
|
<ActivityIndicator size="large" color={tokens.colors.primary} />
|
|
71
86
|
|
|
@@ -93,6 +108,15 @@ export const GeneratingScreen: React.FC<GeneratingScreenProps> = ({
|
|
|
93
108
|
<AtomicText type="bodySmall" style={[styles.hint, { color: tokens.colors.textSecondary }]}>
|
|
94
109
|
{messages.hint}
|
|
95
110
|
</AtomicText>
|
|
111
|
+
|
|
112
|
+
{/* Background hint - tap to dismiss */}
|
|
113
|
+
{onDismiss && (
|
|
114
|
+
<TouchableOpacity style={styles.backgroundHintButton} onPress={onDismiss}>
|
|
115
|
+
<AtomicText type="bodySmall" style={[styles.backgroundHint, { color: tokens.colors.primary }]}>
|
|
116
|
+
{messages.backgroundHint}
|
|
117
|
+
</AtomicText>
|
|
118
|
+
</TouchableOpacity>
|
|
119
|
+
)}
|
|
96
120
|
</View>
|
|
97
121
|
</View>
|
|
98
122
|
);
|
|
@@ -104,6 +128,13 @@ const styles = StyleSheet.create({
|
|
|
104
128
|
justifyContent: "center",
|
|
105
129
|
alignItems: "center",
|
|
106
130
|
},
|
|
131
|
+
closeButton: {
|
|
132
|
+
position: "absolute",
|
|
133
|
+
top: 16,
|
|
134
|
+
right: 16,
|
|
135
|
+
zIndex: 10,
|
|
136
|
+
padding: 8,
|
|
137
|
+
},
|
|
107
138
|
content: {
|
|
108
139
|
width: "80%",
|
|
109
140
|
maxWidth: 400,
|
|
@@ -125,4 +156,13 @@ const styles = StyleSheet.create({
|
|
|
125
156
|
textAlign: "center",
|
|
126
157
|
marginTop: 8,
|
|
127
158
|
},
|
|
159
|
+
backgroundHintButton: {
|
|
160
|
+
marginTop: 24,
|
|
161
|
+
paddingVertical: 12,
|
|
162
|
+
paddingHorizontal: 16,
|
|
163
|
+
},
|
|
164
|
+
backgroundHint: {
|
|
165
|
+
textAlign: "center",
|
|
166
|
+
fontWeight: "600",
|
|
167
|
+
},
|
|
128
168
|
});
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* Note: No Modal wrapper - shows fullscreen progress when processing (FutureUS pattern)
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import React, { useCallback } from "react";
|
|
8
|
+
import React, { useCallback, useState, useEffect } from "react";
|
|
9
9
|
import { View, ScrollView, StyleSheet } from "react-native";
|
|
10
10
|
import {
|
|
11
11
|
useAppDesignTokens,
|
|
@@ -31,6 +31,19 @@ export const DualImageFeatureLayout: React.FC<DualImageFeatureLayoutProps> = ({
|
|
|
31
31
|
const { width: screenWidth, horizontalPadding } = useResponsive();
|
|
32
32
|
const imageSize = screenWidth - horizontalPadding * 2;
|
|
33
33
|
|
|
34
|
+
// Background generation: user can dismiss progress but generation continues
|
|
35
|
+
const [isProgressDismissed, setIsProgressDismissed] = useState(false);
|
|
36
|
+
|
|
37
|
+
useEffect(() => {
|
|
38
|
+
if (feature.isProcessing) {
|
|
39
|
+
setIsProgressDismissed(false);
|
|
40
|
+
}
|
|
41
|
+
}, [feature.isProcessing]);
|
|
42
|
+
|
|
43
|
+
const handleDismissProgress = useCallback(() => {
|
|
44
|
+
setIsProgressDismissed(true);
|
|
45
|
+
}, []);
|
|
46
|
+
|
|
34
47
|
const handleProcess = useCallback(() => {
|
|
35
48
|
void feature.process();
|
|
36
49
|
}, [feature]);
|
|
@@ -48,7 +61,8 @@ export const DualImageFeatureLayout: React.FC<DualImageFeatureLayoutProps> = ({
|
|
|
48
61
|
}, [feature]);
|
|
49
62
|
|
|
50
63
|
// Processing view - fullscreen (FutureUS pattern, no Modal)
|
|
51
|
-
if
|
|
64
|
+
// Show only if processing AND not dismissed
|
|
65
|
+
if (feature.isProcessing && !isProgressDismissed) {
|
|
52
66
|
return (
|
|
53
67
|
<View
|
|
54
68
|
style={[
|
|
@@ -63,6 +77,7 @@ export const DualImageFeatureLayout: React.FC<DualImageFeatureLayoutProps> = ({
|
|
|
63
77
|
message={modalTranslations.message}
|
|
64
78
|
hint={modalTranslations.hint}
|
|
65
79
|
backgroundHint={modalTranslations.backgroundHint}
|
|
80
|
+
onClose={handleDismissProgress}
|
|
66
81
|
backgroundColor={tokens.colors.surface}
|
|
67
82
|
textColor={tokens.colors.textPrimary}
|
|
68
83
|
progressColor={tokens.colors.primary}
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* Note: No Modal wrapper - shows fullscreen progress when processing (FutureUS pattern)
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import React, { useCallback } from "react";
|
|
8
|
+
import React, { useCallback, useState, useEffect } from "react";
|
|
9
9
|
import { View, ScrollView, StyleSheet } from "react-native";
|
|
10
10
|
import {
|
|
11
11
|
useAppDesignTokens,
|
|
@@ -27,6 +27,19 @@ export const DualImageVideoFeatureLayout: React.FC<DualImageVideoFeatureLayoutPr
|
|
|
27
27
|
}) => {
|
|
28
28
|
const tokens = useAppDesignTokens();
|
|
29
29
|
|
|
30
|
+
// Background generation: user can dismiss progress but generation continues
|
|
31
|
+
const [isProgressDismissed, setIsProgressDismissed] = useState(false);
|
|
32
|
+
|
|
33
|
+
useEffect(() => {
|
|
34
|
+
if (feature.isProcessing) {
|
|
35
|
+
setIsProgressDismissed(false);
|
|
36
|
+
}
|
|
37
|
+
}, [feature.isProcessing]);
|
|
38
|
+
|
|
39
|
+
const handleDismissProgress = useCallback(() => {
|
|
40
|
+
setIsProgressDismissed(true);
|
|
41
|
+
}, []);
|
|
42
|
+
|
|
30
43
|
const handleProcess = useCallback(() => {
|
|
31
44
|
void feature.process();
|
|
32
45
|
}, [feature]);
|
|
@@ -44,7 +57,8 @@ export const DualImageVideoFeatureLayout: React.FC<DualImageVideoFeatureLayoutPr
|
|
|
44
57
|
}, [feature]);
|
|
45
58
|
|
|
46
59
|
// Processing view - fullscreen (FutureUS pattern, no Modal)
|
|
47
|
-
if
|
|
60
|
+
// Show only if processing AND not dismissed
|
|
61
|
+
if (feature.isProcessing && !isProgressDismissed) {
|
|
48
62
|
return (
|
|
49
63
|
<View
|
|
50
64
|
style={[
|
|
@@ -59,6 +73,7 @@ export const DualImageVideoFeatureLayout: React.FC<DualImageVideoFeatureLayoutPr
|
|
|
59
73
|
message={modalTranslations.message}
|
|
60
74
|
hint={modalTranslations.hint}
|
|
61
75
|
backgroundHint={modalTranslations.backgroundHint}
|
|
76
|
+
onClose={handleDismissProgress}
|
|
62
77
|
backgroundColor={tokens.colors.surface}
|
|
63
78
|
textColor={tokens.colors.textPrimary}
|
|
64
79
|
progressColor={tokens.colors.primary}
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* Note: No Modal wrapper - shows fullscreen progress when processing (FutureUS pattern)
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import React, { useCallback } from "react";
|
|
8
|
+
import React, { useCallback, useState, useEffect } from "react";
|
|
9
9
|
import { View, ScrollView, StyleSheet } from "react-native";
|
|
10
10
|
import {
|
|
11
11
|
useAppDesignTokens,
|
|
@@ -32,6 +32,20 @@ export const SingleImageFeatureLayout: React.FC<SingleImageFeatureLayoutProps> =
|
|
|
32
32
|
const { width: screenWidth, horizontalPadding } = useResponsive();
|
|
33
33
|
const imageSize = screenWidth - horizontalPadding * 2;
|
|
34
34
|
|
|
35
|
+
// Background generation: user can dismiss progress but generation continues
|
|
36
|
+
const [isProgressDismissed, setIsProgressDismissed] = useState(false);
|
|
37
|
+
|
|
38
|
+
// Reset dismissed state when processing starts
|
|
39
|
+
useEffect(() => {
|
|
40
|
+
if (feature.isProcessing) {
|
|
41
|
+
setIsProgressDismissed(false);
|
|
42
|
+
}
|
|
43
|
+
}, [feature.isProcessing]);
|
|
44
|
+
|
|
45
|
+
const handleDismissProgress = useCallback(() => {
|
|
46
|
+
setIsProgressDismissed(true);
|
|
47
|
+
}, []);
|
|
48
|
+
|
|
35
49
|
const handleProcess = useCallback(() => {
|
|
36
50
|
void feature.process();
|
|
37
51
|
}, [feature]);
|
|
@@ -45,7 +59,8 @@ export const SingleImageFeatureLayout: React.FC<SingleImageFeatureLayoutProps> =
|
|
|
45
59
|
}, [feature]);
|
|
46
60
|
|
|
47
61
|
// Processing view - fullscreen (FutureUS pattern, no Modal)
|
|
48
|
-
if (
|
|
62
|
+
// Show only if processing AND not dismissed (user can dismiss and generation continues)
|
|
63
|
+
if (feature.isProcessing && !isProgressDismissed) {
|
|
49
64
|
return (
|
|
50
65
|
<View
|
|
51
66
|
style={[
|
|
@@ -60,6 +75,7 @@ export const SingleImageFeatureLayout: React.FC<SingleImageFeatureLayoutProps> =
|
|
|
60
75
|
message={modalTranslations.message}
|
|
61
76
|
hint={modalTranslations.hint}
|
|
62
77
|
backgroundHint={modalTranslations.backgroundHint}
|
|
78
|
+
onClose={handleDismissProgress}
|
|
63
79
|
backgroundColor={tokens.colors.surface}
|
|
64
80
|
textColor={tokens.colors.textPrimary}
|
|
65
81
|
progressColor={tokens.colors.primary}
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* Note: No Modal wrapper - shows fullscreen progress when processing (FutureUS pattern)
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
-
import React, { useCallback } from "react";
|
|
9
|
+
import React, { useCallback, useState, useEffect } from "react";
|
|
10
10
|
import { View, ScrollView, StyleSheet } from "react-native";
|
|
11
11
|
import {
|
|
12
12
|
useAppDesignTokens,
|
|
@@ -32,6 +32,19 @@ export const SingleImageWithPromptFeatureLayout: React.FC<SingleImageWithPromptF
|
|
|
32
32
|
const { width: screenWidth, horizontalPadding } = useResponsive();
|
|
33
33
|
const imageSize = screenWidth - horizontalPadding * 2;
|
|
34
34
|
|
|
35
|
+
// Background generation: user can dismiss progress but generation continues
|
|
36
|
+
const [isProgressDismissed, setIsProgressDismissed] = useState(false);
|
|
37
|
+
|
|
38
|
+
useEffect(() => {
|
|
39
|
+
if (feature.isProcessing) {
|
|
40
|
+
setIsProgressDismissed(false);
|
|
41
|
+
}
|
|
42
|
+
}, [feature.isProcessing]);
|
|
43
|
+
|
|
44
|
+
const handleDismissProgress = useCallback(() => {
|
|
45
|
+
setIsProgressDismissed(true);
|
|
46
|
+
}, []);
|
|
47
|
+
|
|
35
48
|
const handleProcess = useCallback(() => {
|
|
36
49
|
void feature.process();
|
|
37
50
|
}, [feature]);
|
|
@@ -52,7 +65,8 @@ export const SingleImageWithPromptFeatureLayout: React.FC<SingleImageWithPromptF
|
|
|
52
65
|
);
|
|
53
66
|
|
|
54
67
|
// Processing view - fullscreen (FutureUS pattern, no Modal)
|
|
55
|
-
if
|
|
68
|
+
// Show only if processing AND not dismissed
|
|
69
|
+
if (feature.isProcessing && !isProgressDismissed) {
|
|
56
70
|
return (
|
|
57
71
|
<View
|
|
58
72
|
style={[
|
|
@@ -67,6 +81,7 @@ export const SingleImageWithPromptFeatureLayout: React.FC<SingleImageWithPromptF
|
|
|
67
81
|
message={modalTranslations.message}
|
|
68
82
|
hint={modalTranslations.hint}
|
|
69
83
|
backgroundHint={modalTranslations.backgroundHint}
|
|
84
|
+
onClose={handleDismissProgress}
|
|
70
85
|
backgroundColor={tokens.colors.surface}
|
|
71
86
|
textColor={tokens.colors.textPrimary}
|
|
72
87
|
progressColor={tokens.colors.primary}
|