@umituz/react-native-ai-generation-content 1.17.277 → 1.17.278
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/screens/CreationsGalleryScreen.tsx +8 -5
- package/src/domains/result-preview/presentation/components/ResultActionBar.tsx +53 -13
- package/src/domains/result-preview/presentation/components/ResultPreviewScreen.tsx +12 -23
- package/src/domains/result-preview/presentation/types/result-preview.types.ts +10 -0
- package/src/features/love-message/presentation/hooks/useLoveMessageGenerator.ts +2 -2
- package/src/features/love-message/presentation/screens/LoveMessageGeneratorScreen.tsx +2 -2
- package/src/features/love-message/presentation/screens/MessageListScreen.tsx +2 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@umituz/react-native-ai-generation-content",
|
|
3
|
-
"version": "1.17.
|
|
3
|
+
"version": "1.17.278",
|
|
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",
|
|
@@ -8,8 +8,8 @@ import {
|
|
|
8
8
|
useSharing,
|
|
9
9
|
FilterSheet,
|
|
10
10
|
ScreenLayout,
|
|
11
|
+
useAppFocusEffect,
|
|
11
12
|
} from "@umituz/react-native-design-system";
|
|
12
|
-
import { useFocusEffect } from "@react-navigation/native";
|
|
13
13
|
import { useCreations } from "../hooks/useCreations";
|
|
14
14
|
import { useDeleteCreation } from "../hooks/useDeleteCreation";
|
|
15
15
|
import { useGalleryFilters } from "../hooks/useGalleryFilters";
|
|
@@ -64,7 +64,7 @@ export function CreationsGalleryScreen({
|
|
|
64
64
|
|
|
65
65
|
const filters = useGalleryFilters({ creations, statusOptions, mediaOptions, t });
|
|
66
66
|
|
|
67
|
-
|
|
67
|
+
useAppFocusEffect(useCallback(() => { void refetch(); }, [refetch]));
|
|
68
68
|
|
|
69
69
|
const handleShareCard = useCallback((c: Creation) => {
|
|
70
70
|
void share(c.uri, { dialogTitle: t("common.share") });
|
|
@@ -177,14 +177,17 @@ export function CreationsGalleryScreen({
|
|
|
177
177
|
onShare={handleShare}
|
|
178
178
|
onTryAgain={handleTryAgain}
|
|
179
179
|
onNavigateBack={handleBack}
|
|
180
|
+
hideLabel
|
|
181
|
+
iconOnly
|
|
182
|
+
showTryAgain={false}
|
|
180
183
|
translations={{
|
|
181
|
-
title: t(config.translations.
|
|
182
|
-
yourResult:
|
|
184
|
+
title: t(config.translations.title),
|
|
185
|
+
yourResult: "",
|
|
183
186
|
saveButton: t("result.saveButton"),
|
|
184
187
|
saving: t("result.saving"),
|
|
185
188
|
shareButton: t("result.shareButton"),
|
|
186
189
|
sharing: t("result.sharing"),
|
|
187
|
-
tryAnother:
|
|
190
|
+
tryAnother: "",
|
|
188
191
|
}}
|
|
189
192
|
/>
|
|
190
193
|
);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* ResultActionBar Component
|
|
3
|
-
* Action buttons for save, share, retry
|
|
3
|
+
* Action buttons for save, share, retry
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import React, { useMemo } from "react";
|
|
@@ -21,6 +21,8 @@ export const ResultActionBar: React.FC<ResultActionBarProps> = ({
|
|
|
21
21
|
saveButtonText,
|
|
22
22
|
shareButtonText,
|
|
23
23
|
tryAgainButtonText,
|
|
24
|
+
iconOnly = false,
|
|
25
|
+
showTryAgain = true,
|
|
24
26
|
}) => {
|
|
25
27
|
const tokens = useAppDesignTokens();
|
|
26
28
|
|
|
@@ -46,15 +48,57 @@ export const ResultActionBar: React.FC<ResultActionBarProps> = ({
|
|
|
46
48
|
minWidth: 110,
|
|
47
49
|
backgroundColor: tokens.colors.primary,
|
|
48
50
|
},
|
|
51
|
+
iconButton: {
|
|
52
|
+
width: 56,
|
|
53
|
+
height: 56,
|
|
54
|
+
borderRadius: 28,
|
|
55
|
+
backgroundColor: tokens.colors.primary,
|
|
56
|
+
justifyContent: "center",
|
|
57
|
+
alignItems: "center",
|
|
58
|
+
},
|
|
49
59
|
buttonText: {
|
|
50
60
|
fontWeight: "700",
|
|
51
61
|
color: tokens.colors.textInverse,
|
|
52
62
|
fontSize: 15,
|
|
53
63
|
},
|
|
64
|
+
disabledButton: {
|
|
65
|
+
opacity: 0.6,
|
|
66
|
+
},
|
|
54
67
|
}),
|
|
55
68
|
[tokens],
|
|
56
69
|
);
|
|
57
70
|
|
|
71
|
+
if (iconOnly) {
|
|
72
|
+
return (
|
|
73
|
+
<View style={styles.container}>
|
|
74
|
+
<TouchableOpacity
|
|
75
|
+
style={[styles.iconButton, isSaving && styles.disabledButton]}
|
|
76
|
+
onPress={onDownload}
|
|
77
|
+
disabled={isSaving}
|
|
78
|
+
activeOpacity={0.7}
|
|
79
|
+
>
|
|
80
|
+
{isSaving ? (
|
|
81
|
+
<ActivityIndicator color={tokens.colors.textInverse} size="small" />
|
|
82
|
+
) : (
|
|
83
|
+
<AtomicIcon name="download" customSize={24} color="onPrimary" />
|
|
84
|
+
)}
|
|
85
|
+
</TouchableOpacity>
|
|
86
|
+
<TouchableOpacity
|
|
87
|
+
style={[styles.iconButton, isSharing && styles.disabledButton]}
|
|
88
|
+
onPress={onShare}
|
|
89
|
+
disabled={isSharing}
|
|
90
|
+
activeOpacity={0.7}
|
|
91
|
+
>
|
|
92
|
+
{isSharing ? (
|
|
93
|
+
<ActivityIndicator color={tokens.colors.textInverse} size="small" />
|
|
94
|
+
) : (
|
|
95
|
+
<AtomicIcon name="share-2" customSize={24} color="onPrimary" />
|
|
96
|
+
)}
|
|
97
|
+
</TouchableOpacity>
|
|
98
|
+
</View>
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
|
|
58
102
|
return (
|
|
59
103
|
<View style={styles.container}>
|
|
60
104
|
<TouchableOpacity
|
|
@@ -66,11 +110,10 @@ export const ResultActionBar: React.FC<ResultActionBarProps> = ({
|
|
|
66
110
|
{isSaving ? (
|
|
67
111
|
<ActivityIndicator color={tokens.colors.textInverse} size="small" />
|
|
68
112
|
) : (
|
|
69
|
-
<AtomicIcon name="download
|
|
113
|
+
<AtomicIcon name="download" customSize={18} color="onPrimary" />
|
|
70
114
|
)}
|
|
71
115
|
<AtomicText style={styles.buttonText}>{saveButtonText}</AtomicText>
|
|
72
116
|
</TouchableOpacity>
|
|
73
|
-
|
|
74
117
|
<TouchableOpacity
|
|
75
118
|
style={styles.button}
|
|
76
119
|
onPress={onShare}
|
|
@@ -80,19 +123,16 @@ export const ResultActionBar: React.FC<ResultActionBarProps> = ({
|
|
|
80
123
|
{isSharing ? (
|
|
81
124
|
<ActivityIndicator color={tokens.colors.textInverse} size="small" />
|
|
82
125
|
) : (
|
|
83
|
-
<AtomicIcon name="share-
|
|
126
|
+
<AtomicIcon name="share-2" customSize={18} color="onPrimary" />
|
|
84
127
|
)}
|
|
85
128
|
<AtomicText style={styles.buttonText}>{shareButtonText}</AtomicText>
|
|
86
129
|
</TouchableOpacity>
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
<AtomicIcon name="refresh-outline" size="sm" color="onPrimary" />
|
|
94
|
-
<AtomicText style={styles.buttonText}>{tryAgainButtonText}</AtomicText>
|
|
95
|
-
</TouchableOpacity>
|
|
130
|
+
{showTryAgain && (
|
|
131
|
+
<TouchableOpacity style={styles.button} onPress={onTryAgain} activeOpacity={0.7}>
|
|
132
|
+
<AtomicIcon name="refresh-cw" customSize={18} color="onPrimary" />
|
|
133
|
+
<AtomicText style={styles.buttonText}>{tryAgainButtonText}</AtomicText>
|
|
134
|
+
</TouchableOpacity>
|
|
135
|
+
)}
|
|
96
136
|
</View>
|
|
97
137
|
);
|
|
98
138
|
};
|
|
@@ -24,12 +24,14 @@ export const ResultPreviewScreen: React.FC<ResultPreviewScreenProps> = ({
|
|
|
24
24
|
onShare,
|
|
25
25
|
onTryAgain,
|
|
26
26
|
onNavigateBack,
|
|
27
|
-
_onRate,
|
|
28
27
|
recentCreations,
|
|
29
28
|
onViewAll,
|
|
30
29
|
onCreationPress,
|
|
31
30
|
translations,
|
|
32
31
|
style,
|
|
32
|
+
hideLabel = false,
|
|
33
|
+
iconOnly = false,
|
|
34
|
+
showTryAgain = true,
|
|
33
35
|
}) => {
|
|
34
36
|
const tokens = useAppDesignTokens();
|
|
35
37
|
|
|
@@ -55,37 +57,22 @@ export const ResultPreviewScreen: React.FC<ResultPreviewScreenProps> = ({
|
|
|
55
57
|
|
|
56
58
|
const displayImageUrl = useMemo(() => {
|
|
57
59
|
if (!imageUrl) return null;
|
|
58
|
-
|
|
59
|
-
// If not a URL and not a data URL, assume it's base64
|
|
60
|
-
if (
|
|
61
|
-
!imageUrl.startsWith("http") &&
|
|
62
|
-
!imageUrl.startsWith("data:image")
|
|
63
|
-
) {
|
|
60
|
+
if (!imageUrl.startsWith("http") && !imageUrl.startsWith("data:image")) {
|
|
64
61
|
return `data:image/jpeg;base64,${imageUrl}`;
|
|
65
62
|
}
|
|
66
|
-
|
|
67
63
|
return imageUrl;
|
|
68
64
|
}, [imageUrl]);
|
|
69
65
|
|
|
70
|
-
if (!displayImageUrl)
|
|
71
|
-
return null;
|
|
72
|
-
}
|
|
66
|
+
if (!displayImageUrl) return null;
|
|
73
67
|
|
|
74
68
|
return (
|
|
75
|
-
<ScreenLayout
|
|
76
|
-
|
|
77
|
-
edges={["left", "right"]}
|
|
78
|
-
backgroundColor={tokens.colors.backgroundPrimary}
|
|
79
|
-
>
|
|
80
|
-
<NavigationHeader
|
|
81
|
-
title={translations.title}
|
|
82
|
-
onBackPress={onNavigateBack}
|
|
83
|
-
/>
|
|
69
|
+
<ScreenLayout scrollable edges={["left", "right"]} backgroundColor={tokens.colors.backgroundPrimary}>
|
|
70
|
+
<NavigationHeader title={translations.title} onBackPress={onNavigateBack} />
|
|
84
71
|
<View style={[styles.container, style]}>
|
|
85
72
|
<View style={styles.resultContainer}>
|
|
86
|
-
|
|
87
|
-
{translations.yourResult}
|
|
88
|
-
|
|
73
|
+
{!hideLabel && (
|
|
74
|
+
<AtomicText style={styles.title}>{translations.yourResult}</AtomicText>
|
|
75
|
+
)}
|
|
89
76
|
<ResultImageCard imageUrl={displayImageUrl} />
|
|
90
77
|
<ResultActionBar
|
|
91
78
|
isSaving={isSaving}
|
|
@@ -96,6 +83,8 @@ export const ResultPreviewScreen: React.FC<ResultPreviewScreenProps> = ({
|
|
|
96
83
|
saveButtonText={translations.saveButton}
|
|
97
84
|
shareButtonText={translations.shareButton}
|
|
98
85
|
tryAgainButtonText={translations.tryAnother}
|
|
86
|
+
iconOnly={iconOnly}
|
|
87
|
+
showTryAgain={showTryAgain}
|
|
99
88
|
/>
|
|
100
89
|
</View>
|
|
101
90
|
{recentCreations && recentCreations.length > 0 && translations.recentCreations && translations.viewAll && (
|
|
@@ -69,6 +69,10 @@ export interface ResultActionBarProps {
|
|
|
69
69
|
shareButtonText: string;
|
|
70
70
|
/** Try again button text */
|
|
71
71
|
tryAgainButtonText: string;
|
|
72
|
+
/** Show only icons without text */
|
|
73
|
+
iconOnly?: boolean;
|
|
74
|
+
/** Show try again button */
|
|
75
|
+
showTryAgain?: boolean;
|
|
72
76
|
}
|
|
73
77
|
|
|
74
78
|
/**
|
|
@@ -107,6 +111,12 @@ export interface ResultPreviewScreenProps {
|
|
|
107
111
|
translations: ResultPreviewTranslations;
|
|
108
112
|
/** Optional custom style */
|
|
109
113
|
style?: StyleProp<ViewStyle>;
|
|
114
|
+
/** Hide "Your Result" label */
|
|
115
|
+
hideLabel?: boolean;
|
|
116
|
+
/** Show icon-only action buttons */
|
|
117
|
+
iconOnly?: boolean;
|
|
118
|
+
/** Show try again button */
|
|
119
|
+
showTryAgain?: boolean;
|
|
110
120
|
}
|
|
111
121
|
|
|
112
122
|
/**
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import { useState, useCallback, useEffect } from "react";
|
|
7
|
-
import {
|
|
7
|
+
import { useAppIsFocused } from "@umituz/react-native-design-system";
|
|
8
8
|
import { MessageType, MessageTone } from "../../domain/types";
|
|
9
9
|
import { generateLoveMessage } from "../../infrastructure/services/LoveMessageService";
|
|
10
10
|
import { PartnerProfileRepository } from "../../infrastructure/persistence/PartnerProfileRepository";
|
|
@@ -20,7 +20,7 @@ export const useLoveMessageGenerator = (config: {
|
|
|
20
20
|
onBack: () => void;
|
|
21
21
|
initialType?: MessageType;
|
|
22
22
|
}) => {
|
|
23
|
-
const isFocused =
|
|
23
|
+
const isFocused = useAppIsFocused();
|
|
24
24
|
|
|
25
25
|
const [currentStep, setCurrentStep] = useState<GeneratorStep>(GeneratorStep.PARTNER);
|
|
26
26
|
const [partnerName, setPartnerName] = useState("");
|
|
@@ -11,9 +11,9 @@ import {
|
|
|
11
11
|
useAppDesignTokens,
|
|
12
12
|
useSafeAreaInsets,
|
|
13
13
|
AppNavigation,
|
|
14
|
+
useAppRoute,
|
|
14
15
|
} from "@umituz/react-native-design-system";
|
|
15
16
|
import { useLocalization } from "@umituz/react-native-localization";
|
|
16
|
-
import { useRoute, RouteProp } from "@react-navigation/native";
|
|
17
17
|
import { ProgressDots } from "../components/ProgressDots";
|
|
18
18
|
import { MessageResult } from "../components/MessageResult";
|
|
19
19
|
import { GeneratorHeader } from "../components/GeneratorHeader";
|
|
@@ -29,7 +29,7 @@ export const LoveMessageGeneratorScreen: FC = () => {
|
|
|
29
29
|
const tokens = useAppDesignTokens();
|
|
30
30
|
const { bottom } = useSafeAreaInsets();
|
|
31
31
|
const { t } = useLocalization();
|
|
32
|
-
const route =
|
|
32
|
+
const route = useAppRoute<{ params: RouteParams }, "params">();
|
|
33
33
|
|
|
34
34
|
const initialType = route.params?.initialType;
|
|
35
35
|
const gen = useLoveMessageGenerator({ onBack: () => AppNavigation.goBack(), initialType });
|
|
@@ -10,9 +10,9 @@ import {
|
|
|
10
10
|
useAppDesignTokens,
|
|
11
11
|
useSafeAreaInsets,
|
|
12
12
|
AppNavigation,
|
|
13
|
+
useAppRoute,
|
|
13
14
|
} from "@umituz/react-native-design-system";
|
|
14
15
|
import { useLocalization } from "@umituz/react-native-localization";
|
|
15
|
-
import { useRoute, RouteProp } from "@react-navigation/native";
|
|
16
16
|
import { CATEGORY_TEMPLATES, MESSAGE_TYPES } from "../../domain/constants";
|
|
17
17
|
import { MessageListItem } from "../components/MessageListItem";
|
|
18
18
|
import type { MessageType } from "../../domain/types";
|
|
@@ -23,7 +23,7 @@ export const MessageListScreen: FC = () => {
|
|
|
23
23
|
const tokens = useAppDesignTokens();
|
|
24
24
|
const { top, bottom } = useSafeAreaInsets();
|
|
25
25
|
const { t } = useLocalization();
|
|
26
|
-
const route =
|
|
26
|
+
const route = useAppRoute<{ params: RouteParams }, "params">();
|
|
27
27
|
|
|
28
28
|
const categoryId = route.params?.categoryId ?? "romantic";
|
|
29
29
|
const messages = useMemo(() => CATEGORY_TEMPLATES[categoryId] || [], [categoryId]);
|