@umituz/react-native-ai-generation-content 1.17.219 → 1.17.220
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/creations/presentation/components/CreationCard.tsx +19 -145
- package/src/domains/creations/presentation/components/CreationCard.types.ts +58 -0
- package/src/domains/creations/presentation/components/CreationCard.utils.ts +29 -0
- package/src/domains/creations/presentation/components/CreationCardMeta.tsx +50 -0
- package/src/domains/creations/presentation/components/CreationsFilterBar.helpers.ts +96 -0
- package/src/domains/creations/presentation/components/CreationsFilterBar.tsx +6 -121
- package/src/domains/creations/presentation/components/CreationsFilterBar.types.ts +47 -0
- package/src/domains/creations/presentation/components/useCreationCardActions.ts +73 -0
- package/src/features/image-to-video/presentation/components/AddMoreCard.tsx +52 -0
- package/src/features/image-to-video/presentation/components/EmptyGridState.tsx +69 -0
- package/src/features/image-to-video/presentation/components/GridImageItem.tsx +64 -0
- package/src/features/image-to-video/presentation/components/ImageSelectionGrid.styles.ts +84 -0
- package/src/features/image-to-video/presentation/components/ImageSelectionGrid.tsx +32 -189
- package/src/features/image-to-video/presentation/components/ImageSelectionGrid.types.ts +18 -0
- package/src/infrastructure/utils/url-extractor/base-extractor.ts +72 -0
- package/src/infrastructure/utils/url-extractor/index.ts +22 -0
- package/src/infrastructure/utils/url-extractor/media-extractors.ts +78 -0
- package/src/infrastructure/utils/url-extractor/multi-extractor.ts +61 -0
- package/src/infrastructure/utils/url-extractor/thumbnail-extractor.ts +31 -0
- package/src/infrastructure/utils/url-extractor.util.ts +8 -218
- package/src/presentation/components/GenerationProgressContent.styles.ts +68 -0
- package/src/presentation/components/GenerationProgressContent.tsx +28 -160
- package/src/presentation/components/GenerationProgressContent.types.ts +23 -0
- package/src/presentation/components/PhotoUploadCard/ImageContent.tsx +48 -0
- package/src/presentation/components/PhotoUploadCard/PhotoUploadCard.styles.ts +112 -0
- package/src/presentation/components/PhotoUploadCard/PhotoUploadCard.tsx +37 -193
- package/src/presentation/components/PhotoUploadCard/PhotoUploadCard.types.ts +42 -0
- package/src/presentation/components/PhotoUploadCard/PlaceholderContent.tsx +45 -0
- package/src/presentation/components/PhotoUploadCard/ValidatingContent.tsx +32 -0
- package/src/presentation/components/PhotoUploadCard/useBorderColor.ts +31 -0
- package/src/presentation/components/ProgressCloseButton.tsx +27 -0
- package/src/presentation/components/ProgressDismissButton.tsx +48 -0
- package/src/presentation/components/ProgressHeader.tsx +64 -0
- package/src/presentation/components/ProgressHint.tsx +62 -0
- package/src/presentation/components/result/ActionButton.tsx +64 -0
- package/src/presentation/components/result/ResultActions.styles.ts +54 -0
- package/src/presentation/components/result/ResultActions.tsx +44 -179
- package/src/presentation/components/result/ResultActions.types.ts +20 -0
- package/src/presentation/components/result/RetryButton.tsx +39 -0
- package/src/presentation/components/result/button-style.utils.ts +56 -0
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Media URL Extractors
|
|
3
|
+
* Specialized extractors for video, audio, and image URLs
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { extractOutputUrl } from "./base-extractor";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Extract video URL from AI generation result
|
|
10
|
+
*/
|
|
11
|
+
export function extractVideoUrl(result: unknown): string | undefined {
|
|
12
|
+
return extractOutputUrl(result, [
|
|
13
|
+
"video_url",
|
|
14
|
+
"videoUrl",
|
|
15
|
+
"video",
|
|
16
|
+
"url",
|
|
17
|
+
]);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Extract audio URL from AI generation result
|
|
22
|
+
*/
|
|
23
|
+
export function extractAudioUrl(result: unknown): string | undefined {
|
|
24
|
+
return extractOutputUrl(result, [
|
|
25
|
+
"audio_url",
|
|
26
|
+
"audioUrl",
|
|
27
|
+
"audio",
|
|
28
|
+
"url",
|
|
29
|
+
]);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Extract image URLs from AI generation result
|
|
34
|
+
*/
|
|
35
|
+
export function extractImageUrls(result: unknown): string[] {
|
|
36
|
+
if (!result || typeof result !== "object") {
|
|
37
|
+
return [];
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const urls: string[] = [];
|
|
41
|
+
const resultObj = result as Record<string, unknown>;
|
|
42
|
+
|
|
43
|
+
// Check top-level image object (birefnet, rembg format)
|
|
44
|
+
const topImage = resultObj.image as Record<string, unknown>;
|
|
45
|
+
if (topImage && typeof topImage === "object" && typeof topImage.url === "string") {
|
|
46
|
+
urls.push(topImage.url);
|
|
47
|
+
return urls;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Check images array
|
|
51
|
+
if (Array.isArray(resultObj.images)) {
|
|
52
|
+
for (const img of resultObj.images) {
|
|
53
|
+
if (typeof img === "string" && img.length > 0) {
|
|
54
|
+
urls.push(img);
|
|
55
|
+
} else if (img && typeof img === "object") {
|
|
56
|
+
const imgObj = img as Record<string, unknown>;
|
|
57
|
+
if (typeof imgObj.url === "string") {
|
|
58
|
+
urls.push(imgObj.url);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Check single image
|
|
65
|
+
if (urls.length === 0) {
|
|
66
|
+
const singleUrl = extractOutputUrl(result, [
|
|
67
|
+
"image_url",
|
|
68
|
+
"imageUrl",
|
|
69
|
+
"image",
|
|
70
|
+
"url",
|
|
71
|
+
]);
|
|
72
|
+
if (singleUrl) {
|
|
73
|
+
urls.push(singleUrl);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return urls;
|
|
78
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Multiple URL Extractor
|
|
3
|
+
* Extracts arrays of URLs from AI generation results
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { extractOutputUrl } from "./base-extractor";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Extract multiple output URLs from result
|
|
10
|
+
*/
|
|
11
|
+
export function extractOutputUrls(
|
|
12
|
+
result: unknown,
|
|
13
|
+
urlFields?: string[],
|
|
14
|
+
): string[] {
|
|
15
|
+
if (!result || typeof result !== "object") {
|
|
16
|
+
return [];
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const urls: string[] = [];
|
|
20
|
+
const resultObj = result as Record<string, unknown>;
|
|
21
|
+
|
|
22
|
+
// Check for arrays
|
|
23
|
+
const arrayFields = ["images", "videos", "outputs", "results", "urls"];
|
|
24
|
+
for (const field of arrayFields) {
|
|
25
|
+
const arr = resultObj[field];
|
|
26
|
+
if (Array.isArray(arr)) {
|
|
27
|
+
for (const item of arr) {
|
|
28
|
+
const url = extractOutputUrl(item, urlFields);
|
|
29
|
+
if (url) {
|
|
30
|
+
urls.push(url);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Check nested data/output
|
|
37
|
+
const nested = resultObj.data || resultObj.output;
|
|
38
|
+
if (nested && typeof nested === "object") {
|
|
39
|
+
for (const field of arrayFields) {
|
|
40
|
+
const arr = (nested as Record<string, unknown>)[field];
|
|
41
|
+
if (Array.isArray(arr)) {
|
|
42
|
+
for (const item of arr) {
|
|
43
|
+
const url = extractOutputUrl(item, urlFields);
|
|
44
|
+
if (url) {
|
|
45
|
+
urls.push(url);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// If no array found, try single URL
|
|
53
|
+
if (urls.length === 0) {
|
|
54
|
+
const singleUrl = extractOutputUrl(result, urlFields);
|
|
55
|
+
if (singleUrl) {
|
|
56
|
+
urls.push(singleUrl);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return urls;
|
|
61
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Thumbnail URL Extractor
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Extract thumbnail URL from AI generation result
|
|
7
|
+
*/
|
|
8
|
+
export function extractThumbnailUrl(result: unknown): string | undefined {
|
|
9
|
+
if (!result || typeof result !== "object") {
|
|
10
|
+
return undefined;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const resultObj = result as Record<string, unknown>;
|
|
14
|
+
|
|
15
|
+
// Check direct fields
|
|
16
|
+
const fields = ["thumbnail_url", "thumbnailUrl", "thumbnail", "poster"];
|
|
17
|
+
for (const field of fields) {
|
|
18
|
+
const value = resultObj[field];
|
|
19
|
+
if (typeof value === "string" && value.length > 0) {
|
|
20
|
+
return value;
|
|
21
|
+
}
|
|
22
|
+
if (value && typeof value === "object") {
|
|
23
|
+
const nested = value as Record<string, unknown>;
|
|
24
|
+
if (typeof nested.url === "string") {
|
|
25
|
+
return nested.url;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return undefined;
|
|
31
|
+
}
|
|
@@ -4,221 +4,11 @@
|
|
|
4
4
|
* Supports various provider response formats
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
if (!result || typeof result !== "object") {
|
|
16
|
-
return undefined;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
const fields = urlFields ?? [
|
|
20
|
-
"url",
|
|
21
|
-
"image_url",
|
|
22
|
-
"video_url",
|
|
23
|
-
"output_url",
|
|
24
|
-
"result_url",
|
|
25
|
-
];
|
|
26
|
-
|
|
27
|
-
const resultObj = result as Record<string, unknown>;
|
|
28
|
-
|
|
29
|
-
// Check top-level fields
|
|
30
|
-
for (const field of fields) {
|
|
31
|
-
const value = resultObj[field];
|
|
32
|
-
if (typeof value === "string" && value.length > 0) {
|
|
33
|
-
return value;
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
// Check top-level image/video objects (for birefnet, rembg, etc.)
|
|
38
|
-
const topMedia =
|
|
39
|
-
(resultObj.image as Record<string, unknown>) ||
|
|
40
|
-
(resultObj.video as Record<string, unknown>);
|
|
41
|
-
if (topMedia && typeof topMedia === "object" && typeof topMedia.url === "string") {
|
|
42
|
-
return topMedia.url;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
// Check nested data/output objects
|
|
46
|
-
const nested =
|
|
47
|
-
(resultObj.data as Record<string, unknown>) ||
|
|
48
|
-
(resultObj.output as Record<string, unknown>) ||
|
|
49
|
-
(resultObj.result as Record<string, unknown>);
|
|
50
|
-
|
|
51
|
-
if (nested && typeof nested === "object") {
|
|
52
|
-
for (const field of fields) {
|
|
53
|
-
const value = nested[field];
|
|
54
|
-
if (typeof value === "string" && value.length > 0) {
|
|
55
|
-
return value;
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
// Check for nested image/video objects
|
|
60
|
-
const media =
|
|
61
|
-
(nested.image as Record<string, unknown>) ||
|
|
62
|
-
(nested.video as Record<string, unknown>);
|
|
63
|
-
if (media && typeof media === "object" && typeof media.url === "string") {
|
|
64
|
-
return media.url;
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
return undefined;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
/**
|
|
72
|
-
* Extract multiple output URLs from result
|
|
73
|
-
*/
|
|
74
|
-
export function extractOutputUrls(
|
|
75
|
-
result: unknown,
|
|
76
|
-
urlFields?: string[],
|
|
77
|
-
): string[] {
|
|
78
|
-
if (!result || typeof result !== "object") {
|
|
79
|
-
return [];
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
const urls: string[] = [];
|
|
83
|
-
const resultObj = result as Record<string, unknown>;
|
|
84
|
-
|
|
85
|
-
// Check for arrays
|
|
86
|
-
const arrayFields = ["images", "videos", "outputs", "results", "urls"];
|
|
87
|
-
for (const field of arrayFields) {
|
|
88
|
-
const arr = resultObj[field];
|
|
89
|
-
if (Array.isArray(arr)) {
|
|
90
|
-
for (const item of arr) {
|
|
91
|
-
const url = extractOutputUrl(item, urlFields);
|
|
92
|
-
if (url) {
|
|
93
|
-
urls.push(url);
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
// Check nested data/output
|
|
100
|
-
const nested = resultObj.data || resultObj.output;
|
|
101
|
-
if (nested && typeof nested === "object") {
|
|
102
|
-
for (const field of arrayFields) {
|
|
103
|
-
const arr = (nested as Record<string, unknown>)[field];
|
|
104
|
-
if (Array.isArray(arr)) {
|
|
105
|
-
for (const item of arr) {
|
|
106
|
-
const url = extractOutputUrl(item, urlFields);
|
|
107
|
-
if (url) {
|
|
108
|
-
urls.push(url);
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
// If no array found, try single URL
|
|
116
|
-
if (urls.length === 0) {
|
|
117
|
-
const singleUrl = extractOutputUrl(result, urlFields);
|
|
118
|
-
if (singleUrl) {
|
|
119
|
-
urls.push(singleUrl);
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
return urls;
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
/**
|
|
127
|
-
* Extract video URL from AI generation result
|
|
128
|
-
*/
|
|
129
|
-
export function extractVideoUrl(result: unknown): string | undefined {
|
|
130
|
-
return extractOutputUrl(result, [
|
|
131
|
-
"video_url",
|
|
132
|
-
"videoUrl",
|
|
133
|
-
"video",
|
|
134
|
-
"url",
|
|
135
|
-
]);
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
/**
|
|
139
|
-
* Extract thumbnail URL from AI generation result
|
|
140
|
-
*/
|
|
141
|
-
export function extractThumbnailUrl(result: unknown): string | undefined {
|
|
142
|
-
if (!result || typeof result !== "object") {
|
|
143
|
-
return undefined;
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
const resultObj = result as Record<string, unknown>;
|
|
147
|
-
|
|
148
|
-
// Check direct fields
|
|
149
|
-
const fields = ["thumbnail_url", "thumbnailUrl", "thumbnail", "poster"];
|
|
150
|
-
for (const field of fields) {
|
|
151
|
-
const value = resultObj[field];
|
|
152
|
-
if (typeof value === "string" && value.length > 0) {
|
|
153
|
-
return value;
|
|
154
|
-
}
|
|
155
|
-
if (value && typeof value === "object") {
|
|
156
|
-
const nested = value as Record<string, unknown>;
|
|
157
|
-
if (typeof nested.url === "string") {
|
|
158
|
-
return nested.url;
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
return undefined;
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
/**
|
|
167
|
-
* Extract audio URL from AI generation result
|
|
168
|
-
*/
|
|
169
|
-
export function extractAudioUrl(result: unknown): string | undefined {
|
|
170
|
-
return extractOutputUrl(result, [
|
|
171
|
-
"audio_url",
|
|
172
|
-
"audioUrl",
|
|
173
|
-
"audio",
|
|
174
|
-
"url",
|
|
175
|
-
]);
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
/**
|
|
179
|
-
* Extract image URLs from AI generation result
|
|
180
|
-
*/
|
|
181
|
-
export function extractImageUrls(result: unknown): string[] {
|
|
182
|
-
if (!result || typeof result !== "object") {
|
|
183
|
-
return [];
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
const urls: string[] = [];
|
|
187
|
-
const resultObj = result as Record<string, unknown>;
|
|
188
|
-
|
|
189
|
-
// Check top-level image object (birefnet, rembg format)
|
|
190
|
-
const topImage = resultObj.image as Record<string, unknown>;
|
|
191
|
-
if (topImage && typeof topImage === "object" && typeof topImage.url === "string") {
|
|
192
|
-
urls.push(topImage.url);
|
|
193
|
-
return urls;
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
// Check images array
|
|
197
|
-
if (Array.isArray(resultObj.images)) {
|
|
198
|
-
for (const img of resultObj.images) {
|
|
199
|
-
if (typeof img === "string" && img.length > 0) {
|
|
200
|
-
urls.push(img);
|
|
201
|
-
} else if (img && typeof img === "object") {
|
|
202
|
-
const imgObj = img as Record<string, unknown>;
|
|
203
|
-
if (typeof imgObj.url === "string") {
|
|
204
|
-
urls.push(imgObj.url);
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
// Check single image
|
|
211
|
-
if (urls.length === 0) {
|
|
212
|
-
const singleUrl = extractOutputUrl(result, [
|
|
213
|
-
"image_url",
|
|
214
|
-
"imageUrl",
|
|
215
|
-
"image",
|
|
216
|
-
"url",
|
|
217
|
-
]);
|
|
218
|
-
if (singleUrl) {
|
|
219
|
-
urls.push(singleUrl);
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
return urls;
|
|
224
|
-
}
|
|
7
|
+
export {
|
|
8
|
+
extractOutputUrl,
|
|
9
|
+
extractVideoUrl,
|
|
10
|
+
extractAudioUrl,
|
|
11
|
+
extractImageUrls,
|
|
12
|
+
extractOutputUrls,
|
|
13
|
+
extractThumbnailUrl,
|
|
14
|
+
} from "./url-extractor";
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GenerationProgressContent Styles
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { StyleSheet } from "react-native";
|
|
6
|
+
|
|
7
|
+
export const generationProgressContentStyles = StyleSheet.create({
|
|
8
|
+
modal: {
|
|
9
|
+
width: "100%",
|
|
10
|
+
maxWidth: 380,
|
|
11
|
+
borderRadius: 24,
|
|
12
|
+
padding: 32,
|
|
13
|
+
borderWidth: 1,
|
|
14
|
+
alignItems: "center",
|
|
15
|
+
position: "relative",
|
|
16
|
+
},
|
|
17
|
+
closeButton: {
|
|
18
|
+
position: "absolute",
|
|
19
|
+
top: 16,
|
|
20
|
+
right: 16,
|
|
21
|
+
width: 32,
|
|
22
|
+
height: 32,
|
|
23
|
+
borderRadius: 16,
|
|
24
|
+
justifyContent: "center",
|
|
25
|
+
alignItems: "center",
|
|
26
|
+
zIndex: 1,
|
|
27
|
+
},
|
|
28
|
+
iconContainer: {
|
|
29
|
+
marginBottom: 20,
|
|
30
|
+
},
|
|
31
|
+
title: {
|
|
32
|
+
fontWeight: "700",
|
|
33
|
+
marginBottom: 8,
|
|
34
|
+
textAlign: "center",
|
|
35
|
+
},
|
|
36
|
+
message: {
|
|
37
|
+
marginBottom: 28,
|
|
38
|
+
textAlign: "center",
|
|
39
|
+
lineHeight: 20,
|
|
40
|
+
},
|
|
41
|
+
hint: {
|
|
42
|
+
textAlign: "center",
|
|
43
|
+
lineHeight: 18,
|
|
44
|
+
paddingHorizontal: 8,
|
|
45
|
+
},
|
|
46
|
+
backgroundHintButton: {
|
|
47
|
+
marginTop: 16,
|
|
48
|
+
paddingVertical: 8,
|
|
49
|
+
paddingHorizontal: 16,
|
|
50
|
+
},
|
|
51
|
+
backgroundHintText: {
|
|
52
|
+
textAlign: "center",
|
|
53
|
+
textDecorationLine: "underline",
|
|
54
|
+
},
|
|
55
|
+
dismissButton: {
|
|
56
|
+
marginTop: 16,
|
|
57
|
+
paddingVertical: 14,
|
|
58
|
+
paddingHorizontal: 32,
|
|
59
|
+
borderRadius: 12,
|
|
60
|
+
minWidth: 140,
|
|
61
|
+
alignItems: "center",
|
|
62
|
+
},
|
|
63
|
+
dismissText: {
|
|
64
|
+
fontWeight: "600",
|
|
65
|
+
},
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
export type GenerationProgressContentStyles = typeof generationProgressContentStyles;
|
|
@@ -5,33 +5,15 @@
|
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
import React from "react";
|
|
8
|
-
import { View
|
|
9
|
-
import {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
} from "
|
|
8
|
+
import { View } from "react-native";
|
|
9
|
+
import { useAppDesignTokens } from "@umituz/react-native-design-system";
|
|
10
|
+
import { ProgressCloseButton } from "./ProgressCloseButton";
|
|
11
|
+
import { ProgressHeader } from "./ProgressHeader";
|
|
12
|
+
import { ProgressHint } from "./ProgressHint";
|
|
13
|
+
import { ProgressDismissButton } from "./ProgressDismissButton";
|
|
14
14
|
import { GenerationProgressBar } from "./GenerationProgressBar";
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
readonly progress: number;
|
|
18
|
-
readonly icon?: string;
|
|
19
|
-
readonly title?: string;
|
|
20
|
-
readonly message?: string;
|
|
21
|
-
readonly hint?: string;
|
|
22
|
-
readonly dismissLabel?: string;
|
|
23
|
-
readonly onDismiss?: () => void;
|
|
24
|
-
/** Close button in top-right corner for background generation */
|
|
25
|
-
readonly onClose?: () => void;
|
|
26
|
-
/** Hint text shown near close button (e.g., "Continue in background") */
|
|
27
|
-
readonly backgroundHint?: string;
|
|
28
|
-
readonly backgroundColor?: string;
|
|
29
|
-
readonly textColor?: string;
|
|
30
|
-
readonly hintColor?: string;
|
|
31
|
-
readonly progressColor?: string;
|
|
32
|
-
readonly progressBackgroundColor?: string;
|
|
33
|
-
readonly dismissButtonColor?: string;
|
|
34
|
-
}
|
|
15
|
+
import { generationProgressContentStyles } from "./GenerationProgressContent.styles";
|
|
16
|
+
import type { GenerationProgressContentProps } from "./GenerationProgressContent.types";
|
|
35
17
|
|
|
36
18
|
export const GenerationProgressContent: React.FC<
|
|
37
19
|
GenerationProgressContentProps
|
|
@@ -53,55 +35,26 @@ export const GenerationProgressContent: React.FC<
|
|
|
53
35
|
dismissButtonColor,
|
|
54
36
|
}) => {
|
|
55
37
|
const tokens = useAppDesignTokens();
|
|
56
|
-
|
|
57
|
-
const activeTextColor = textColor || tokens.colors.textPrimary;
|
|
58
38
|
const activeBgColor = backgroundColor || tokens.colors.surface;
|
|
59
|
-
const activeHintColor = hintColor || tokens.colors.textTertiary;
|
|
60
39
|
|
|
61
40
|
return (
|
|
62
41
|
<View
|
|
63
42
|
style={[
|
|
64
|
-
|
|
43
|
+
generationProgressContentStyles.modal,
|
|
65
44
|
{
|
|
66
45
|
backgroundColor: activeBgColor,
|
|
67
46
|
borderColor: tokens.colors.borderLight,
|
|
68
47
|
},
|
|
69
48
|
]}
|
|
70
49
|
>
|
|
71
|
-
{
|
|
72
|
-
{onClose && (
|
|
73
|
-
<TouchableOpacity
|
|
74
|
-
style={styles.closeButton}
|
|
75
|
-
onPress={onClose}
|
|
76
|
-
hitSlop={{ top: 10, bottom: 10, left: 10, right: 10 }}
|
|
77
|
-
>
|
|
78
|
-
<AtomicIcon name="close" size="md" color="secondary" />
|
|
79
|
-
</TouchableOpacity>
|
|
80
|
-
)}
|
|
81
|
-
|
|
82
|
-
{icon && (
|
|
83
|
-
<View style={styles.iconContainer}>
|
|
84
|
-
<AtomicIcon name={icon} size="xl" color="primary" />
|
|
85
|
-
</View>
|
|
86
|
-
)}
|
|
87
|
-
|
|
88
|
-
{title && (
|
|
89
|
-
<AtomicText
|
|
90
|
-
type="headlineSmall"
|
|
91
|
-
style={[styles.title, { color: activeTextColor }]}
|
|
92
|
-
>
|
|
93
|
-
{title}
|
|
94
|
-
</AtomicText>
|
|
95
|
-
)}
|
|
50
|
+
{onClose && <ProgressCloseButton onPress={onClose} />}
|
|
96
51
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
</AtomicText>
|
|
104
|
-
)}
|
|
52
|
+
<ProgressHeader
|
|
53
|
+
icon={icon}
|
|
54
|
+
title={title}
|
|
55
|
+
message={message}
|
|
56
|
+
textColor={textColor}
|
|
57
|
+
/>
|
|
105
58
|
|
|
106
59
|
<GenerationProgressBar
|
|
107
60
|
progress={progress}
|
|
@@ -110,107 +63,22 @@ export const GenerationProgressContent: React.FC<
|
|
|
110
63
|
backgroundColor={progressBackgroundColor}
|
|
111
64
|
/>
|
|
112
65
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
</AtomicText>
|
|
120
|
-
)}
|
|
121
|
-
|
|
122
|
-
{/* Background hint - clickable to close and continue in background */}
|
|
123
|
-
{onClose && backgroundHint && (
|
|
124
|
-
<TouchableOpacity
|
|
125
|
-
style={styles.backgroundHintButton}
|
|
126
|
-
onPress={onClose}
|
|
127
|
-
>
|
|
128
|
-
<AtomicText
|
|
129
|
-
type="bodySmall"
|
|
130
|
-
style={[styles.backgroundHintText, { color: tokens.colors.primary }]}
|
|
131
|
-
>
|
|
132
|
-
{backgroundHint}
|
|
133
|
-
</AtomicText>
|
|
134
|
-
</TouchableOpacity>
|
|
135
|
-
)}
|
|
66
|
+
<ProgressHint
|
|
67
|
+
hint={hint}
|
|
68
|
+
backgroundHint={backgroundHint}
|
|
69
|
+
hintColor={hintColor}
|
|
70
|
+
onBackgroundHintPress={onClose}
|
|
71
|
+
/>
|
|
136
72
|
|
|
137
73
|
{onDismiss && (
|
|
138
|
-
<
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
onPress={onDismiss}
|
|
144
|
-
>
|
|
145
|
-
<AtomicText
|
|
146
|
-
type="bodyMedium"
|
|
147
|
-
style={[styles.dismissText, { color: tokens.colors.textInverse }]}
|
|
148
|
-
>
|
|
149
|
-
{dismissLabel || "OK"}
|
|
150
|
-
</AtomicText>
|
|
151
|
-
</TouchableOpacity>
|
|
74
|
+
<ProgressDismissButton
|
|
75
|
+
dismissLabel={dismissLabel}
|
|
76
|
+
dismissButtonColor={dismissButtonColor}
|
|
77
|
+
onDismiss={onDismiss}
|
|
78
|
+
/>
|
|
152
79
|
)}
|
|
153
80
|
</View>
|
|
154
81
|
);
|
|
155
82
|
};
|
|
156
83
|
|
|
157
|
-
|
|
158
|
-
modal: {
|
|
159
|
-
width: "100%",
|
|
160
|
-
maxWidth: 380,
|
|
161
|
-
borderRadius: 24,
|
|
162
|
-
padding: 32,
|
|
163
|
-
borderWidth: 1,
|
|
164
|
-
alignItems: "center",
|
|
165
|
-
position: "relative",
|
|
166
|
-
},
|
|
167
|
-
closeButton: {
|
|
168
|
-
position: "absolute",
|
|
169
|
-
top: 16,
|
|
170
|
-
right: 16,
|
|
171
|
-
width: 32,
|
|
172
|
-
height: 32,
|
|
173
|
-
borderRadius: 16,
|
|
174
|
-
justifyContent: "center",
|
|
175
|
-
alignItems: "center",
|
|
176
|
-
zIndex: 1,
|
|
177
|
-
},
|
|
178
|
-
iconContainer: {
|
|
179
|
-
marginBottom: 20,
|
|
180
|
-
},
|
|
181
|
-
title: {
|
|
182
|
-
fontWeight: "700",
|
|
183
|
-
marginBottom: 8,
|
|
184
|
-
textAlign: "center",
|
|
185
|
-
},
|
|
186
|
-
message: {
|
|
187
|
-
marginBottom: 28,
|
|
188
|
-
textAlign: "center",
|
|
189
|
-
lineHeight: 20,
|
|
190
|
-
},
|
|
191
|
-
hint: {
|
|
192
|
-
textAlign: "center",
|
|
193
|
-
lineHeight: 18,
|
|
194
|
-
paddingHorizontal: 8,
|
|
195
|
-
},
|
|
196
|
-
backgroundHintButton: {
|
|
197
|
-
marginTop: 16,
|
|
198
|
-
paddingVertical: 8,
|
|
199
|
-
paddingHorizontal: 16,
|
|
200
|
-
},
|
|
201
|
-
backgroundHintText: {
|
|
202
|
-
textAlign: "center",
|
|
203
|
-
textDecorationLine: "underline",
|
|
204
|
-
},
|
|
205
|
-
dismissButton: {
|
|
206
|
-
marginTop: 16,
|
|
207
|
-
paddingVertical: 14,
|
|
208
|
-
paddingHorizontal: 32,
|
|
209
|
-
borderRadius: 12,
|
|
210
|
-
minWidth: 140,
|
|
211
|
-
alignItems: "center",
|
|
212
|
-
},
|
|
213
|
-
dismissText: {
|
|
214
|
-
fontWeight: "600",
|
|
215
|
-
},
|
|
216
|
-
});
|
|
84
|
+
export type { GenerationProgressContentProps } from "./GenerationProgressContent.types";
|