@umituz/react-native-ai-generation-content 1.17.275 → 1.17.277

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@umituz/react-native-ai-generation-content",
3
- "version": "1.17.275",
3
+ "version": "1.17.277",
4
4
  "description": "Provider-agnostic AI generation orchestration for React Native with result preview components",
5
5
  "main": "src/index.ts",
6
6
  "types": "src/index.ts",
@@ -27,6 +27,8 @@ export interface CreationsTranslations {
27
27
  readonly statusFilterTitle?: string;
28
28
  readonly mediaFilterTitle?: string;
29
29
  readonly clearFilter?: string;
30
+ readonly resultTitle?: string;
31
+ readonly resultLabel?: string;
30
32
  }
31
33
 
32
34
  export interface CreationsFilterConfig {
@@ -1,4 +1,4 @@
1
- import React, { useMemo, useCallback } from "react";
1
+ import React, { useState, useMemo, useCallback } from "react";
2
2
  import { View, FlatList, RefreshControl, StyleSheet } from "react-native";
3
3
  import {
4
4
  useAppDesignTokens,
@@ -14,7 +14,10 @@ import { useCreations } from "../hooks/useCreations";
14
14
  import { useDeleteCreation } from "../hooks/useDeleteCreation";
15
15
  import { useGalleryFilters } from "../hooks/useGalleryFilters";
16
16
  import { GalleryHeader, CreationCard, GalleryEmptyStates } from "../components";
17
+ import { ResultPreviewScreen } from "../../../result-preview/presentation/components/ResultPreviewScreen";
18
+ import { useResultActions } from "../../../result-preview/presentation/hooks/useResultActions";
17
19
  import { MEDIA_FILTER_OPTIONS, STATUS_FILTER_OPTIONS } from "../../domain/types/creation-filter";
20
+ import { getPreviewUrl } from "../../domain/utils";
18
21
  import type { Creation } from "../../domain/entities/Creation";
19
22
  import type { CreationsConfig } from "../../domain/value-objects/CreationsConfig";
20
23
  import type { ICreationsRepository } from "../../domain/repositories/ICreationsRepository";
@@ -24,11 +27,9 @@ interface CreationsGalleryScreenProps {
24
27
  readonly repository: ICreationsRepository;
25
28
  readonly config: CreationsConfig;
26
29
  readonly t: (key: string) => string;
27
- readonly locale?: string;
28
30
  readonly onEmptyAction?: () => void;
29
31
  readonly emptyActionLabel?: string;
30
32
  readonly showFilter?: boolean;
31
- readonly onViewResult?: (creation: Creation) => void;
32
33
  }
33
34
 
34
35
  export function CreationsGalleryScreen({
@@ -39,15 +40,23 @@ export function CreationsGalleryScreen({
39
40
  onEmptyAction,
40
41
  emptyActionLabel,
41
42
  showFilter = config.showFilter ?? true,
42
- onViewResult,
43
43
  }: CreationsGalleryScreenProps) {
44
44
  const tokens = useAppDesignTokens();
45
45
  const { share } = useSharing();
46
46
  const alert = useAlert();
47
+ const [selectedCreation, setSelectedCreation] = useState<Creation | null>(null);
47
48
 
48
49
  const { data: creations, isLoading, refetch } = useCreations({ userId, repository });
49
50
  const deleteMutation = useDeleteCreation({ userId, repository });
50
51
 
52
+ const selectedImageUrl = selectedCreation ? (getPreviewUrl(selectedCreation.output) || selectedCreation.uri) : undefined;
53
+
54
+ const { isSharing, isSaving, handleDownload, handleShare } = useResultActions({
55
+ imageUrl: selectedImageUrl,
56
+ onSaveSuccess: () => alert.show(AlertType.SUCCESS, AlertMode.TOAST, t("result.saveSuccess"), t("result.saveSuccessMessage")),
57
+ onSaveError: () => alert.show(AlertType.ERROR, AlertMode.TOAST, t("common.error"), t("result.saveError")),
58
+ });
59
+
51
60
  const statusOptions = config.filterConfig?.statusOptions ?? STATUS_FILTER_OPTIONS;
52
61
  const mediaOptions = config.filterConfig?.mediaOptions ?? MEDIA_FILTER_OPTIONS;
53
62
  const showStatusFilter = config.filterConfig?.showStatusFilter ?? true;
@@ -57,7 +66,7 @@ export function CreationsGalleryScreen({
57
66
 
58
67
  useFocusEffect(useCallback(() => { void refetch(); }, [refetch]));
59
68
 
60
- const handleShare = useCallback((c: Creation) => {
69
+ const handleShareCard = useCallback((c: Creation) => {
61
70
  void share(c.uri, { dialogTitle: t("common.share") });
62
71
  }, [share, t]);
63
72
 
@@ -80,6 +89,18 @@ export function CreationsGalleryScreen({
80
89
  })();
81
90
  }, [userId, repository, refetch]);
82
91
 
92
+ const handleCardPress = useCallback((item: Creation) => {
93
+ setSelectedCreation(item);
94
+ }, []);
95
+
96
+ const handleBack = useCallback(() => {
97
+ setSelectedCreation(null);
98
+ }, []);
99
+
100
+ const handleTryAgain = useCallback(() => {
101
+ setSelectedCreation(null);
102
+ }, []);
103
+
83
104
  const filterButtons = useMemo(() => {
84
105
  const buttons = [];
85
106
  if (showStatusFilter) {
@@ -103,27 +124,17 @@ export function CreationsGalleryScreen({
103
124
  return buttons;
104
125
  }, [showStatusFilter, showMediaFilter, filters, t, config.translations]);
105
126
 
106
- const handleCardPress = useCallback((item: Creation) => {
107
- if (__DEV__) {
108
- console.log("[CreationsGalleryScreen] Card pressed", {
109
- creationId: item.id,
110
- hasOnViewResult: !!onViewResult
111
- });
112
- }
113
- onViewResult?.(item);
114
- }, [onViewResult]);
115
-
116
127
  const renderItem = useCallback(({ item }: { item: Creation }) => (
117
128
  <CreationCard
118
129
  creation={item}
119
130
  callbacks={{
120
131
  onPress: () => handleCardPress(item),
121
- onShare: async () => handleShare(item),
132
+ onShare: async () => handleShareCard(item),
122
133
  onDelete: () => handleDelete(item),
123
134
  onFavorite: () => handleFavorite(item, !item.isFavorite),
124
135
  }}
125
136
  />
126
- ), [handleShare, handleDelete, handleFavorite, handleCardPress]);
137
+ ), [handleShareCard, handleDelete, handleFavorite, handleCardPress]);
127
138
 
128
139
  const renderHeader = useMemo(() => {
129
140
  if ((!creations || creations.length === 0) && !isLoading) return null;
@@ -155,6 +166,30 @@ export function CreationsGalleryScreen({
155
166
  />
156
167
  ), [isLoading, creations, filters.isFiltered, tokens, t, config, emptyActionLabel, onEmptyAction, filters.clearAllFilters]);
157
168
 
169
+ // Show result preview when a creation is selected
170
+ if (selectedCreation && selectedImageUrl) {
171
+ return (
172
+ <ResultPreviewScreen
173
+ imageUrl={selectedImageUrl}
174
+ isSaving={isSaving}
175
+ isSharing={isSharing}
176
+ onDownload={handleDownload}
177
+ onShare={handleShare}
178
+ onTryAgain={handleTryAgain}
179
+ onNavigateBack={handleBack}
180
+ translations={{
181
+ title: t(config.translations.resultTitle ?? "result.title"),
182
+ yourResult: t(config.translations.resultLabel ?? "result.yourResult"),
183
+ saveButton: t("result.saveButton"),
184
+ saving: t("result.saving"),
185
+ shareButton: t("result.shareButton"),
186
+ sharing: t("result.sharing"),
187
+ tryAnother: t("result.tryAnother"),
188
+ }}
189
+ />
190
+ );
191
+ }
192
+
158
193
  return (
159
194
  <ScreenLayout scrollable={false}>
160
195
  <FlatList
@@ -163,10 +198,7 @@ export function CreationsGalleryScreen({
163
198
  keyExtractor={(item) => item.id}
164
199
  ListHeaderComponent={renderHeader}
165
200
  ListEmptyComponent={renderEmpty}
166
- contentContainerStyle={[
167
- styles.listContent,
168
- (!filters.filtered || filters.filtered.length === 0) && styles.emptyContent
169
- ]}
201
+ contentContainerStyle={[styles.listContent, (!filters.filtered || filters.filtered.length === 0) && styles.emptyContent]}
170
202
  showsVerticalScrollIndicator={false}
171
203
  refreshControl={<RefreshControl refreshing={isLoading} onRefresh={() => void refetch()} tintColor={tokens.colors.primary} />}
172
204
  />
@@ -177,7 +209,6 @@ export function CreationsGalleryScreen({
177
209
  }
178
210
 
179
211
  const styles = StyleSheet.create({
180
- container: { flex: 1 },
181
212
  header: { borderBottomWidth: 1 },
182
213
  listContent: { paddingHorizontal: 16, paddingTop: 16 },
183
214
  emptyContent: { flexGrow: 1 },