@umituz/react-native-ai-generation-content 1.17.0 → 1.17.1
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 +13 -14
- package/src/domains/creations/domain/entities/Creation.ts +33 -2
- package/src/domains/creations/domain/entities/index.ts +1 -1
- package/src/domains/creations/domain/types/creation-categories.ts +133 -0
- package/src/domains/creations/domain/types/creation-filter.ts +131 -0
- package/src/domains/creations/domain/types/creation-types.ts +63 -0
- package/src/domains/creations/domain/types/index.ts +44 -0
- package/src/domains/creations/domain/utils/creation-helpers.ts +134 -0
- package/src/domains/creations/domain/utils/index.ts +8 -0
- package/src/domains/creations/domain/utils/preview-helpers.ts +84 -0
- package/src/domains/creations/domain/utils/status-helpers.ts +90 -0
- package/src/domains/creations/index.ts +95 -21
- package/src/domains/creations/infrastructure/repositories/CreationsRepository.ts +14 -1
- package/src/domains/creations/presentation/components/CreationActions.tsx +120 -0
- package/src/domains/creations/presentation/components/CreationBadges.tsx +111 -0
- package/src/domains/creations/presentation/components/CreationCard.tsx +201 -102
- package/src/domains/creations/presentation/components/CreationPreview.tsx +117 -0
- package/src/domains/creations/presentation/components/CreationsFilterBar.tsx +254 -0
- package/src/domains/creations/presentation/components/CreationsGrid.tsx +121 -68
- package/src/domains/creations/presentation/components/index.ts +23 -3
- package/src/domains/creations/presentation/hooks/index.ts +1 -0
- package/src/domains/creations/presentation/hooks/useAdvancedFilter.ts +262 -0
- package/src/domains/creations/presentation/screens/CreationsGalleryScreen.tsx +5 -6
- package/src/features/ai-hug/domain/index.ts +5 -0
- package/src/features/ai-hug/domain/types/ai-hug.types.ts +72 -0
- package/src/features/ai-hug/domain/types/index.ts +14 -0
- package/src/features/ai-hug/index.ts +27 -0
- package/src/features/ai-hug/infrastructure/index.ts +5 -0
- package/src/features/ai-hug/infrastructure/services/ai-hug-executor.ts +96 -0
- package/src/features/ai-hug/infrastructure/services/index.ts +6 -0
- package/src/features/ai-hug/presentation/hooks/index.ts +9 -0
- package/src/features/ai-hug/presentation/hooks/useAIHugFeature.ts +157 -0
- package/src/features/ai-hug/presentation/index.ts +5 -0
- package/src/features/ai-kiss/domain/index.ts +5 -0
- package/src/features/ai-kiss/domain/types/ai-kiss.types.ts +72 -0
- package/src/features/ai-kiss/domain/types/index.ts +14 -0
- package/src/features/ai-kiss/index.ts +27 -0
- package/src/features/ai-kiss/infrastructure/index.ts +5 -0
- package/src/features/ai-kiss/infrastructure/services/ai-kiss-executor.ts +96 -0
- package/src/features/ai-kiss/infrastructure/services/index.ts +6 -0
- package/src/features/ai-kiss/presentation/hooks/index.ts +9 -0
- package/src/features/ai-kiss/presentation/hooks/useAIKissFeature.ts +157 -0
- package/src/features/ai-kiss/presentation/index.ts +5 -0
- package/src/features/anime-selfie/domain/index.ts +5 -0
- package/src/features/anime-selfie/domain/types/anime-selfie.types.ts +72 -0
- package/src/features/anime-selfie/domain/types/index.ts +15 -0
- package/src/features/anime-selfie/index.ts +28 -0
- package/src/features/anime-selfie/infrastructure/index.ts +5 -0
- package/src/features/anime-selfie/infrastructure/services/anime-selfie-executor.ts +95 -0
- package/src/features/anime-selfie/infrastructure/services/index.ts +6 -0
- package/src/features/anime-selfie/presentation/hooks/index.ts +9 -0
- package/src/features/anime-selfie/presentation/hooks/useAnimeSelfieFeature.ts +138 -0
- package/src/features/anime-selfie/presentation/index.ts +5 -0
- package/src/features/background/domain/types/index.ts +15 -0
- package/src/features/background/domain/types/replace-background.types.ts +82 -0
- package/src/features/background/index.ts +31 -3
- package/src/features/background/infrastructure/index.ts +5 -0
- package/src/features/background/infrastructure/services/index.ts +6 -0
- package/src/features/background/infrastructure/services/replace-background-executor.ts +95 -0
- package/src/features/background/presentation/hooks/index.ts +6 -1
- package/src/features/background/presentation/hooks/useReplaceBackgroundFeature.ts +160 -0
- package/src/features/face-swap/domain/index.ts +5 -0
- package/src/features/face-swap/domain/types/face-swap.types.ts +72 -0
- package/src/features/face-swap/domain/types/index.ts +14 -0
- package/src/features/face-swap/index.ts +27 -1
- package/src/features/face-swap/infrastructure/index.ts +5 -0
- package/src/features/face-swap/infrastructure/services/face-swap-executor.ts +96 -0
- package/src/features/face-swap/infrastructure/services/index.ts +6 -0
- package/src/features/face-swap/presentation/hooks/index.ts +9 -0
- package/src/features/face-swap/presentation/hooks/useFaceSwapFeature.ts +157 -0
- package/src/features/face-swap/presentation/index.ts +5 -0
- package/src/features/photo-restoration/domain/types/index.ts +2 -5
- package/src/features/photo-restoration/domain/types/photo-restore.types.ts +14 -0
- package/src/features/photo-restoration/index.ts +3 -8
- package/src/features/photo-restoration/infrastructure/services/index.ts +1 -6
- package/src/features/photo-restoration/infrastructure/services/photo-restore-executor.ts +64 -30
- package/src/features/photo-restoration/presentation/hooks/usePhotoRestoreFeature.ts +11 -6
- package/src/features/remove-background/domain/index.ts +5 -0
- package/src/features/remove-background/domain/types/index.ts +14 -0
- package/src/features/remove-background/domain/types/remove-background.types.ts +69 -0
- package/src/features/remove-background/index.ts +27 -0
- package/src/features/remove-background/infrastructure/index.ts +5 -0
- package/src/features/remove-background/infrastructure/services/index.ts +6 -0
- package/src/features/remove-background/infrastructure/services/remove-background-executor.ts +95 -0
- package/src/features/remove-background/presentation/hooks/index.ts +9 -0
- package/src/features/remove-background/presentation/hooks/useRemoveBackgroundFeature.ts +137 -0
- package/src/features/remove-background/presentation/index.ts +5 -0
- package/src/features/remove-object/domain/index.ts +5 -0
- package/src/features/remove-object/domain/types/index.ts +14 -0
- package/src/features/remove-object/domain/types/remove-object.types.ts +77 -0
- package/src/features/remove-object/index.ts +27 -0
- package/src/features/remove-object/infrastructure/index.ts +5 -0
- package/src/features/remove-object/infrastructure/services/index.ts +6 -0
- package/src/features/remove-object/infrastructure/services/remove-object-executor.ts +99 -0
- package/src/features/remove-object/presentation/hooks/index.ts +9 -0
- package/src/features/remove-object/presentation/hooks/useRemoveObjectFeature.ts +168 -0
- package/src/features/remove-object/presentation/index.ts +5 -0
- package/src/features/upscaling/domain/types/index.ts +0 -1
- package/src/features/upscaling/domain/types/upscale.types.ts +14 -0
- package/src/features/upscaling/index.ts +3 -11
- package/src/features/upscaling/infrastructure/services/index.ts +1 -6
- package/src/features/upscaling/infrastructure/services/upscale-executor.ts +64 -30
- package/src/features/upscaling/presentation/hooks/useUpscaleFeature.ts +12 -7
- package/src/index.ts +39 -0
- package/src/types/jsx.d.ts +19 -0
- package/src/features/face-swap/domain/entities.ts +0 -48
- package/src/features/photo-restoration/domain/types/provider.types.ts +0 -23
- package/src/features/photo-restoration/infrastructure/services/photo-restore-provider-registry.ts +0 -77
- package/src/features/upscaling/domain/types/provider.types.ts +0 -23
- package/src/features/upscaling/infrastructure/services/upscale-provider-registry.ts +0 -77
|
@@ -1,151 +1,250 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CreationCard Component
|
|
3
|
+
* Full-featured card for displaying a creation with preview, badges, and actions
|
|
4
|
+
*/
|
|
5
|
+
|
|
1
6
|
import React, { useMemo, useCallback } from "react";
|
|
2
|
-
import { View,
|
|
7
|
+
import { View, StyleSheet, TouchableOpacity, Text } from "react-native";
|
|
3
8
|
import {
|
|
4
9
|
AtomicText,
|
|
5
|
-
AtomicIcon,
|
|
6
10
|
useAppDesignTokens,
|
|
7
11
|
} from "@umituz/react-native-design-system";
|
|
8
|
-
import {
|
|
9
|
-
import
|
|
12
|
+
import { CreationPreview } from "./CreationPreview";
|
|
13
|
+
import { CreationBadges } from "./CreationBadges";
|
|
14
|
+
import { CreationActions, type CreationAction } from "./CreationActions";
|
|
15
|
+
import type { CreationStatus, CreationTypeId } from "../../domain/types";
|
|
16
|
+
import type { CreationOutput } from "../../domain/utils";
|
|
17
|
+
import { getPreviewUrl, getCreationTitle } from "../../domain/utils";
|
|
10
18
|
|
|
11
|
-
|
|
19
|
+
/**
|
|
20
|
+
* Creation data interface for the card
|
|
21
|
+
* Flexible to support both package and app Creation types
|
|
22
|
+
*/
|
|
23
|
+
export interface CreationCardData {
|
|
24
|
+
id: string;
|
|
25
|
+
type: CreationTypeId | string;
|
|
26
|
+
status?: CreationStatus;
|
|
27
|
+
prompt?: string;
|
|
28
|
+
/** Output object for app-style creations */
|
|
29
|
+
output?: CreationOutput;
|
|
30
|
+
/** URI for package-style creations */
|
|
31
|
+
uri?: string;
|
|
32
|
+
provider?: string;
|
|
33
|
+
createdAt: Date | number;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Action callbacks interface
|
|
38
|
+
*/
|
|
39
|
+
export interface CreationCardCallbacks {
|
|
40
|
+
onPress?: (creation: CreationCardData) => void;
|
|
41
|
+
onDownload?: (creation: CreationCardData) => Promise<void>;
|
|
42
|
+
onShare?: (creation: CreationCardData) => Promise<void>;
|
|
43
|
+
onDelete?: (creation: CreationCardData) => void;
|
|
44
|
+
onFavorite?: (creation: CreationCardData) => void;
|
|
45
|
+
onPostToFeed?: (creation: CreationCardData) => void;
|
|
46
|
+
}
|
|
12
47
|
|
|
13
48
|
interface CreationCardProps {
|
|
14
|
-
|
|
15
|
-
readonly
|
|
16
|
-
|
|
17
|
-
readonly
|
|
18
|
-
|
|
19
|
-
readonly
|
|
49
|
+
/** Creation data */
|
|
50
|
+
readonly creation: CreationCardData;
|
|
51
|
+
/** Action callbacks */
|
|
52
|
+
readonly callbacks?: CreationCardCallbacks;
|
|
53
|
+
/** Show badges overlay */
|
|
54
|
+
readonly showBadges?: boolean;
|
|
55
|
+
/** Show action buttons */
|
|
56
|
+
readonly showActions?: boolean;
|
|
57
|
+
/** Custom status text (for i18n) */
|
|
58
|
+
readonly statusText?: string;
|
|
59
|
+
/** Custom type text (for i18n) */
|
|
60
|
+
readonly typeText?: string;
|
|
61
|
+
/** Date formatter function */
|
|
62
|
+
readonly formatDate?: (date: Date) => string;
|
|
63
|
+
/** Is sharing in progress */
|
|
64
|
+
readonly isSharing?: boolean;
|
|
65
|
+
/** Is download available */
|
|
66
|
+
readonly isDownloadAvailable?: boolean;
|
|
67
|
+
/** Can post to feed */
|
|
68
|
+
readonly canPostToFeed?: boolean;
|
|
20
69
|
}
|
|
21
70
|
|
|
22
71
|
export function CreationCard({
|
|
23
72
|
creation,
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
73
|
+
callbacks = {},
|
|
74
|
+
showBadges = true,
|
|
75
|
+
showActions = true,
|
|
76
|
+
statusText,
|
|
77
|
+
typeText,
|
|
78
|
+
formatDate,
|
|
79
|
+
isSharing = false,
|
|
80
|
+
isDownloadAvailable = true,
|
|
81
|
+
canPostToFeed = false,
|
|
29
82
|
}: CreationCardProps) {
|
|
30
83
|
const tokens = useAppDesignTokens();
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
const
|
|
34
|
-
const icon = typeConfig?.icon;
|
|
35
|
-
// Use manual name if available, otherwise use translated label from config
|
|
36
|
-
const label = (creation.metadata?.names as string) || typeConfig?.labelKey || creation.type;
|
|
37
|
-
|
|
38
|
-
const handleView = useCallback(() => onView?.(creation), [creation, onView]);
|
|
39
|
-
const handleShare = useCallback(() => onShare(creation), [creation, onShare]);
|
|
40
|
-
const handleDelete = useCallback(
|
|
41
|
-
() => onDelete(creation),
|
|
42
|
-
[creation, onDelete],
|
|
43
|
-
);
|
|
44
|
-
const handleFavorite = useCallback(
|
|
45
|
-
() => onFavorite?.(creation, !creation.isFavorite),
|
|
46
|
-
[creation, onFavorite],
|
|
47
|
-
);
|
|
84
|
+
// Support both output object and direct uri
|
|
85
|
+
const previewUrl = creation.uri || getPreviewUrl(creation.output);
|
|
86
|
+
const title = getCreationTitle(creation.prompt, creation.type as CreationTypeId);
|
|
48
87
|
|
|
88
|
+
// Format date
|
|
49
89
|
const formattedDate = useMemo(() => {
|
|
50
|
-
const date =
|
|
51
|
-
creation.createdAt
|
|
52
|
-
|
|
53
|
-
|
|
90
|
+
const date = creation.createdAt instanceof Date
|
|
91
|
+
? creation.createdAt
|
|
92
|
+
: new Date(creation.createdAt);
|
|
93
|
+
|
|
94
|
+
if (formatDate) {
|
|
95
|
+
return formatDate(date);
|
|
96
|
+
}
|
|
54
97
|
|
|
55
|
-
return
|
|
98
|
+
return date.toLocaleDateString(undefined, {
|
|
56
99
|
month: "short",
|
|
57
100
|
day: "numeric",
|
|
58
|
-
|
|
59
|
-
minute: "2-digit",
|
|
101
|
+
year: "numeric",
|
|
60
102
|
});
|
|
61
|
-
}, [creation.createdAt,
|
|
103
|
+
}, [creation.createdAt, formatDate]);
|
|
104
|
+
|
|
105
|
+
// Build actions array
|
|
106
|
+
const actions = useMemo<CreationAction[]>(() => {
|
|
107
|
+
const result: CreationAction[] = [];
|
|
108
|
+
|
|
109
|
+
if (callbacks.onDownload && isDownloadAvailable && creation.output) {
|
|
110
|
+
result.push({
|
|
111
|
+
id: "download",
|
|
112
|
+
icon: "Download",
|
|
113
|
+
onPress: () => callbacks.onDownload?.(creation),
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
if (callbacks.onShare) {
|
|
118
|
+
result.push({
|
|
119
|
+
id: "share",
|
|
120
|
+
icon: "share-social",
|
|
121
|
+
loading: isSharing,
|
|
122
|
+
onPress: () => callbacks.onShare?.(creation),
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
if (callbacks.onFavorite) {
|
|
127
|
+
result.push({
|
|
128
|
+
id: "favorite",
|
|
129
|
+
icon: "heart-outline",
|
|
130
|
+
onPress: () => callbacks.onFavorite?.(creation),
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
if (callbacks.onDelete) {
|
|
135
|
+
result.push({
|
|
136
|
+
id: "delete",
|
|
137
|
+
icon: "trash",
|
|
138
|
+
color: "error",
|
|
139
|
+
onPress: () => callbacks.onDelete?.(creation),
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
if (callbacks.onPostToFeed && canPostToFeed) {
|
|
144
|
+
result.push({
|
|
145
|
+
id: "post",
|
|
146
|
+
icon: "Send",
|
|
147
|
+
filled: true,
|
|
148
|
+
onPress: () => callbacks.onPostToFeed?.(creation),
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
return result;
|
|
153
|
+
}, [callbacks, creation, isSharing, isDownloadAvailable, canPostToFeed]);
|
|
154
|
+
|
|
155
|
+
const handlePress = useCallback(() => {
|
|
156
|
+
callbacks.onPress?.(creation);
|
|
157
|
+
}, [callbacks, creation]);
|
|
62
158
|
|
|
63
159
|
const styles = useMemo(
|
|
64
160
|
() =>
|
|
65
161
|
StyleSheet.create({
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
backgroundColor: tokens.colors.surface,
|
|
69
|
-
borderRadius: tokens.spacing.md,
|
|
162
|
+
card: {
|
|
163
|
+
borderRadius: 12,
|
|
70
164
|
overflow: "hidden",
|
|
71
|
-
marginBottom:
|
|
165
|
+
marginBottom: 16,
|
|
166
|
+
backgroundColor: tokens.colors.surface,
|
|
72
167
|
},
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
height: 100,
|
|
168
|
+
previewContainer: {
|
|
169
|
+
position: "relative",
|
|
76
170
|
},
|
|
77
171
|
content: {
|
|
78
|
-
|
|
79
|
-
padding: tokens.spacing.md,
|
|
80
|
-
justifyContent: "space-between",
|
|
172
|
+
padding: 12,
|
|
81
173
|
},
|
|
82
|
-
|
|
174
|
+
header: {
|
|
83
175
|
flexDirection: "row",
|
|
84
|
-
|
|
85
|
-
|
|
176
|
+
justifyContent: "space-between",
|
|
177
|
+
alignItems: "flex-start",
|
|
178
|
+
marginBottom: 8,
|
|
179
|
+
gap: 8,
|
|
86
180
|
},
|
|
87
|
-
|
|
88
|
-
|
|
181
|
+
titleContainer: {
|
|
182
|
+
flex: 1,
|
|
89
183
|
},
|
|
90
|
-
|
|
91
|
-
...tokens.typography.bodyMedium,
|
|
184
|
+
title: {
|
|
92
185
|
fontWeight: "600",
|
|
93
|
-
color: tokens.colors.textPrimary,
|
|
94
186
|
},
|
|
95
|
-
|
|
96
|
-
...tokens.typography.bodySmall,
|
|
97
|
-
color: tokens.colors.textSecondary,
|
|
98
|
-
},
|
|
99
|
-
actions: {
|
|
187
|
+
meta: {
|
|
100
188
|
flexDirection: "row",
|
|
101
|
-
gap: tokens.spacing.sm,
|
|
102
|
-
},
|
|
103
|
-
actionBtn: {
|
|
104
|
-
width: 36,
|
|
105
|
-
height: 36,
|
|
106
|
-
borderRadius: 18,
|
|
107
|
-
backgroundColor: tokens.colors.backgroundSecondary,
|
|
108
|
-
justifyContent: "center",
|
|
109
189
|
alignItems: "center",
|
|
110
190
|
},
|
|
191
|
+
metaText: {
|
|
192
|
+
fontSize: 12,
|
|
193
|
+
color: tokens.colors.textSecondary,
|
|
194
|
+
},
|
|
195
|
+
metaDot: {
|
|
196
|
+
marginHorizontal: 4,
|
|
197
|
+
},
|
|
111
198
|
}),
|
|
112
|
-
[tokens]
|
|
199
|
+
[tokens]
|
|
113
200
|
);
|
|
114
201
|
|
|
115
202
|
return (
|
|
116
|
-
<
|
|
117
|
-
|
|
203
|
+
<TouchableOpacity
|
|
204
|
+
style={styles.card}
|
|
205
|
+
onPress={handlePress}
|
|
206
|
+
activeOpacity={callbacks.onPress ? 0.7 : 1}
|
|
207
|
+
disabled={!callbacks.onPress}
|
|
208
|
+
>
|
|
209
|
+
<View style={styles.previewContainer}>
|
|
210
|
+
<CreationPreview
|
|
211
|
+
uri={previewUrl}
|
|
212
|
+
status={creation.status || "completed"}
|
|
213
|
+
type={creation.type as CreationTypeId}
|
|
214
|
+
/>
|
|
215
|
+
{showBadges && creation.status && (
|
|
216
|
+
<CreationBadges
|
|
217
|
+
status={creation.status}
|
|
218
|
+
type={creation.type as CreationTypeId}
|
|
219
|
+
statusText={statusText}
|
|
220
|
+
typeText={typeText}
|
|
221
|
+
/>
|
|
222
|
+
)}
|
|
223
|
+
</View>
|
|
224
|
+
|
|
118
225
|
<View style={styles.content}>
|
|
119
|
-
<View>
|
|
120
|
-
<View style={styles.
|
|
121
|
-
|
|
122
|
-
|
|
226
|
+
<View style={styles.header}>
|
|
227
|
+
<View style={styles.titleContainer}>
|
|
228
|
+
<AtomicText type="bodyMedium" style={styles.title} numberOfLines={2}>
|
|
229
|
+
{title}
|
|
230
|
+
</AtomicText>
|
|
123
231
|
</View>
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
{onView && (
|
|
128
|
-
<TouchableOpacity style={styles.actionBtn} onPress={handleView}>
|
|
129
|
-
<AtomicIcon name="eye" size="sm" color="primary" />
|
|
130
|
-
</TouchableOpacity>
|
|
232
|
+
|
|
233
|
+
{showActions && actions.length > 0 && (
|
|
234
|
+
<CreationActions actions={actions} size="md" />
|
|
131
235
|
)}
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
236
|
+
</View>
|
|
237
|
+
|
|
238
|
+
<View style={styles.meta}>
|
|
239
|
+
<Text style={styles.metaText}>{formattedDate}</Text>
|
|
240
|
+
{creation.provider && (
|
|
241
|
+
<>
|
|
242
|
+
<Text style={[styles.metaText, styles.metaDot]}>•</Text>
|
|
243
|
+
<Text style={styles.metaText}>{creation.provider}</Text>
|
|
244
|
+
</>
|
|
140
245
|
)}
|
|
141
|
-
<TouchableOpacity style={styles.actionBtn} onPress={handleShare}>
|
|
142
|
-
<AtomicIcon name="share-social" size="sm" color="primary" />
|
|
143
|
-
</TouchableOpacity>
|
|
144
|
-
<TouchableOpacity style={styles.actionBtn} onPress={handleDelete}>
|
|
145
|
-
<AtomicIcon name="trash" size="sm" color="error" />
|
|
146
|
-
</TouchableOpacity>
|
|
147
246
|
</View>
|
|
148
247
|
</View>
|
|
149
|
-
</
|
|
248
|
+
</TouchableOpacity>
|
|
150
249
|
);
|
|
151
250
|
}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CreationPreview Component
|
|
3
|
+
* Displays creation preview image with loading/placeholder states
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import React, { useMemo } from "react";
|
|
7
|
+
import { View, StyleSheet, Image, ActivityIndicator } from "react-native";
|
|
8
|
+
import {
|
|
9
|
+
useAppDesignTokens,
|
|
10
|
+
AtomicIcon,
|
|
11
|
+
} from "@umituz/react-native-design-system";
|
|
12
|
+
import type { CreationStatus, CreationTypeId } from "../../domain/types";
|
|
13
|
+
import { isInProgress } from "../../domain/utils";
|
|
14
|
+
import { getTypeIcon } from "../../domain/utils";
|
|
15
|
+
|
|
16
|
+
interface CreationPreviewProps {
|
|
17
|
+
/** Preview image URL */
|
|
18
|
+
readonly uri?: string | null;
|
|
19
|
+
/** Creation status */
|
|
20
|
+
readonly status?: CreationStatus;
|
|
21
|
+
/** Creation type for placeholder icon */
|
|
22
|
+
readonly type?: CreationTypeId;
|
|
23
|
+
/** Aspect ratio (default: 16/9) */
|
|
24
|
+
readonly aspectRatio?: number;
|
|
25
|
+
/** Custom height (overrides aspectRatio) */
|
|
26
|
+
readonly height?: number;
|
|
27
|
+
/** Show loading indicator when in progress */
|
|
28
|
+
readonly showLoadingIndicator?: boolean;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function CreationPreview({
|
|
32
|
+
uri,
|
|
33
|
+
status = "completed",
|
|
34
|
+
type = "text-to-image",
|
|
35
|
+
aspectRatio = 16 / 9,
|
|
36
|
+
height,
|
|
37
|
+
showLoadingIndicator = true,
|
|
38
|
+
}: CreationPreviewProps) {
|
|
39
|
+
const tokens = useAppDesignTokens();
|
|
40
|
+
const inProgress = isInProgress(status);
|
|
41
|
+
const typeIcon = getTypeIcon(type);
|
|
42
|
+
const hasPreview = !!uri && !inProgress;
|
|
43
|
+
|
|
44
|
+
const styles = useMemo(
|
|
45
|
+
() =>
|
|
46
|
+
StyleSheet.create({
|
|
47
|
+
container: {
|
|
48
|
+
width: "100%",
|
|
49
|
+
aspectRatio: height ? undefined : aspectRatio,
|
|
50
|
+
height: height,
|
|
51
|
+
backgroundColor: tokens.colors.backgroundSecondary,
|
|
52
|
+
position: "relative",
|
|
53
|
+
overflow: "hidden",
|
|
54
|
+
},
|
|
55
|
+
image: {
|
|
56
|
+
width: "100%",
|
|
57
|
+
height: "100%",
|
|
58
|
+
},
|
|
59
|
+
placeholder: {
|
|
60
|
+
width: "100%",
|
|
61
|
+
height: "100%",
|
|
62
|
+
justifyContent: "center",
|
|
63
|
+
alignItems: "center",
|
|
64
|
+
},
|
|
65
|
+
loadingContainer: {
|
|
66
|
+
width: "100%",
|
|
67
|
+
height: "100%",
|
|
68
|
+
justifyContent: "center",
|
|
69
|
+
alignItems: "center",
|
|
70
|
+
},
|
|
71
|
+
loadingIcon: {
|
|
72
|
+
width: 64,
|
|
73
|
+
height: 64,
|
|
74
|
+
borderRadius: 32,
|
|
75
|
+
backgroundColor: tokens.colors.primary + "20",
|
|
76
|
+
justifyContent: "center",
|
|
77
|
+
alignItems: "center",
|
|
78
|
+
},
|
|
79
|
+
}),
|
|
80
|
+
[tokens, aspectRatio, height]
|
|
81
|
+
);
|
|
82
|
+
|
|
83
|
+
// Show loading state
|
|
84
|
+
if (inProgress && showLoadingIndicator) {
|
|
85
|
+
return (
|
|
86
|
+
<View style={styles.container}>
|
|
87
|
+
<View style={styles.loadingContainer}>
|
|
88
|
+
<View style={styles.loadingIcon}>
|
|
89
|
+
<ActivityIndicator size="large" color={tokens.colors.primary} />
|
|
90
|
+
</View>
|
|
91
|
+
</View>
|
|
92
|
+
</View>
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// Show image preview
|
|
97
|
+
if (hasPreview) {
|
|
98
|
+
return (
|
|
99
|
+
<View style={styles.container}>
|
|
100
|
+
<Image
|
|
101
|
+
source={{ uri }}
|
|
102
|
+
style={styles.image}
|
|
103
|
+
resizeMode="cover"
|
|
104
|
+
/>
|
|
105
|
+
</View>
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// Show placeholder
|
|
110
|
+
return (
|
|
111
|
+
<View style={styles.container}>
|
|
112
|
+
<View style={styles.placeholder}>
|
|
113
|
+
<AtomicIcon name={typeIcon} color="secondary" size="xl" />
|
|
114
|
+
</View>
|
|
115
|
+
</View>
|
|
116
|
+
);
|
|
117
|
+
}
|