@umituz/react-native-ai-generation-content 1.12.21 → 1.12.23

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 (81) hide show
  1. package/package.json +33 -15
  2. package/src/domains/content-moderation/infrastructure/services/content-moderation.service.ts +4 -32
  3. package/src/domains/content-moderation/infrastructure/services/moderators/base.moderator.ts +1 -1
  4. package/src/domains/face-detection/infrastructure/validators/faceValidator.ts +1 -1
  5. package/src/domains/face-detection/presentation/components/FaceValidationStatus.tsx +3 -3
  6. package/src/domains/feature-background/presentation/components/BackgroundFeature.tsx +5 -4
  7. package/src/domains/feature-background/presentation/components/ComparisonSlider.tsx +45 -51
  8. package/src/domains/feature-background/presentation/components/ErrorDisplay.tsx +5 -3
  9. package/src/domains/feature-background/presentation/components/ModeSelector.tsx +2 -2
  10. package/src/domains/feature-background/presentation/hooks/useBackgroundFeature.ts +3 -2
  11. package/src/domains/prompts/domain/entities/FuturePredictionConfig.ts +2 -1
  12. package/src/domains/prompts/domain/entities/GeneratedPrompt.ts +0 -1
  13. package/src/domains/prompts/domain/repositories/IAIPromptServices.ts +6 -12
  14. package/src/domains/prompts/infrastructure/repositories/PromptHistoryRepository.ts +42 -42
  15. package/src/domains/prompts/infrastructure/repositories/TemplateRepository.ts +42 -42
  16. package/src/domains/prompts/infrastructure/services/BackgroundRemovalService.ts +7 -7
  17. package/src/domains/prompts/infrastructure/services/ColorizationService.ts +7 -7
  18. package/src/domains/prompts/infrastructure/services/FaceSwapService.ts +19 -20
  19. package/src/domains/prompts/infrastructure/services/FuturePredictionService.ts +11 -31
  20. package/src/domains/prompts/infrastructure/services/ImageEnhancementService.ts +7 -7
  21. package/src/domains/prompts/infrastructure/services/PhotoRestorationService.ts +7 -7
  22. package/src/domains/prompts/infrastructure/services/PromptGenerationService.ts +13 -13
  23. package/src/domains/prompts/infrastructure/services/StyleTransferService.ts +8 -8
  24. package/src/domains/prompts/infrastructure/services/TextGenerationService.ts +7 -7
  25. package/src/domains/prompts/presentation/hooks/useAIServices.ts +30 -28
  26. package/src/domains/prompts/presentation/hooks/useFaceSwap.ts +1 -2
  27. package/src/domains/prompts/presentation/hooks/usePromptGeneration.ts +4 -5
  28. package/src/domains/prompts/presentation/hooks/useStyleTransfer.ts +1 -1
  29. package/src/domains/prompts/presentation/hooks/useTemplateRepository.ts +3 -3
  30. package/src/domains/prompts/presentation/theme/utils.ts +1 -1
  31. package/src/index.ts +0 -5
  32. package/src/infrastructure/utils/status-checker.util.ts +4 -4
  33. package/src/infrastructure/wrappers/synchronous-generation.wrapper.ts +3 -3
  34. package/src/presentation/components/result/GenerationResultContent.tsx +21 -22
  35. package/src/presentation/components/result/ResultActions.tsx +51 -52
  36. package/src/presentation/components/result/ResultHeader.tsx +24 -25
  37. package/src/presentation/components/result/ResultImageCard.tsx +19 -20
  38. package/src/presentation/components/result/ResultStoryCard.tsx +23 -24
  39. package/src/presentation/hooks/photo-generation.types.ts +4 -4
  40. package/src/presentation/hooks/usePhotoGeneration.ts +18 -13
  41. package/src/domains/creations/application/services/CreationsService.ts +0 -72
  42. package/src/domains/creations/domain/entities/Creation.ts +0 -54
  43. package/src/domains/creations/domain/entities/index.ts +0 -6
  44. package/src/domains/creations/domain/repositories/ICreationsRepository.ts +0 -25
  45. package/src/domains/creations/domain/repositories/index.ts +0 -5
  46. package/src/domains/creations/domain/services/ICreationsStorageService.ts +0 -13
  47. package/src/domains/creations/domain/value-objects/CreationsConfig.ts +0 -77
  48. package/src/domains/creations/domain/value-objects/index.ts +0 -12
  49. package/src/domains/creations/index.ts +0 -84
  50. package/src/domains/creations/infrastructure/adapters/createRepository.ts +0 -54
  51. package/src/domains/creations/infrastructure/adapters/index.ts +0 -5
  52. package/src/domains/creations/infrastructure/repositories/CreationsRepository.ts +0 -263
  53. package/src/domains/creations/infrastructure/repositories/index.ts +0 -8
  54. package/src/domains/creations/infrastructure/services/CreationsStorageService.ts +0 -48
  55. package/src/domains/creations/presentation/components/CreationCard.tsx +0 -196
  56. package/src/domains/creations/presentation/components/CreationDetail/DetailActions.tsx +0 -76
  57. package/src/domains/creations/presentation/components/CreationDetail/DetailHeader.tsx +0 -81
  58. package/src/domains/creations/presentation/components/CreationDetail/DetailImage.tsx +0 -41
  59. package/src/domains/creations/presentation/components/CreationDetail/DetailStory.tsx +0 -67
  60. package/src/domains/creations/presentation/components/CreationDetail/index.ts +0 -4
  61. package/src/domains/creations/presentation/components/CreationImageViewer.tsx +0 -101
  62. package/src/domains/creations/presentation/components/CreationThumbnail.tsx +0 -63
  63. package/src/domains/creations/presentation/components/CreationsGalleryEmptyState.tsx +0 -77
  64. package/src/domains/creations/presentation/components/CreationsGrid.tsx +0 -87
  65. package/src/domains/creations/presentation/components/CreationsHomeCard.tsx +0 -176
  66. package/src/domains/creations/presentation/components/EmptyState.tsx +0 -75
  67. package/src/domains/creations/presentation/components/FilterBottomSheet.tsx +0 -157
  68. package/src/domains/creations/presentation/components/FilterChips.tsx +0 -105
  69. package/src/domains/creations/presentation/components/GalleryHeader.tsx +0 -157
  70. package/src/domains/creations/presentation/components/index.ts +0 -20
  71. package/src/domains/creations/presentation/hooks/index.ts +0 -9
  72. package/src/domains/creations/presentation/hooks/useCreations.ts +0 -33
  73. package/src/domains/creations/presentation/hooks/useCreationsFilter.ts +0 -90
  74. package/src/domains/creations/presentation/hooks/useDeleteCreation.ts +0 -51
  75. package/src/domains/creations/presentation/hooks/useDeleteMultipleCreations.ts +0 -57
  76. package/src/domains/creations/presentation/hooks/useToggleFavorite.ts +0 -59
  77. package/src/domains/creations/presentation/screens/CreationDetailScreen.tsx +0 -71
  78. package/src/domains/creations/presentation/screens/CreationsGalleryScreen.tsx +0 -264
  79. package/src/domains/creations/presentation/screens/index.ts +0 -5
  80. package/src/domains/creations/presentation/utils/filterUtils.ts +0 -52
  81. package/src/domains/creations/types.d.ts +0 -107
@@ -1,26 +1,26 @@
1
1
  import { useState, useCallback } from 'react';
2
- import type {
2
+ import type {
3
3
  FaceSwapConfig
4
4
  } from '../../domain/entities/FaceSwapConfig';
5
- import type {
5
+ import type {
6
6
  PhotoRestorationConfig
7
7
  } from '../../domain/entities/PhotoRestorationConfig';
8
- import type {
8
+ import type {
9
9
  ImageEnhancementConfig
10
10
  } from '../../domain/entities/ImageEnhancementConfig';
11
- import type {
11
+ import type {
12
12
  StyleTransferConfig
13
13
  } from '../../domain/entities/StyleTransferConfig';
14
- import type {
14
+ import type {
15
15
  BackgroundRemovalConfig
16
16
  } from '../../domain/entities/BackgroundRemovalConfig';
17
- import type {
17
+ import type {
18
18
  TextGenerationConfig
19
19
  } from '../../domain/entities/TextGenerationConfig';
20
- import type {
20
+ import type {
21
21
  ColorizationConfig
22
22
  } from '../../domain/entities/ColorizationConfig';
23
- import type {
23
+ import type {
24
24
  IFaceSwapService,
25
25
  IPhotoRestorationService,
26
26
  IImageEnhancementService,
@@ -34,8 +34,10 @@ import type { IPromptHistoryRepository } from '../../domain/repositories/IPrompt
34
34
  import type { GeneratedPrompt } from '../../domain/entities/GeneratedPrompt';
35
35
  import { createGeneratedPrompt } from '../../domain/entities/GeneratedPrompt';
36
36
  import { useAsyncState } from './useAsyncState';
37
+ import type { AIPromptResult } from '../../domain/entities/types';
38
+ import type { AIPromptTemplate } from '../../domain/entities/AIPromptTemplate';
37
39
 
38
- export type AIConfig =
40
+ export type AIConfig =
39
41
  | { type: 'face-swap'; config: FaceSwapConfig }
40
42
  | { type: 'photo-restoration'; config: PhotoRestorationConfig }
41
43
  | { type: 'image-enhancement'; config: ImageEnhancementConfig }
@@ -86,11 +88,11 @@ export const useAIServices = (
86
88
  const processRequest = useCallback(async (aiConfig: AIConfig): Promise<void> => {
87
89
  clearError();
88
90
  setCurrentService(aiConfig.type);
89
-
91
+
90
92
  try {
91
- let templateResult;
92
- let promptResult;
93
-
93
+ let templateResult: AIPromptResult<AIPromptTemplate> | undefined;
94
+ let promptResult: AIPromptResult<string> | undefined;
95
+
94
96
  switch (aiConfig.type) {
95
97
  case 'face-swap':
96
98
  templateResult = await services.faceSwap.generateTemplate(aiConfig.config);
@@ -98,74 +100,74 @@ export const useAIServices = (
98
100
  promptResult = await services.faceSwap.generatePrompt(templateResult.data, aiConfig.config);
99
101
  }
100
102
  break;
101
-
103
+
102
104
  case 'photo-restoration':
103
105
  templateResult = await services.photoRestoration.generateTemplate(aiConfig.config);
104
106
  if (templateResult.success && templateResult.data) {
105
107
  promptResult = await services.photoRestoration.generatePrompt(templateResult.data, aiConfig.config);
106
108
  }
107
109
  break;
108
-
110
+
109
111
  case 'image-enhancement':
110
112
  templateResult = await services.imageEnhancement.generateTemplate(aiConfig.config);
111
113
  if (templateResult.success && templateResult.data) {
112
114
  promptResult = await services.imageEnhancement.generatePrompt(templateResult.data, aiConfig.config);
113
115
  }
114
116
  break;
115
-
117
+
116
118
  case 'style-transfer':
117
119
  templateResult = await services.styleTransfer.generateTemplate(aiConfig.config);
118
120
  if (templateResult.success && templateResult.data) {
119
121
  promptResult = await services.styleTransfer.generatePrompt(templateResult.data, aiConfig.config);
120
122
  }
121
123
  break;
122
-
124
+
123
125
  case 'background-removal':
124
126
  templateResult = await services.backgroundRemoval.generateTemplate(aiConfig.config);
125
127
  if (templateResult.success && templateResult.data) {
126
128
  promptResult = await services.backgroundRemoval.generatePrompt(templateResult.data, aiConfig.config);
127
129
  }
128
130
  break;
129
-
131
+
130
132
  case 'text-generation':
131
133
  templateResult = await services.textGeneration.generateTemplate(aiConfig.config);
132
134
  if (templateResult.success && templateResult.data) {
133
135
  promptResult = await services.textGeneration.generatePrompt(templateResult.data, aiConfig.config);
134
136
  }
135
137
  break;
136
-
138
+
137
139
  case 'colorization':
138
140
  templateResult = await services.colorization.generateTemplate(aiConfig.config);
139
141
  if (templateResult.success && templateResult.data) {
140
142
  promptResult = await services.colorization.generatePrompt(templateResult.data, aiConfig.config);
141
143
  }
142
144
  break;
143
-
145
+
144
146
  default:
145
147
  setError('Unknown AI service type');
146
148
  return;
147
149
  }
148
-
150
+
149
151
  if (!templateResult?.success || !templateResult.data) {
150
152
  setError('Failed to generate template');
151
153
  return;
152
154
  }
153
-
154
- if (!promptResult?.success) {
155
+
156
+ if (!promptResult?.success || !promptResult.data) {
155
157
  setError('Failed to generate prompt');
156
158
  return;
157
159
  }
158
-
160
+
159
161
  const newPrompt = createGeneratedPrompt({
160
162
  templateId: templateResult.data.id,
161
163
  generatedText: promptResult.data,
162
164
  variables: aiConfig.config as unknown as Record<string, unknown>,
163
165
  });
164
-
166
+
165
167
  await repositories.history.save(newPrompt);
166
168
  setGeneratedPrompt(newPrompt);
167
-
168
- } catch (error) {
169
+
170
+ } catch {
169
171
  setError('An unexpected error occurred');
170
172
  } finally {
171
173
  setCurrentService(null);
@@ -182,7 +184,7 @@ export const useAIServices = (
182
184
  default:
183
185
  return [];
184
186
  }
185
- } catch (error) {
187
+ } catch {
186
188
  setError('Failed to load available styles');
187
189
  return [];
188
190
  }
@@ -3,7 +3,6 @@ import type { FaceSwapConfig, FaceSwapGenerationResult } from '../../domain/enti
3
3
  import type { IFaceSwapService } from '../../domain/repositories/IAIPromptServices';
4
4
  import type { ITemplateRepository } from '../../domain/repositories/ITemplateRepository';
5
5
  import type { IPromptHistoryRepository } from '../../domain/repositories/IPromptHistoryRepository';
6
- import type { GeneratedPrompt } from '../../domain/entities/GeneratedPrompt';
7
6
  import { createGeneratedPrompt } from '../../domain/entities/GeneratedPrompt';
8
7
  import { useAsyncState } from './useAsyncState';
9
8
 
@@ -35,7 +34,7 @@ export const useFaceSwap = (
35
34
 
36
35
  const generateFaceSwapPrompt = useCallback(async (config: FaceSwapConfig): Promise<void> => {
37
36
  clearError();
38
-
37
+
39
38
  try {
40
39
  const templateResult = await faceSwapService.generateTemplate(config);
41
40
  if (!templateResult.success || !templateResult.data) {
@@ -1,5 +1,4 @@
1
1
  import { useState, useCallback } from 'react';
2
- import type { AIPromptTemplate } from '../../domain/entities/AIPromptTemplate';
3
2
  import type { IPromptGenerationService } from '../../domain/repositories/IAIPromptServices';
4
3
  import type { ITemplateRepository } from '../../domain/repositories/ITemplateRepository';
5
4
  import type { IPromptHistoryRepository } from '../../domain/repositories/IPromptHistoryRepository';
@@ -43,7 +42,7 @@ export const usePromptGeneration = (
43
42
  const generatePrompt = useCallback(
44
43
  async (templateId: string, variables: Record<string, unknown>): Promise<void> => {
45
44
  clearError();
46
-
45
+
47
46
  try {
48
47
  const templateResult = await templateRepository.findById(templateId);
49
48
  if (!templateResult.success || !templateResult.data) {
@@ -69,8 +68,8 @@ export const usePromptGeneration = (
69
68
 
70
69
  await historyRepository.save(newPrompt);
71
70
  setGeneratedPrompt(newPrompt);
72
-
73
- await loadHistory(50);
71
+
72
+ void loadHistory(50);
74
73
  } catch (error) {
75
74
  setError('An unexpected error occurred');
76
75
  }
@@ -110,7 +109,7 @@ export const usePromptGeneration = (
110
109
  clearError();
111
110
  try {
112
111
  await historyRepository.save(prompt);
113
- await loadHistory(50);
112
+ void loadHistory(50);
114
113
  } catch (error) {
115
114
  setError('Failed to save to history');
116
115
  }
@@ -109,7 +109,7 @@ export const useStyleTransfer = (
109
109
  }, [setResult, clearError]);
110
110
 
111
111
  useEffect(() => {
112
- getAvailableStyles();
112
+ void getAvailableStyles();
113
113
  }, [getAvailableStyles]);
114
114
 
115
115
  return {
@@ -1,6 +1,6 @@
1
1
  import { useState, useCallback } from 'react';
2
2
  import type { AIPromptTemplate } from '../../domain/entities/AIPromptTemplate';
3
- import type { AIPromptCategory, AIPromptResult } from '../../domain/entities/types';
3
+ import type { AIPromptCategory } from '../../domain/entities/types';
4
4
  import type { ITemplateRepository } from '../../domain/repositories/ITemplateRepository';
5
5
  import { useAsyncState } from './useAsyncState';
6
6
 
@@ -77,7 +77,7 @@ export const useTemplateRepository = (
77
77
  const result = await repository.save(template);
78
78
 
79
79
  if (result.success) {
80
- loadAllTemplates();
80
+ void loadAllTemplates();
81
81
  } else {
82
82
  setError(('message' in result && result.message) || 'Failed to save template');
83
83
  }
@@ -91,7 +91,7 @@ export const useTemplateRepository = (
91
91
  if (currentTemplate?.id === id) {
92
92
  setCurrentTemplate(null);
93
93
  }
94
- loadAllTemplates();
94
+ void loadAllTemplates();
95
95
  } else {
96
96
  setError(('message' in result && result.message) || 'Failed to delete template');
97
97
  }
@@ -1,7 +1,7 @@
1
1
  import type { Theme } from './types';
2
2
  import { useTheme } from './theme';
3
3
 
4
- export const createStyleSheet = <T extends Record<string, any>>(
4
+ export const createStyleSheet = <T extends Record<string, unknown>>(
5
5
  styles: (theme: Theme) => T
6
6
  ): T => {
7
7
  const theme = useTheme();
package/src/index.ts CHANGED
@@ -234,11 +234,6 @@ export * from "./domains/prompts";
234
234
 
235
235
  export * from "./domains/content-moderation";
236
236
 
237
- // =============================================================================
238
- // DOMAINS - AI Creations
239
- // =============================================================================
240
-
241
- export * from "./domains/creations";
242
237
 
243
238
  // =============================================================================
244
239
  // DOMAINS - Face Detection
@@ -34,7 +34,7 @@ export function checkStatusForErrors(
34
34
  const logs = Array.isArray((status as JobStatus)?.logs)
35
35
  ? (status as JobStatus).logs
36
36
  : [];
37
- const errorLogs = (logs as AILogEntry[]).filter((log) => {
37
+ const errorLogs = logs.filter((log) => {
38
38
  const level = String(log?.level || "").toUpperCase();
39
39
  return level === "ERROR" || level === "FATAL";
40
40
  });
@@ -44,9 +44,9 @@ export function checkStatusForErrors(
44
44
  const errorLogMessage =
45
45
  errorLogs.length > 0
46
46
  ? (errorLogs[0] as AILogEntry & { text?: string; content?: string })
47
- ?.message ||
48
- (errorLogs[0] as AILogEntry & { text?: string })?.text ||
49
- (errorLogs[0] as AILogEntry & { content?: string })?.content
47
+ ?.message ||
48
+ (errorLogs[0] as AILogEntry & { text?: string })?.text ||
49
+ (errorLogs[0] as AILogEntry & { content?: string })?.content
50
50
  : undefined;
51
51
 
52
52
  // Combine error messages
@@ -13,13 +13,13 @@ export interface SynchronousGenerationInput {
13
13
  userId?: string;
14
14
  type?: string;
15
15
  languageCode?: string;
16
- metadata?: Record<string, any>;
16
+ metadata?: Record<string, unknown>;
17
17
  }
18
18
 
19
- export interface SynchronousGenerationConfig<T = any> {
19
+ export interface SynchronousGenerationConfig<T = unknown> {
20
20
  checkCredits?: (userId: string, type: string) => Promise<boolean>;
21
21
  deductCredits?: (userId: string, type: string) => Promise<void>;
22
- execute: (prompt: string, metadata?: Record<string, any>) => Promise<T>;
22
+ execute: (prompt: string, metadata?: Record<string, unknown>) => Promise<T>;
23
23
  }
24
24
 
25
25
  export async function generateSynchronously<T = string>(
@@ -3,8 +3,9 @@
3
3
  * Composition of result components for CelebrationModal
4
4
  */
5
5
 
6
- import React from "react";
7
- import { ScrollView, StyleSheet, Dimensions } from "react-native";
6
+ import * as React from "react";
7
+ import { useMemo } from "react";
8
+ import { ScrollView, StyleSheet, Dimensions, type ViewStyle, type StyleProp } from "react-native";
8
9
  import { Animated } from "@umituz/react-native-design-system";
9
10
  import { useAppDesignTokens } from "@umituz/react-native-design-system";
10
11
  import { ResultHeader } from "./ResultHeader";
@@ -35,7 +36,7 @@ export interface GenerationResultContentProps {
35
36
  retry: string;
36
37
  aiGenerated: string;
37
38
  };
38
- modalStyle?: any;
39
+ modalStyle?: StyleProp<ViewStyle>;
39
40
  }
40
41
 
41
42
  export const GenerationResultContent: React.FC<GenerationResultContentProps> = ({
@@ -49,7 +50,23 @@ export const GenerationResultContent: React.FC<GenerationResultContentProps> = (
49
50
  modalStyle,
50
51
  }) => {
51
52
  const tokens = useAppDesignTokens();
52
- const styles = createStyles(tokens);
53
+
54
+ const styles = useMemo(() => StyleSheet.create({
55
+ container: {
56
+ width: width - 40,
57
+ maxHeight: "90%",
58
+ backgroundColor: tokens.colors.backgroundPrimary,
59
+ borderRadius: 28,
60
+ overflow: "hidden",
61
+ },
62
+ scrollView: {
63
+ flex: 1,
64
+ },
65
+ scrollContent: {
66
+ paddingTop: 24,
67
+ paddingBottom: 20,
68
+ },
69
+ }), [tokens]);
53
70
 
54
71
  return (
55
72
  <Animated.View style={[styles.container, modalStyle]}>
@@ -73,21 +90,3 @@ export const GenerationResultContent: React.FC<GenerationResultContentProps> = (
73
90
  </Animated.View>
74
91
  );
75
92
  };
76
-
77
- const createStyles = (tokens: any) =>
78
- StyleSheet.create({
79
- container: {
80
- width: width - 40,
81
- maxHeight: "90%",
82
- backgroundColor: tokens.colors.backgroundPrimary,
83
- borderRadius: 28,
84
- overflow: "hidden",
85
- },
86
- scrollView: {
87
- flex: 1,
88
- },
89
- scrollContent: {
90
- paddingTop: 24,
91
- paddingBottom: 20,
92
- },
93
- });
@@ -3,7 +3,8 @@
3
3
  * Action buttons for generation results
4
4
  */
5
5
 
6
- import React from "react";
6
+ import * as React from "react";
7
+ import { useMemo } from "react";
7
8
  import { View, TouchableOpacity, StyleSheet } from "react-native";
8
9
  import {
9
10
  AtomicText,
@@ -34,56 +35,8 @@ export const ResultActions: React.FC<ResultActionsProps> = ({
34
35
  translations,
35
36
  }) => {
36
37
  const tokens = useAppDesignTokens();
37
- const styles = createStyles(tokens);
38
38
 
39
- return (
40
- <View style={styles.container}>
41
- {onRetry && (
42
- <TouchableOpacity style={styles.retryButton} onPress={onRetry}>
43
- <AtomicIcon name="refresh" size="sm" customColor={tokens.colors.primary} />
44
- <AtomicText style={styles.retryText}>{translations.retry}</AtomicText>
45
- </TouchableOpacity>
46
- )}
47
-
48
- <View style={styles.buttons}>
49
- {onShare && (
50
- <TouchableOpacity
51
- style={[styles.button, styles.shareButton]}
52
- onPress={onShare}
53
- disabled={isSharing}
54
- >
55
- <AtomicIcon
56
- name={isSharing ? "hourglass" : "share-social"}
57
- size="md"
58
- customColor="#fff"
59
- />
60
- <AtomicText style={styles.shareText}>
61
- {isSharing ? translations.sharing : translations.share}
62
- </AtomicText>
63
- </TouchableOpacity>
64
- )}
65
-
66
- {onSave && (
67
- <TouchableOpacity
68
- style={[styles.button, styles.saveButton]}
69
- onPress={onSave}
70
- disabled={isSaving}
71
- >
72
- <AtomicIcon
73
- name={isSaving ? "hourglass" : "download"}
74
- size="md"
75
- customColor={tokens.colors.primary}
76
- />
77
- <AtomicText style={styles.saveText}>{translations.save}</AtomicText>
78
- </TouchableOpacity>
79
- )}
80
- </View>
81
- </View>
82
- );
83
- };
84
-
85
- const createStyles = (tokens: any) =>
86
- StyleSheet.create({
39
+ const styles = useMemo(() => StyleSheet.create({
87
40
  container: {
88
41
  paddingHorizontal: 20,
89
42
  paddingBottom: 20,
@@ -120,7 +73,7 @@ const createStyles = (tokens: any) =>
120
73
  shareText: {
121
74
  fontSize: 15,
122
75
  fontWeight: "700",
123
- color: "#fff",
76
+ color: tokens.colors.onPrimary,
124
77
  },
125
78
  saveButton: {
126
79
  backgroundColor: tokens.colors.surface,
@@ -132,4 +85,50 @@ const createStyles = (tokens: any) =>
132
85
  fontWeight: "700",
133
86
  color: tokens.colors.primary,
134
87
  },
135
- });
88
+ }), [tokens]);
89
+
90
+ return (
91
+ <View style={styles.container}>
92
+ {onRetry && (
93
+ <TouchableOpacity style={styles.retryButton} onPress={onRetry}>
94
+ <AtomicIcon name="refresh" size="sm" color="primary" />
95
+ <AtomicText style={styles.retryText}>{translations.retry}</AtomicText>
96
+ </TouchableOpacity>
97
+ )}
98
+
99
+ <View style={styles.buttons}>
100
+ {onShare && (
101
+ <TouchableOpacity
102
+ style={[styles.button, styles.shareButton]}
103
+ onPress={onShare}
104
+ disabled={isSharing}
105
+ >
106
+ <AtomicIcon
107
+ name={isSharing ? "hourglass" : "share-social"}
108
+ size="md"
109
+ color="onPrimary"
110
+ />
111
+ <AtomicText style={styles.shareText}>
112
+ {isSharing ? translations.sharing : translations.share}
113
+ </AtomicText>
114
+ </TouchableOpacity>
115
+ )}
116
+
117
+ {onSave && (
118
+ <TouchableOpacity
119
+ style={[styles.button, styles.saveButton]}
120
+ onPress={onSave}
121
+ disabled={isSaving}
122
+ >
123
+ <AtomicIcon
124
+ name={isSaving ? "hourglass" : "download"}
125
+ size="md"
126
+ color="primary"
127
+ />
128
+ <AtomicText style={styles.saveText}>{translations.save}</AtomicText>
129
+ </TouchableOpacity>
130
+ )}
131
+ </View>
132
+ </View>
133
+ );
134
+ };
@@ -3,7 +3,8 @@
3
3
  * Header with title and date badge
4
4
  */
5
5
 
6
- import React from "react";
6
+ import * as React from "react";
7
+ import { useMemo } from "react";
7
8
  import { View, StyleSheet } from "react-native";
8
9
  import {
9
10
  AtomicText,
@@ -18,29 +19,8 @@ export interface ResultHeaderProps {
18
19
 
19
20
  export const ResultHeader: React.FC<ResultHeaderProps> = ({ title, date }) => {
20
21
  const tokens = useAppDesignTokens();
21
- const styles = createStyles(tokens);
22
22
 
23
- if (!title && !date) return null;
24
-
25
- return (
26
- <View style={styles.container}>
27
- {title && <AtomicText style={styles.title}>{title}</AtomicText>}
28
- {date && (
29
- <View style={styles.badge}>
30
- <AtomicIcon
31
- name="calendar-outline"
32
- size="sm"
33
- customColor={tokens.colors.primary}
34
- />
35
- <AtomicText style={styles.dateText}>{date}</AtomicText>
36
- </View>
37
- )}
38
- </View>
39
- );
40
- };
41
-
42
- const createStyles = (tokens: any) =>
43
- StyleSheet.create({
23
+ const styles = useMemo(() => StyleSheet.create({
44
24
  container: {
45
25
  alignItems: "center",
46
26
  paddingHorizontal: 24,
@@ -60,7 +40,7 @@ const createStyles = (tokens: any) =>
60
40
  gap: 6,
61
41
  paddingHorizontal: 14,
62
42
  paddingVertical: 6,
63
- backgroundColor: `${tokens.colors.primary}15`,
43
+ backgroundColor: tokens.colors.primaryContainer,
64
44
  borderRadius: 16,
65
45
  },
66
46
  dateText: {
@@ -68,4 +48,23 @@ const createStyles = (tokens: any) =>
68
48
  fontWeight: "600",
69
49
  color: tokens.colors.primary,
70
50
  },
71
- });
51
+ }), [tokens]);
52
+
53
+ if (!title && !date) return null;
54
+
55
+ return (
56
+ <View style={styles.container}>
57
+ {title && <AtomicText style={styles.title}>{title}</AtomicText>}
58
+ {date && (
59
+ <View style={styles.badge}>
60
+ <AtomicIcon
61
+ name="calendar-outline"
62
+ size="sm"
63
+ color="primary"
64
+ />
65
+ <AtomicText style={styles.dateText}>{date}</AtomicText>
66
+ </View>
67
+ )}
68
+ </View>
69
+ );
70
+ };
@@ -3,7 +3,8 @@
3
3
  * Displays generated image with AI badge
4
4
  */
5
5
 
6
- import React from "react";
6
+ import * as React from "react";
7
+ import { useMemo } from "react";
7
8
  import { View, Image, StyleSheet } from "react-native";
8
9
  import {
9
10
  AtomicText,
@@ -21,23 +22,8 @@ export const ResultImageCard: React.FC<ResultImageCardProps> = ({
21
22
  badgeText,
22
23
  }) => {
23
24
  const tokens = useAppDesignTokens();
24
- const styles = createStyles(tokens);
25
25
 
26
- return (
27
- <View style={styles.container}>
28
- <View style={styles.frame}>
29
- <Image source={{ uri: imageUrl }} style={styles.image} resizeMode="cover" />
30
- <View style={styles.badge}>
31
- <AtomicIcon name="sparkles" size="xs" customColor="#fff" />
32
- <AtomicText style={styles.badgeText}>{badgeText}</AtomicText>
33
- </View>
34
- </View>
35
- </View>
36
- );
37
- };
38
-
39
- const createStyles = (tokens: any) =>
40
- StyleSheet.create({
26
+ const styles = useMemo(() => StyleSheet.create({
41
27
  container: {
42
28
  paddingHorizontal: 20,
43
29
  marginBottom: 20,
@@ -60,13 +46,26 @@ const createStyles = (tokens: any) =>
60
46
  gap: 4,
61
47
  paddingHorizontal: 10,
62
48
  paddingVertical: 5,
63
- backgroundColor: "rgba(0,0,0,0.6)",
49
+ backgroundColor: "rgba(0, 0, 0, 0.6)",
64
50
  borderRadius: 12,
65
51
  },
66
52
  badgeText: {
67
53
  fontSize: 10,
68
54
  fontWeight: "700",
69
- color: "#fff",
55
+ color: "#FFFFFF",
70
56
  letterSpacing: 0.5,
71
57
  },
72
- });
58
+ }), [tokens]);
59
+
60
+ return (
61
+ <View style={styles.container}>
62
+ <View style={styles.frame}>
63
+ <Image source={{ uri: imageUrl }} style={styles.image} resizeMode="cover" />
64
+ <View style={styles.badge}>
65
+ <AtomicIcon name="sparkles" size="xs" color="onPrimary" />
66
+ <AtomicText style={styles.badgeText}>{badgeText}</AtomicText>
67
+ </View>
68
+ </View>
69
+ </View>
70
+ );
71
+ };