@umituz/react-native-ai-generation-content 1.17.182 → 1.17.183

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.
@@ -1,15 +1,14 @@
1
1
  /**
2
2
  * FaceSwapFeature Component
3
3
  * Self-contained face swap feature UI component
4
- * Uses hook internally, only requires config and translations
4
+ * Uses centralized DualImageFeatureLayout for consistent UX
5
5
  */
6
6
 
7
- import React, { useCallback } from "react";
8
- import { View, ScrollView, StyleSheet, Image } from "react-native";
9
- import { useAppDesignTokens, useResponsive } from "@umituz/react-native-design-system";
7
+ import React, { useMemo } from "react";
8
+ import { View, Image, StyleSheet } from "react-native";
10
9
  import { DualImagePicker } from "../../../../presentation/components/image-picker/DualImagePicker";
11
- import { AIGenerationForm } from "../../../../presentation/components/AIGenerationForm";
12
- import { AIGenerationResult } from "../../../../presentation/components/display/AIGenerationResult";
10
+ import { DualImageFeatureLayout } from "../../../../presentation/layouts";
11
+ import type { ProcessingModalRenderProps } from "../../../../presentation/layouts";
13
12
  import { useFaceSwapFeature } from "../hooks";
14
13
  import type {
15
14
  FaceSwapTranslations,
@@ -18,16 +17,17 @@ import type {
18
17
 
19
18
  export interface FaceSwapFeatureProps {
20
19
  config: FaceSwapFeatureConfig;
21
- translations: FaceSwapTranslations;
20
+ translations: FaceSwapTranslations & {
21
+ modalTitle?: string;
22
+ modalMessage?: string;
23
+ modalHint?: string;
24
+ modalBackgroundHint?: string;
25
+ };
22
26
  onSelectSourceImage: () => Promise<string | null>;
23
27
  onSelectTargetImage: () => Promise<string | null>;
24
28
  onSaveImage: (imageUrl: string) => Promise<void>;
25
- /** Called before processing starts. Return false to cancel. */
26
29
  onBeforeProcess?: () => Promise<boolean>;
27
- renderProcessingModal?: (props: {
28
- visible: boolean;
29
- progress: number;
30
- }) => React.ReactNode;
30
+ renderProcessingModal?: (props: ProcessingModalRenderProps) => React.ReactNode;
31
31
  }
32
32
 
33
33
  export const FaceSwapFeature: React.FC<FaceSwapFeatureProps> = ({
@@ -39,10 +39,6 @@ export const FaceSwapFeature: React.FC<FaceSwapFeatureProps> = ({
39
39
  onBeforeProcess,
40
40
  renderProcessingModal,
41
41
  }) => {
42
- const tokens = useAppDesignTokens();
43
- const { width: screenWidth, horizontalPadding } = useResponsive();
44
- const imageSize = screenWidth - horizontalPadding * 2;
45
-
46
42
  const feature = useFaceSwapFeature({
47
43
  config,
48
44
  onSelectSourceImage,
@@ -51,122 +47,53 @@ export const FaceSwapFeature: React.FC<FaceSwapFeatureProps> = ({
51
47
  onBeforeProcess,
52
48
  });
53
49
 
54
- const handleProcess = useCallback(() => {
55
- void feature.process();
56
- }, [feature]);
57
-
58
- const handleSave = useCallback(() => {
59
- void feature.save();
60
- }, [feature]);
61
-
62
- const handleSelectSource = useCallback(() => {
63
- void feature.selectSourceImage();
64
- }, [feature]);
65
-
66
- const handleSelectTarget = useCallback(() => {
67
- void feature.selectTargetImage();
68
- }, [feature]);
69
-
70
- if (feature.processedUrl) {
71
- return (
72
- <ScrollView
73
- style={[styles.container, { backgroundColor: tokens.colors.backgroundPrimary }]}
74
- contentContainerStyle={styles.content}
75
- showsVerticalScrollIndicator={false}
76
- >
77
- <AIGenerationResult
78
- successText={translations.successText}
79
- primaryAction={{
80
- label: translations.saveButtonText,
81
- onPress: handleSave,
82
- }}
83
- secondaryAction={{
84
- label: translations.tryAnotherText,
85
- onPress: feature.reset,
86
- }}
87
- >
88
- <Image
89
- source={{ uri: feature.processedUrl }}
90
- style={[styles.resultImage, { width: imageSize, height: imageSize }]}
91
- resizeMode="contain"
92
- />
93
- </AIGenerationResult>
94
- </ScrollView>
95
- );
96
- }
50
+ const modalTranslations = useMemo(
51
+ () => ({
52
+ title: translations.modalTitle || "Processing",
53
+ message: translations.modalMessage || "AI is swapping faces...",
54
+ hint: translations.modalHint || "This may take a moment",
55
+ backgroundHint: translations.modalBackgroundHint || "Continue in background",
56
+ }),
57
+ [translations],
58
+ );
97
59
 
98
60
  return (
99
- <>
100
- <ScrollView
101
- style={[styles.container, { backgroundColor: tokens.colors.backgroundPrimary }]}
102
- contentContainerStyle={styles.content}
103
- showsVerticalScrollIndicator={false}
104
- >
105
- <AIGenerationForm
106
- onGenerate={handleProcess}
107
- isGenerating={feature.isProcessing}
108
- progress={feature.progress}
109
- translations={{
110
- generateButton: translations.processButtonText,
111
- generatingButton: translations.processingText,
112
- progressTitle: translations.processingText,
113
- }}
114
- >
115
- <View style={styles.pickerContainer}>
116
- <DualImagePicker
117
- sourceImageUri={feature.sourceImageUri}
118
- targetImageUri={feature.targetImageUri}
119
- isDisabled={feature.isProcessing}
120
- onSelectSource={handleSelectSource}
121
- onSelectTarget={handleSelectTarget}
122
- sourcePlaceholder={translations.sourceUploadTitle}
123
- targetPlaceholder={translations.targetUploadTitle}
124
- layout="horizontal"
125
- />
126
- </View>
127
- </AIGenerationForm>
128
- </ScrollView>
129
-
130
- {renderProcessingModal?.({ visible: feature.isProcessing, progress: feature.progress })}
131
- </>
61
+ <DualImageFeatureLayout
62
+ feature={feature}
63
+ translations={translations}
64
+ modalTranslations={modalTranslations}
65
+ renderProcessingModal={renderProcessingModal}
66
+ renderInput={({ sourceImageUri, targetImageUri, onSelectSource, onSelectTarget, isDisabled }) => (
67
+ <View style={styles.pickerContainer}>
68
+ <DualImagePicker
69
+ sourceImageUri={sourceImageUri}
70
+ targetImageUri={targetImageUri}
71
+ isDisabled={isDisabled}
72
+ onSelectSource={onSelectSource}
73
+ onSelectTarget={onSelectTarget}
74
+ sourcePlaceholder={translations.sourceUploadTitle}
75
+ targetPlaceholder={translations.targetUploadTitle}
76
+ layout="horizontal"
77
+ />
78
+ </View>
79
+ )}
80
+ renderResult={({ imageUrl, imageSize }) => (
81
+ <Image
82
+ source={{ uri: imageUrl }}
83
+ style={[styles.resultImage, { width: imageSize, height: imageSize }]}
84
+ resizeMode="contain"
85
+ />
86
+ )}
87
+ />
132
88
  );
133
89
  };
134
90
 
135
91
  const styles = StyleSheet.create({
136
- container: {
137
- flex: 1,
138
- },
139
- content: {
140
- paddingVertical: 16,
141
- },
142
- description: {
143
- textAlign: "center",
144
- marginHorizontal: 24,
145
- marginBottom: 24,
146
- lineHeight: 24,
147
- },
148
92
  pickerContainer: {
149
93
  marginHorizontal: 16,
150
94
  marginBottom: 16,
151
95
  },
152
- successText: {
153
- textAlign: "center",
154
- marginBottom: 24,
155
- },
156
- resultImageContainer: {
157
- alignItems: "center",
158
- marginHorizontal: 24,
159
- marginBottom: 24,
160
- },
161
96
  resultImage: {
162
97
  borderRadius: 16,
163
98
  },
164
- resultActions: {
165
- marginHorizontal: 24,
166
- gap: 12,
167
- },
168
- buttonContainer: {
169
- marginHorizontal: 24,
170
- marginTop: 8,
171
- },
172
99
  });
@@ -1,15 +1,14 @@
1
1
  /**
2
2
  * HDTouchUpFeature Component
3
3
  * Self-contained HD touch up feature UI component
4
- * Uses hook internally, only requires config and translations
4
+ * Uses centralized SingleImageFeatureLayout for consistent UX
5
5
  */
6
6
 
7
- import React, { useCallback, useMemo } from "react";
8
- import { ScrollView, StyleSheet, Image } from "react-native";
9
- import { useAppDesignTokens, useResponsive } from "@umituz/react-native-design-system";
7
+ import React, { useMemo } from "react";
8
+ import { Image, StyleSheet } from "react-native";
10
9
  import { PhotoUploadCard } from "../../../../presentation/components/PhotoUploadCard";
11
- import { AIGenerationForm } from "../../../../presentation/components/AIGenerationForm";
12
- import { AIGenerationResult } from "../../../../presentation/components/display/AIGenerationResult";
10
+ import { SingleImageFeatureLayout } from "../../../../presentation/layouts";
11
+ import type { ProcessingModalRenderProps } from "../../../../presentation/layouts";
13
12
  import { useHDTouchUpFeature } from "../hooks";
14
13
  import type {
15
14
  HDTouchUpTranslations,
@@ -18,15 +17,16 @@ import type {
18
17
 
19
18
  export interface HDTouchUpFeatureProps {
20
19
  config: HDTouchUpFeatureConfig;
21
- translations: HDTouchUpTranslations;
20
+ translations: HDTouchUpTranslations & {
21
+ modalTitle?: string;
22
+ modalMessage?: string;
23
+ modalHint?: string;
24
+ modalBackgroundHint?: string;
25
+ };
22
26
  onSelectImage: () => Promise<string | null>;
23
27
  onSaveImage: (imageUrl: string) => Promise<void>;
24
- /** Called before processing starts. Return false to cancel. */
25
28
  onBeforeProcess?: () => Promise<boolean>;
26
- renderProcessingModal?: (props: {
27
- visible: boolean;
28
- progress: number;
29
- }) => React.ReactNode;
29
+ renderProcessingModal?: (props: ProcessingModalRenderProps) => React.ReactNode;
30
30
  }
31
31
 
32
32
  export const HDTouchUpFeature: React.FC<HDTouchUpFeatureProps> = ({
@@ -37,10 +37,6 @@ export const HDTouchUpFeature: React.FC<HDTouchUpFeatureProps> = ({
37
37
  onBeforeProcess,
38
38
  renderProcessingModal,
39
39
  }) => {
40
- const tokens = useAppDesignTokens();
41
- const { width: screenWidth, horizontalPadding } = useResponsive();
42
- const imageSize = screenWidth - horizontalPadding * 2;
43
-
44
40
  const feature = useHDTouchUpFeature({
45
41
  config,
46
42
  onSelectImage,
@@ -48,123 +44,55 @@ export const HDTouchUpFeature: React.FC<HDTouchUpFeatureProps> = ({
48
44
  onBeforeProcess,
49
45
  });
50
46
 
51
- const photoTranslations = useMemo(
47
+ const modalTranslations = useMemo(
52
48
  () => ({
53
- tapToUpload: translations.uploadTitle,
54
- selectPhoto: translations.uploadSubtitle,
55
- change: translations.uploadChange,
56
- analyzing: translations.uploadAnalyzing,
49
+ title: translations.modalTitle || "Processing",
50
+ message: translations.modalMessage || "AI is enhancing your photo...",
51
+ hint: translations.modalHint || "This may take a moment",
52
+ backgroundHint: translations.modalBackgroundHint || "Continue in background",
57
53
  }),
58
54
  [translations],
59
55
  );
60
56
 
61
- const handleProcess = useCallback(() => {
62
- void feature.process();
63
- }, [feature]);
64
-
65
- const handleSave = useCallback(() => {
66
- void feature.save();
67
- }, [feature]);
68
-
69
- const handleSelectImage = useCallback(() => {
70
- void feature.selectImage();
71
- }, [feature]);
72
-
73
- if (feature.processedUrl) {
74
- return (
75
- <ScrollView
76
- style={[styles.container, { backgroundColor: tokens.colors.backgroundPrimary }]}
77
- contentContainerStyle={styles.content}
78
- showsVerticalScrollIndicator={false}
79
- >
80
- <AIGenerationResult
81
- successText={translations.successText}
82
- primaryAction={{
83
- label: translations.saveButtonText,
84
- onPress: handleSave,
85
- }}
86
- secondaryAction={{
87
- label: translations.tryAnotherText,
88
- onPress: feature.reset,
89
- }}
90
- >
91
- <Image
92
- source={{ uri: feature.processedUrl }}
93
- style={[styles.resultImage, { width: imageSize, height: imageSize }]}
94
- resizeMode="contain"
95
- />
96
- </AIGenerationResult>
97
- </ScrollView>
98
- );
99
- }
100
-
101
57
  return (
102
- <>
103
- <ScrollView
104
- style={[styles.container, { backgroundColor: tokens.colors.backgroundPrimary }]}
105
- contentContainerStyle={styles.content}
106
- showsVerticalScrollIndicator={false}
107
- >
108
- <AIGenerationForm
109
- onGenerate={handleProcess}
110
- isGenerating={feature.isProcessing}
58
+ <SingleImageFeatureLayout
59
+ feature={feature}
60
+ translations={translations}
61
+ modalTranslations={modalTranslations}
62
+ renderProcessingModal={renderProcessingModal}
63
+ renderInput={({ imageUri, onSelect, isDisabled, isProcessing }) => (
64
+ <PhotoUploadCard
65
+ imageUri={imageUri}
66
+ onPress={onSelect}
67
+ isValidating={isProcessing}
68
+ disabled={isDisabled}
111
69
  translations={{
112
- generateButton: translations.processButtonText,
113
- generatingButton: translations.processingText,
70
+ tapToUpload: translations.uploadTitle,
71
+ selectPhoto: translations.uploadSubtitle,
72
+ change: translations.uploadChange,
73
+ analyzing: translations.uploadAnalyzing,
114
74
  }}
115
- >
116
- <PhotoUploadCard
117
- imageUri={feature.imageUri}
118
- onPress={handleSelectImage}
119
- isValidating={feature.isProcessing}
120
- disabled={feature.isProcessing}
121
- translations={photoTranslations}
122
- config={{
123
- aspectRatio: 1,
124
- borderRadius: 24,
125
- showValidationStatus: false,
126
- allowChange: true,
127
- }}
128
- />
129
- </AIGenerationForm>
130
- </ScrollView>
131
-
132
- {renderProcessingModal?.({ visible: feature.isProcessing, progress: feature.progress })}
133
- </>
75
+ config={{
76
+ aspectRatio: 1,
77
+ borderRadius: 24,
78
+ showValidationStatus: false,
79
+ allowChange: true,
80
+ }}
81
+ />
82
+ )}
83
+ renderResult={({ imageUrl, imageSize }) => (
84
+ <Image
85
+ source={{ uri: imageUrl }}
86
+ style={[styles.resultImage, { width: imageSize, height: imageSize }]}
87
+ resizeMode="contain"
88
+ />
89
+ )}
90
+ />
134
91
  );
135
92
  };
136
93
 
137
94
  const styles = StyleSheet.create({
138
- container: {
139
- flex: 1,
140
- },
141
- content: {
142
- paddingVertical: 16,
143
- },
144
- description: {
145
- textAlign: "center",
146
- marginHorizontal: 24,
147
- marginBottom: 24,
148
- lineHeight: 24,
149
- },
150
- successText: {
151
- textAlign: "center",
152
- marginBottom: 24,
153
- },
154
- resultImageContainer: {
155
- alignItems: "center",
156
- marginHorizontal: 24,
157
- marginBottom: 24,
158
- },
159
95
  resultImage: {
160
96
  borderRadius: 16,
161
97
  },
162
- resultActions: {
163
- marginHorizontal: 24,
164
- gap: 12,
165
- },
166
- buttonContainer: {
167
- marginHorizontal: 24,
168
- marginTop: 8,
169
- },
170
98
  });
@@ -77,6 +77,14 @@ export interface BaseImageTranslations {
77
77
  beforeLabel?: string;
78
78
  afterLabel?: string;
79
79
  compareHint?: string;
80
+ /** Modal title shown during processing */
81
+ modalTitle?: string;
82
+ /** Modal message shown during processing */
83
+ modalMessage?: string;
84
+ /** Modal hint/tip shown during processing */
85
+ modalHint?: string;
86
+ /** "Continue in background" text */
87
+ modalBackgroundHint?: string;
80
88
  }
81
89
 
82
90
  /**
@@ -95,6 +103,14 @@ export interface BaseDualImageTranslations {
95
103
  successText: string;
96
104
  saveButtonText: string;
97
105
  tryAnotherText: string;
106
+ /** Modal title shown during processing */
107
+ modalTitle?: string;
108
+ /** Modal message shown during processing */
109
+ modalMessage?: string;
110
+ /** Modal hint/tip shown during processing */
111
+ modalHint?: string;
112
+ /** "Continue in background" text */
113
+ modalBackgroundHint?: string;
98
114
  }
99
115
 
100
116
  /**
@@ -1,15 +1,14 @@
1
1
  /**
2
2
  * RemoveBackgroundFeature Component
3
3
  * Self-contained remove background feature UI component
4
- * Uses hook internally, only requires config and translations
4
+ * Uses centralized SingleImageFeatureLayout for consistent UX
5
5
  */
6
6
 
7
- import React, { useCallback, useMemo } from "react";
8
- import { ScrollView, StyleSheet, Image } from "react-native";
9
- import { useAppDesignTokens, useResponsive } from "@umituz/react-native-design-system";
7
+ import React, { useMemo } from "react";
8
+ import { Image, StyleSheet } from "react-native";
10
9
  import { PhotoUploadCard } from "../../../../presentation/components/PhotoUploadCard";
11
- import { AIGenerationForm } from "../../../../presentation/components/AIGenerationForm";
12
- import { AIGenerationResult } from "../../../../presentation/components/display/AIGenerationResult";
10
+ import { SingleImageFeatureLayout } from "../../../../presentation/layouts";
11
+ import type { ProcessingModalRenderProps } from "../../../../presentation/layouts";
13
12
  import { useRemoveBackgroundFeature } from "../hooks";
14
13
  import type {
15
14
  RemoveBackgroundTranslations,
@@ -18,15 +17,16 @@ import type {
18
17
 
19
18
  export interface RemoveBackgroundFeatureProps {
20
19
  config: RemoveBackgroundFeatureConfig;
21
- translations: RemoveBackgroundTranslations;
20
+ translations: RemoveBackgroundTranslations & {
21
+ modalTitle?: string;
22
+ modalMessage?: string;
23
+ modalHint?: string;
24
+ modalBackgroundHint?: string;
25
+ };
22
26
  onSelectImage: () => Promise<string | null>;
23
27
  onSaveImage: (imageUrl: string) => Promise<void>;
24
- /** Called before processing starts. Return false to cancel. */
25
28
  onBeforeProcess?: () => Promise<boolean>;
26
- renderProcessingModal?: (props: {
27
- visible: boolean;
28
- progress: number;
29
- }) => React.ReactNode;
29
+ renderProcessingModal?: (props: ProcessingModalRenderProps) => React.ReactNode;
30
30
  }
31
31
 
32
32
  export const RemoveBackgroundFeature: React.FC<RemoveBackgroundFeatureProps> = ({
@@ -37,10 +37,6 @@ export const RemoveBackgroundFeature: React.FC<RemoveBackgroundFeatureProps> = (
37
37
  onBeforeProcess,
38
38
  renderProcessingModal,
39
39
  }) => {
40
- const tokens = useAppDesignTokens();
41
- const { width: screenWidth, horizontalPadding } = useResponsive();
42
- const imageSize = screenWidth - horizontalPadding * 2;
43
-
44
40
  const feature = useRemoveBackgroundFeature({
45
41
  config,
46
42
  onSelectImage,
@@ -48,125 +44,55 @@ export const RemoveBackgroundFeature: React.FC<RemoveBackgroundFeatureProps> = (
48
44
  onBeforeProcess,
49
45
  });
50
46
 
51
- const photoTranslations = useMemo(
47
+ const modalTranslations = useMemo(
52
48
  () => ({
53
- tapToUpload: translations.uploadTitle,
54
- selectPhoto: translations.uploadSubtitle,
55
- change: translations.uploadChange,
56
- analyzing: translations.uploadAnalyzing,
49
+ title: translations.modalTitle || "Processing",
50
+ message: translations.modalMessage || "AI is removing the background...",
51
+ hint: translations.modalHint || "This may take a moment",
52
+ backgroundHint: translations.modalBackgroundHint || "Continue in background",
57
53
  }),
58
54
  [translations],
59
55
  );
60
56
 
61
- const handleProcess = useCallback(() => {
62
- void feature.process();
63
- }, [feature]);
64
-
65
- const handleSave = useCallback(() => {
66
- void feature.save();
67
- }, [feature]);
68
-
69
- const handleSelectImage = useCallback(() => {
70
- void feature.selectImage();
71
- }, [feature]);
72
-
73
- if (feature.processedUrl) {
74
- return (
75
- <ScrollView
76
- style={[styles.container, { backgroundColor: tokens.colors.backgroundPrimary }]}
77
- contentContainerStyle={styles.content}
78
- showsVerticalScrollIndicator={false}
79
- >
80
- <AIGenerationResult
81
- successText={translations.successText}
82
- primaryAction={{
83
- label: translations.saveButtonText,
84
- onPress: handleSave,
85
- }}
86
- secondaryAction={{
87
- label: translations.tryAnotherText,
88
- onPress: feature.reset,
89
- }}
90
- >
91
- <Image
92
- source={{ uri: feature.processedUrl }}
93
- style={[styles.resultImage, { width: imageSize, height: imageSize }]}
94
- resizeMode="contain"
95
- />
96
- </AIGenerationResult>
97
- </ScrollView>
98
- );
99
- }
100
-
101
57
  return (
102
- <>
103
- <ScrollView
104
- style={[styles.container, { backgroundColor: tokens.colors.backgroundPrimary }]}
105
- contentContainerStyle={styles.content}
106
- showsVerticalScrollIndicator={false}
107
- >
108
- <AIGenerationForm
109
- onGenerate={handleProcess}
110
- isGenerating={feature.isProcessing}
111
- progress={feature.progress}
58
+ <SingleImageFeatureLayout
59
+ feature={feature}
60
+ translations={translations}
61
+ modalTranslations={modalTranslations}
62
+ renderProcessingModal={renderProcessingModal}
63
+ renderInput={({ imageUri, onSelect, isDisabled, isProcessing }) => (
64
+ <PhotoUploadCard
65
+ imageUri={imageUri}
66
+ onPress={onSelect}
67
+ isValidating={isProcessing}
68
+ disabled={isDisabled}
112
69
  translations={{
113
- generateButton: translations.processButtonText,
114
- generatingButton: translations.processingText,
115
- progressTitle: translations.processingText,
70
+ tapToUpload: translations.uploadTitle,
71
+ selectPhoto: translations.uploadSubtitle,
72
+ change: translations.uploadChange,
73
+ analyzing: translations.uploadAnalyzing,
116
74
  }}
117
- >
118
- <PhotoUploadCard
119
- imageUri={feature.imageUri}
120
- onPress={handleSelectImage}
121
- isValidating={feature.isProcessing}
122
- disabled={feature.isProcessing}
123
- translations={photoTranslations}
124
- config={{
125
- aspectRatio: 1,
126
- borderRadius: 24,
127
- showValidationStatus: false,
128
- allowChange: true,
129
- }}
130
- />
131
- </AIGenerationForm>
132
- </ScrollView>
133
-
134
- {renderProcessingModal?.({ visible: feature.isProcessing, progress: feature.progress })}
135
- </>
75
+ config={{
76
+ aspectRatio: 1,
77
+ borderRadius: 24,
78
+ showValidationStatus: false,
79
+ allowChange: true,
80
+ }}
81
+ />
82
+ )}
83
+ renderResult={({ imageUrl, imageSize }) => (
84
+ <Image
85
+ source={{ uri: imageUrl }}
86
+ style={[styles.resultImage, { width: imageSize, height: imageSize }]}
87
+ resizeMode="contain"
88
+ />
89
+ )}
90
+ />
136
91
  );
137
92
  };
138
93
 
139
94
  const styles = StyleSheet.create({
140
- container: {
141
- flex: 1,
142
- },
143
- content: {
144
- paddingVertical: 16,
145
- },
146
- description: {
147
- textAlign: "center",
148
- marginHorizontal: 24,
149
- marginBottom: 24,
150
- lineHeight: 24,
151
- },
152
- successText: {
153
- textAlign: "center",
154
- marginBottom: 24,
155
- },
156
- resultImageContainer: {
157
- alignItems: "center",
158
- marginHorizontal: 24,
159
- marginBottom: 24,
160
- },
161
95
  resultImage: {
162
96
  borderRadius: 16,
163
97
  },
164
- resultActions: {
165
- marginHorizontal: 24,
166
- gap: 12,
167
- },
168
- buttonContainer: {
169
- marginHorizontal: 24,
170
- marginTop: 8,
171
- },
172
98
  });