@umituz/react-native-ai-generation-content 1.17.11 → 1.17.13
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/features/hd-touch-up/infrastructure/services/hd-touch-up-executor.ts +1 -1
- package/src/features/replace-background/index.ts +2 -1
- package/src/features/replace-background/presentation/components/ReplaceBackgroundFeature.tsx +216 -0
- package/src/features/replace-background/presentation/components/index.ts +3 -0
package/package.json
CHANGED
|
@@ -74,6 +74,7 @@ export type { ExecuteReplaceBackgroundOptions } from "./infrastructure";
|
|
|
74
74
|
|
|
75
75
|
export {
|
|
76
76
|
BackgroundFeature,
|
|
77
|
+
ReplaceBackgroundFeature,
|
|
77
78
|
ImagePicker,
|
|
78
79
|
PromptInput,
|
|
79
80
|
GenerateButton,
|
|
@@ -85,7 +86,7 @@ export {
|
|
|
85
86
|
ModeSelector,
|
|
86
87
|
} from "./presentation/components";
|
|
87
88
|
|
|
88
|
-
export type { BackgroundFeatureProps } from "./presentation/components";
|
|
89
|
+
export type { BackgroundFeatureProps, ReplaceBackgroundFeatureProps } from "./presentation/components";
|
|
89
90
|
|
|
90
91
|
// =============================================================================
|
|
91
92
|
// PRESENTATION LAYER - Hooks
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ReplaceBackgroundFeature Component
|
|
3
|
+
* Self-contained background replacement feature UI component
|
|
4
|
+
* Uses hook internally, only requires config and translations
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import React, { useCallback, useMemo } from "react";
|
|
8
|
+
import { View, ScrollView, StyleSheet, Image, Dimensions } from "react-native";
|
|
9
|
+
import {
|
|
10
|
+
useAppDesignTokens,
|
|
11
|
+
AtomicText,
|
|
12
|
+
AtomicButton,
|
|
13
|
+
AtomicInput,
|
|
14
|
+
} from "@umituz/react-native-design-system";
|
|
15
|
+
import { PhotoUploadCard } from "../../../../presentation/components/PhotoUploadCard";
|
|
16
|
+
import { ErrorDisplay } from "../../../../presentation/components/display/ErrorDisplay";
|
|
17
|
+
import { useReplaceBackgroundFeature } from "../hooks";
|
|
18
|
+
import type {
|
|
19
|
+
ReplaceBackgroundTranslations,
|
|
20
|
+
ReplaceBackgroundFeatureConfig,
|
|
21
|
+
} from "../../domain/types";
|
|
22
|
+
|
|
23
|
+
export interface ReplaceBackgroundFeatureProps {
|
|
24
|
+
config: ReplaceBackgroundFeatureConfig;
|
|
25
|
+
userId: string;
|
|
26
|
+
translations: ReplaceBackgroundTranslations;
|
|
27
|
+
onSelectImage: () => Promise<string | null>;
|
|
28
|
+
onSaveImage: (imageUrl: string) => Promise<void>;
|
|
29
|
+
renderProcessingModal?: (props: {
|
|
30
|
+
visible: boolean;
|
|
31
|
+
progress: number;
|
|
32
|
+
}) => React.ReactNode;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export const ReplaceBackgroundFeature: React.FC<ReplaceBackgroundFeatureProps> = ({
|
|
36
|
+
config,
|
|
37
|
+
userId,
|
|
38
|
+
translations,
|
|
39
|
+
onSelectImage,
|
|
40
|
+
onSaveImage,
|
|
41
|
+
renderProcessingModal,
|
|
42
|
+
}) => {
|
|
43
|
+
const tokens = useAppDesignTokens();
|
|
44
|
+
|
|
45
|
+
const feature = useReplaceBackgroundFeature({
|
|
46
|
+
config,
|
|
47
|
+
userId,
|
|
48
|
+
onSelectImage,
|
|
49
|
+
onSaveImage,
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
const photoTranslations = useMemo(
|
|
53
|
+
() => ({
|
|
54
|
+
tapToUpload: translations.uploadTitle,
|
|
55
|
+
selectPhoto: translations.uploadSubtitle,
|
|
56
|
+
change: translations.uploadChange,
|
|
57
|
+
analyzing: translations.uploadAnalyzing,
|
|
58
|
+
}),
|
|
59
|
+
[translations],
|
|
60
|
+
);
|
|
61
|
+
|
|
62
|
+
const handleProcess = useCallback(() => {
|
|
63
|
+
void feature.process();
|
|
64
|
+
}, [feature]);
|
|
65
|
+
|
|
66
|
+
const handleSave = useCallback(() => {
|
|
67
|
+
void feature.save();
|
|
68
|
+
}, [feature]);
|
|
69
|
+
|
|
70
|
+
const handleSelectImage = useCallback(() => {
|
|
71
|
+
void feature.selectImage();
|
|
72
|
+
}, [feature]);
|
|
73
|
+
|
|
74
|
+
if (feature.processedUrl) {
|
|
75
|
+
const screenWidth = Dimensions.get("window").width;
|
|
76
|
+
const imageSize = screenWidth - 48;
|
|
77
|
+
|
|
78
|
+
return (
|
|
79
|
+
<ScrollView
|
|
80
|
+
style={[styles.container, { backgroundColor: tokens.colors.backgroundPrimary }]}
|
|
81
|
+
contentContainerStyle={styles.content}
|
|
82
|
+
showsVerticalScrollIndicator={false}
|
|
83
|
+
>
|
|
84
|
+
<AtomicText
|
|
85
|
+
type="headlineMedium"
|
|
86
|
+
style={[styles.successText, { color: tokens.colors.success }]}
|
|
87
|
+
>
|
|
88
|
+
{translations.successText}
|
|
89
|
+
</AtomicText>
|
|
90
|
+
|
|
91
|
+
<View style={styles.resultImageContainer}>
|
|
92
|
+
<Image
|
|
93
|
+
source={{ uri: feature.processedUrl }}
|
|
94
|
+
style={[styles.resultImage, { width: imageSize, height: imageSize }]}
|
|
95
|
+
resizeMode="contain"
|
|
96
|
+
/>
|
|
97
|
+
</View>
|
|
98
|
+
|
|
99
|
+
<View style={styles.resultActions}>
|
|
100
|
+
<AtomicButton
|
|
101
|
+
title={translations.saveButtonText}
|
|
102
|
+
onPress={handleSave}
|
|
103
|
+
variant="primary"
|
|
104
|
+
size="lg"
|
|
105
|
+
/>
|
|
106
|
+
<AtomicButton
|
|
107
|
+
title={translations.tryAnotherText}
|
|
108
|
+
onPress={feature.reset}
|
|
109
|
+
variant="secondary"
|
|
110
|
+
size="lg"
|
|
111
|
+
/>
|
|
112
|
+
</View>
|
|
113
|
+
</ScrollView>
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
return (
|
|
118
|
+
<>
|
|
119
|
+
<ScrollView
|
|
120
|
+
style={[styles.container, { backgroundColor: tokens.colors.backgroundPrimary }]}
|
|
121
|
+
contentContainerStyle={styles.content}
|
|
122
|
+
showsVerticalScrollIndicator={false}
|
|
123
|
+
>
|
|
124
|
+
<AtomicText
|
|
125
|
+
type="bodyLarge"
|
|
126
|
+
style={[styles.description, { color: tokens.colors.textSecondary }]}
|
|
127
|
+
>
|
|
128
|
+
{translations.description}
|
|
129
|
+
</AtomicText>
|
|
130
|
+
|
|
131
|
+
<PhotoUploadCard
|
|
132
|
+
imageUri={feature.imageUri}
|
|
133
|
+
onPress={handleSelectImage}
|
|
134
|
+
isValidating={feature.isProcessing}
|
|
135
|
+
disabled={feature.isProcessing}
|
|
136
|
+
translations={photoTranslations}
|
|
137
|
+
config={{
|
|
138
|
+
aspectRatio: 1,
|
|
139
|
+
borderRadius: 24,
|
|
140
|
+
showValidationStatus: false,
|
|
141
|
+
allowChange: true,
|
|
142
|
+
}}
|
|
143
|
+
/>
|
|
144
|
+
|
|
145
|
+
<View style={styles.promptContainer}>
|
|
146
|
+
<AtomicInput
|
|
147
|
+
value={feature.prompt}
|
|
148
|
+
onChangeText={feature.setPrompt}
|
|
149
|
+
placeholder={translations.promptPlaceholder}
|
|
150
|
+
multiline
|
|
151
|
+
numberOfLines={3}
|
|
152
|
+
editable={!feature.isProcessing}
|
|
153
|
+
/>
|
|
154
|
+
</View>
|
|
155
|
+
|
|
156
|
+
<ErrorDisplay error={feature.error} />
|
|
157
|
+
|
|
158
|
+
<View style={styles.buttonContainer}>
|
|
159
|
+
<AtomicButton
|
|
160
|
+
title={
|
|
161
|
+
feature.isProcessing
|
|
162
|
+
? translations.processingText
|
|
163
|
+
: translations.processButtonText
|
|
164
|
+
}
|
|
165
|
+
onPress={handleProcess}
|
|
166
|
+
disabled={!feature.imageUri || feature.isProcessing}
|
|
167
|
+
variant="primary"
|
|
168
|
+
size="lg"
|
|
169
|
+
/>
|
|
170
|
+
</View>
|
|
171
|
+
</ScrollView>
|
|
172
|
+
|
|
173
|
+
{renderProcessingModal?.({ visible: feature.isProcessing, progress: feature.progress })}
|
|
174
|
+
</>
|
|
175
|
+
);
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
const styles = StyleSheet.create({
|
|
179
|
+
container: {
|
|
180
|
+
flex: 1,
|
|
181
|
+
},
|
|
182
|
+
content: {
|
|
183
|
+
paddingVertical: 16,
|
|
184
|
+
},
|
|
185
|
+
description: {
|
|
186
|
+
textAlign: "center",
|
|
187
|
+
marginHorizontal: 24,
|
|
188
|
+
marginBottom: 24,
|
|
189
|
+
lineHeight: 24,
|
|
190
|
+
},
|
|
191
|
+
promptContainer: {
|
|
192
|
+
marginHorizontal: 24,
|
|
193
|
+
marginTop: 16,
|
|
194
|
+
marginBottom: 8,
|
|
195
|
+
},
|
|
196
|
+
successText: {
|
|
197
|
+
textAlign: "center",
|
|
198
|
+
marginBottom: 24,
|
|
199
|
+
},
|
|
200
|
+
resultImageContainer: {
|
|
201
|
+
alignItems: "center",
|
|
202
|
+
marginHorizontal: 24,
|
|
203
|
+
marginBottom: 24,
|
|
204
|
+
},
|
|
205
|
+
resultImage: {
|
|
206
|
+
borderRadius: 16,
|
|
207
|
+
},
|
|
208
|
+
resultActions: {
|
|
209
|
+
marginHorizontal: 24,
|
|
210
|
+
gap: 12,
|
|
211
|
+
},
|
|
212
|
+
buttonContainer: {
|
|
213
|
+
marginHorizontal: 24,
|
|
214
|
+
marginTop: 8,
|
|
215
|
+
},
|
|
216
|
+
});
|
|
@@ -5,6 +5,9 @@
|
|
|
5
5
|
export { BackgroundFeature } from "./BackgroundFeature";
|
|
6
6
|
export type { BackgroundFeatureProps } from "./BackgroundFeature";
|
|
7
7
|
|
|
8
|
+
export { ReplaceBackgroundFeature } from "./ReplaceBackgroundFeature";
|
|
9
|
+
export type { ReplaceBackgroundFeatureProps } from "./ReplaceBackgroundFeature";
|
|
10
|
+
|
|
8
11
|
export { ImagePicker } from "./ImagePicker";
|
|
9
12
|
export { PromptInput } from "./PromptInput";
|
|
10
13
|
export { GenerateButton } from "./GenerateButton";
|