@umituz/react-native-ai-generation-content 1.17.0 → 1.17.2

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.
Files changed (156) hide show
  1. package/package.json +13 -14
  2. package/src/domains/creations/domain/entities/Creation.ts +33 -2
  3. package/src/domains/creations/domain/entities/index.ts +1 -1
  4. package/src/domains/creations/domain/types/creation-categories.ts +133 -0
  5. package/src/domains/creations/domain/types/creation-filter.ts +131 -0
  6. package/src/domains/creations/domain/types/creation-types.ts +63 -0
  7. package/src/domains/creations/domain/types/index.ts +44 -0
  8. package/src/domains/creations/domain/utils/creation-helpers.ts +134 -0
  9. package/src/domains/creations/domain/utils/index.ts +8 -0
  10. package/src/domains/creations/domain/utils/preview-helpers.ts +84 -0
  11. package/src/domains/creations/domain/utils/status-helpers.ts +90 -0
  12. package/src/domains/creations/index.ts +95 -21
  13. package/src/domains/creations/infrastructure/repositories/CreationsRepository.ts +14 -1
  14. package/src/domains/creations/presentation/components/CreationActions.tsx +120 -0
  15. package/src/domains/creations/presentation/components/CreationBadges.tsx +111 -0
  16. package/src/domains/creations/presentation/components/CreationCard.tsx +201 -102
  17. package/src/domains/creations/presentation/components/CreationPreview.tsx +117 -0
  18. package/src/domains/creations/presentation/components/CreationsFilterBar.tsx +254 -0
  19. package/src/domains/creations/presentation/components/CreationsGrid.tsx +121 -68
  20. package/src/domains/creations/presentation/components/CreationsHomeCard.tsx +1 -1
  21. package/src/domains/creations/presentation/components/index.ts +23 -3
  22. package/src/domains/creations/presentation/hooks/index.ts +1 -0
  23. package/src/domains/creations/presentation/hooks/useAdvancedFilter.ts +261 -0
  24. package/src/domains/creations/presentation/screens/CreationsGalleryScreen.tsx +8 -6
  25. package/src/domains/face-detection/infrastructure/validators/faceValidator.ts +1 -1
  26. package/src/domains/prompts/infrastructure/services/PromptGenerationService.ts +1 -1
  27. package/src/domains/prompts/presentation/hooks/useFaceSwap.ts +2 -2
  28. package/src/domains/prompts/presentation/hooks/usePromptGeneration.ts +4 -4
  29. package/src/features/ai-hug/domain/index.ts +5 -0
  30. package/src/features/ai-hug/domain/types/ai-hug.types.ts +72 -0
  31. package/src/features/ai-hug/domain/types/index.ts +14 -0
  32. package/src/features/ai-hug/index.ts +27 -0
  33. package/src/features/ai-hug/infrastructure/index.ts +5 -0
  34. package/src/features/ai-hug/infrastructure/services/ai-hug-executor.ts +96 -0
  35. package/src/features/ai-hug/infrastructure/services/index.ts +6 -0
  36. package/src/features/ai-hug/presentation/hooks/index.ts +9 -0
  37. package/src/features/ai-hug/presentation/hooks/useAIHugFeature.ts +157 -0
  38. package/src/features/ai-hug/presentation/index.ts +5 -0
  39. package/src/features/ai-kiss/domain/index.ts +5 -0
  40. package/src/features/ai-kiss/domain/types/ai-kiss.types.ts +72 -0
  41. package/src/features/ai-kiss/domain/types/index.ts +14 -0
  42. package/src/features/ai-kiss/index.ts +27 -0
  43. package/src/features/ai-kiss/infrastructure/index.ts +5 -0
  44. package/src/features/ai-kiss/infrastructure/services/ai-kiss-executor.ts +96 -0
  45. package/src/features/ai-kiss/infrastructure/services/index.ts +6 -0
  46. package/src/features/ai-kiss/presentation/hooks/index.ts +9 -0
  47. package/src/features/ai-kiss/presentation/hooks/useAIKissFeature.ts +157 -0
  48. package/src/features/ai-kiss/presentation/index.ts +5 -0
  49. package/src/features/anime-selfie/domain/index.ts +5 -0
  50. package/src/features/anime-selfie/domain/types/anime-selfie.types.ts +72 -0
  51. package/src/features/anime-selfie/domain/types/index.ts +15 -0
  52. package/src/features/anime-selfie/index.ts +28 -0
  53. package/src/features/anime-selfie/infrastructure/index.ts +5 -0
  54. package/src/features/anime-selfie/infrastructure/services/anime-selfie-executor.ts +95 -0
  55. package/src/features/anime-selfie/infrastructure/services/index.ts +6 -0
  56. package/src/features/anime-selfie/presentation/hooks/index.ts +9 -0
  57. package/src/features/anime-selfie/presentation/hooks/useAnimeSelfieFeature.ts +138 -0
  58. package/src/features/anime-selfie/presentation/index.ts +5 -0
  59. package/src/features/background/domain/types/index.ts +15 -0
  60. package/src/features/background/domain/types/replace-background.types.ts +82 -0
  61. package/src/features/background/index.ts +31 -3
  62. package/src/features/background/infrastructure/index.ts +5 -0
  63. package/src/features/background/infrastructure/services/index.ts +6 -0
  64. package/src/features/background/infrastructure/services/replace-background-executor.ts +95 -0
  65. package/src/features/background/presentation/hooks/index.ts +6 -1
  66. package/src/features/background/presentation/hooks/useReplaceBackgroundFeature.ts +160 -0
  67. package/src/features/face-swap/domain/index.ts +5 -0
  68. package/src/features/face-swap/domain/types/face-swap.types.ts +72 -0
  69. package/src/features/face-swap/domain/types/index.ts +14 -0
  70. package/src/features/face-swap/index.ts +27 -1
  71. package/src/features/face-swap/infrastructure/index.ts +5 -0
  72. package/src/features/face-swap/infrastructure/services/face-swap-executor.ts +96 -0
  73. package/src/features/face-swap/infrastructure/services/index.ts +6 -0
  74. package/src/features/face-swap/presentation/hooks/index.ts +9 -0
  75. package/src/features/face-swap/presentation/hooks/useFaceSwapFeature.ts +157 -0
  76. package/src/features/face-swap/presentation/index.ts +5 -0
  77. package/src/features/image-to-video/domain/index.ts +1 -0
  78. package/src/features/image-to-video/domain/types/image-to-video.types.ts +71 -0
  79. package/src/features/image-to-video/domain/types/index.ts +10 -0
  80. package/src/features/image-to-video/index.ts +27 -0
  81. package/src/features/image-to-video/infrastructure/index.ts +1 -0
  82. package/src/features/image-to-video/infrastructure/services/image-to-video-executor.ts +112 -0
  83. package/src/features/image-to-video/infrastructure/services/index.ts +5 -0
  84. package/src/features/image-to-video/presentation/hooks/index.ts +5 -0
  85. package/src/features/image-to-video/presentation/hooks/useImageToVideoFeature.ts +121 -0
  86. package/src/features/image-to-video/presentation/index.ts +1 -0
  87. package/src/features/photo-restoration/domain/types/index.ts +2 -5
  88. package/src/features/photo-restoration/domain/types/photo-restore.types.ts +14 -0
  89. package/src/features/photo-restoration/index.ts +3 -8
  90. package/src/features/photo-restoration/infrastructure/services/index.ts +1 -6
  91. package/src/features/photo-restoration/infrastructure/services/photo-restore-executor.ts +64 -30
  92. package/src/features/photo-restoration/presentation/hooks/usePhotoRestoreFeature.ts +11 -6
  93. package/src/features/remove-background/domain/index.ts +5 -0
  94. package/src/features/remove-background/domain/types/index.ts +14 -0
  95. package/src/features/remove-background/domain/types/remove-background.types.ts +69 -0
  96. package/src/features/remove-background/index.ts +27 -0
  97. package/src/features/remove-background/infrastructure/index.ts +5 -0
  98. package/src/features/remove-background/infrastructure/services/index.ts +6 -0
  99. package/src/features/remove-background/infrastructure/services/remove-background-executor.ts +95 -0
  100. package/src/features/remove-background/presentation/hooks/index.ts +9 -0
  101. package/src/features/remove-background/presentation/hooks/useRemoveBackgroundFeature.ts +137 -0
  102. package/src/features/remove-background/presentation/index.ts +5 -0
  103. package/src/features/remove-object/domain/index.ts +5 -0
  104. package/src/features/remove-object/domain/types/index.ts +14 -0
  105. package/src/features/remove-object/domain/types/remove-object.types.ts +77 -0
  106. package/src/features/remove-object/index.ts +27 -0
  107. package/src/features/remove-object/infrastructure/index.ts +5 -0
  108. package/src/features/remove-object/infrastructure/services/index.ts +6 -0
  109. package/src/features/remove-object/infrastructure/services/remove-object-executor.ts +99 -0
  110. package/src/features/remove-object/presentation/hooks/index.ts +9 -0
  111. package/src/features/remove-object/presentation/hooks/useRemoveObjectFeature.ts +168 -0
  112. package/src/features/remove-object/presentation/index.ts +5 -0
  113. package/src/features/text-to-image/domain/index.ts +1 -0
  114. package/src/features/text-to-image/domain/types/index.ts +10 -0
  115. package/src/features/text-to-image/domain/types/text-to-image.types.ts +66 -0
  116. package/src/features/text-to-image/index.ts +27 -1
  117. package/src/features/text-to-image/infrastructure/index.ts +1 -0
  118. package/src/features/text-to-image/infrastructure/services/index.ts +5 -0
  119. package/src/features/text-to-image/infrastructure/services/text-to-image-executor.ts +113 -0
  120. package/src/features/text-to-image/presentation/hooks/index.ts +5 -0
  121. package/src/features/text-to-image/presentation/hooks/useTextToImageFeature.ts +111 -0
  122. package/src/features/text-to-image/presentation/index.ts +1 -0
  123. package/src/features/text-to-video/domain/index.ts +1 -0
  124. package/src/features/text-to-video/domain/types/index.ts +10 -0
  125. package/src/features/text-to-video/domain/types/text-to-video.types.ts +65 -0
  126. package/src/features/text-to-video/index.ts +27 -1
  127. package/src/features/text-to-video/infrastructure/index.ts +1 -0
  128. package/src/features/text-to-video/infrastructure/services/index.ts +5 -0
  129. package/src/features/text-to-video/infrastructure/services/text-to-video-executor.ts +108 -0
  130. package/src/features/text-to-video/presentation/hooks/index.ts +5 -0
  131. package/src/features/text-to-video/presentation/hooks/useTextToVideoFeature.ts +111 -0
  132. package/src/features/text-to-video/presentation/index.ts +1 -0
  133. package/src/features/text-to-voice/domain/index.ts +1 -0
  134. package/src/features/text-to-voice/domain/types/index.ts +10 -0
  135. package/src/features/text-to-voice/domain/types/text-to-voice.types.ts +65 -0
  136. package/src/features/text-to-voice/index.ts +27 -0
  137. package/src/features/text-to-voice/infrastructure/index.ts +1 -0
  138. package/src/features/text-to-voice/infrastructure/services/index.ts +5 -0
  139. package/src/features/text-to-voice/infrastructure/services/text-to-voice-executor.ts +111 -0
  140. package/src/features/text-to-voice/presentation/hooks/index.ts +5 -0
  141. package/src/features/text-to-voice/presentation/hooks/useTextToVoiceFeature.ts +105 -0
  142. package/src/features/text-to-voice/presentation/index.ts +1 -0
  143. package/src/features/upscaling/domain/types/index.ts +0 -1
  144. package/src/features/upscaling/domain/types/upscale.types.ts +14 -0
  145. package/src/features/upscaling/index.ts +3 -11
  146. package/src/features/upscaling/infrastructure/services/index.ts +1 -6
  147. package/src/features/upscaling/infrastructure/services/upscale-executor.ts +64 -30
  148. package/src/features/upscaling/presentation/hooks/useUpscaleFeature.ts +12 -7
  149. package/src/index.ts +63 -0
  150. package/src/features/face-swap/domain/entities.ts +0 -48
  151. package/src/features/photo-restoration/domain/types/provider.types.ts +0 -23
  152. package/src/features/photo-restoration/infrastructure/services/photo-restore-provider-registry.ts +0 -77
  153. package/src/features/text-to-image/domain/entities.ts +0 -58
  154. package/src/features/text-to-video/domain/entities.ts +0 -52
  155. package/src/features/upscaling/domain/types/provider.types.ts +0 -23
  156. 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, Image, TouchableOpacity, StyleSheet } from "react-native";
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 { timezoneService } from "@umituz/react-native-timezone";
9
- import type { Creation } from "../../domain/entities/Creation";
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
- import { useCreationsProvider } from "./CreationsProvider";
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
- readonly creation: Creation;
15
- readonly onView?: (creation: Creation) => void;
16
- readonly onShare: (creation: Creation) => void;
17
- readonly onDelete: (creation: Creation) => void;
18
- readonly onFavorite?: (creation: Creation, isFavorite: boolean) => void;
19
- readonly locale?: string;
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
- onView,
25
- onShare,
26
- onDelete,
27
- onFavorite,
28
- locale = "en-US",
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
- const { translatedTypes } = useCreationsProvider();
32
-
33
- const typeConfig = translatedTypes.find((type) => type.id === creation.type);
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 instanceof Date
52
- ? creation.createdAt
53
- : new Date(creation.createdAt);
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 timezoneService.formatDateTime(date, locale, {
98
+ return date.toLocaleDateString(undefined, {
56
99
  month: "short",
57
100
  day: "numeric",
58
- hour: "2-digit",
59
- minute: "2-digit",
101
+ year: "numeric",
60
102
  });
61
- }, [creation.createdAt, locale]);
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
- container: {
67
- flexDirection: "row",
68
- backgroundColor: tokens.colors.surface,
69
- borderRadius: tokens.spacing.md,
162
+ card: {
163
+ borderRadius: 12,
70
164
  overflow: "hidden",
71
- marginBottom: tokens.spacing.md,
165
+ marginBottom: 16,
166
+ backgroundColor: tokens.colors.surface,
72
167
  },
73
- thumbnail: {
74
- width: 100,
75
- height: 100,
168
+ previewContainer: {
169
+ position: "relative",
76
170
  },
77
171
  content: {
78
- flex: 1,
79
- padding: tokens.spacing.md,
80
- justifyContent: "space-between",
172
+ padding: 12,
81
173
  },
82
- typeRow: {
174
+ header: {
83
175
  flexDirection: "row",
84
- alignItems: "center",
85
- gap: tokens.spacing.sm,
176
+ justifyContent: "space-between",
177
+ alignItems: "flex-start",
178
+ marginBottom: 8,
179
+ gap: 8,
86
180
  },
87
- icon: {
88
- fontSize: 20,
181
+ titleContainer: {
182
+ flex: 1,
89
183
  },
90
- typeText: {
91
- ...tokens.typography.bodyMedium,
184
+ title: {
92
185
  fontWeight: "600",
93
- color: tokens.colors.textPrimary,
94
186
  },
95
- dateText: {
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
- <View style={styles.container}>
117
- <Image source={{ uri: creation.uri }} style={styles.thumbnail} />
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.typeRow}>
121
- {icon && <AtomicIcon name={icon} size="sm" color="primary" />}
122
- <AtomicText style={styles.typeText}>{label}</AtomicText>
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
- <AtomicText style={styles.dateText}>{formattedDate}</AtomicText>
125
- </View>
126
- <View style={styles.actions}>
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
- {onFavorite && (
133
- <TouchableOpacity style={styles.actionBtn} onPress={handleFavorite}>
134
- <AtomicIcon
135
- name={creation.isFavorite ? "heart" : "heart-outline"}
136
- size="sm"
137
- color={creation.isFavorite ? "error" : "primary"}
138
- />
139
- </TouchableOpacity>
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
- </View>
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
+ }