@umituz/react-native-ai-generation-content 1.26.14 → 1.26.16
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/love-message/domain/constants.ts +162 -0
- package/src/domains/love-message/domain/types.ts +58 -0
- package/src/domains/love-message/index.ts +37 -0
- package/src/domains/love-message/infrastructure/persistence/PartnerProfileRepository.ts +52 -0
- package/src/domains/love-message/infrastructure/prompts/messagePromptBuilder.ts +109 -0
- package/src/domains/love-message/infrastructure/services/LoveMessageService.ts +35 -0
- package/src/domains/love-message/presentation/components/CategoryGrid.tsx +88 -0
- package/src/domains/love-message/presentation/components/DetailsInput.tsx +74 -0
- package/src/domains/love-message/presentation/components/ExploreHeader.tsx +67 -0
- package/src/domains/love-message/presentation/components/FieldInput.tsx +83 -0
- package/src/domains/love-message/presentation/components/GeneratorHeader.tsx +88 -0
- package/src/domains/love-message/presentation/components/LoveMessageHeroSection.tsx +114 -0
- package/src/domains/love-message/presentation/components/MessageListItem.tsx +77 -0
- package/src/domains/love-message/presentation/components/MessageResult.tsx +105 -0
- package/src/domains/love-message/presentation/components/PartnerInput.tsx +78 -0
- package/src/domains/love-message/presentation/components/ProgressDots.tsx +48 -0
- package/src/domains/love-message/presentation/components/StepDetails.tsx +23 -0
- package/src/domains/love-message/presentation/components/StepPartner.tsx +116 -0
- package/src/domains/love-message/presentation/components/StepVibe.tsx +30 -0
- package/src/domains/love-message/presentation/components/ToneSelector.tsx +100 -0
- package/src/domains/love-message/presentation/components/TrendingSection.tsx +130 -0
- package/src/domains/love-message/presentation/components/TypeSelector.tsx +99 -0
- package/src/domains/love-message/presentation/hooks/useLoveMessageGenerator.ts +114 -0
- package/src/domains/love-message/presentation/hooks/usePartnerProfile.ts +43 -0
- package/src/domains/love-message/presentation/navigation/LoveMessageStack.tsx +39 -0
- package/src/domains/love-message/presentation/screens/LoveMessageExploreScreen.tsx +53 -0
- package/src/domains/love-message/presentation/screens/LoveMessageGeneratorScreen.tsx +169 -0
- package/src/domains/love-message/presentation/screens/MessageListScreen.tsx +127 -0
- package/src/domains/love-message/presentation/screens/PartnerProfileScreen.tsx +119 -0
- package/src/domains/scenarios/domain/scenario.types.ts +49 -0
- package/src/domains/scenarios/index.ts +5 -0
- package/src/index.ts +1 -0
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Love Message Explore Screen
|
|
3
|
+
* Premium entry point for Love Message domain
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { FC } from "react";
|
|
7
|
+
import { View, ScrollView, StyleSheet } from "react-native";
|
|
8
|
+
import {
|
|
9
|
+
useAppDesignTokens,
|
|
10
|
+
useSafeAreaInsets,
|
|
11
|
+
useAppNavigation,
|
|
12
|
+
} from "@umituz/react-native-design-system";
|
|
13
|
+
import { ExploreHeader } from "../components/ExploreHeader";
|
|
14
|
+
import { LoveMessageHeroSection } from "../components/LoveMessageHeroSection";
|
|
15
|
+
import { CategoryGrid } from "../components/CategoryGrid";
|
|
16
|
+
import { TrendingSection } from "../components/TrendingSection";
|
|
17
|
+
|
|
18
|
+
export const LoveMessageExploreScreen: FC = () => {
|
|
19
|
+
const tokens = useAppDesignTokens();
|
|
20
|
+
const { bottom } = useSafeAreaInsets();
|
|
21
|
+
const navigation = useAppNavigation();
|
|
22
|
+
|
|
23
|
+
const handleNavigateToGenerator = () => {
|
|
24
|
+
navigation.navigate("MessageGenerator", {});
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
const handleNavigateToCategory = (categoryId: string) => {
|
|
28
|
+
navigation.navigate("MessageList", { categoryId });
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
const handleNavigateToTrending = () => {
|
|
32
|
+
navigation.navigate("MessageList", { categoryId: "trending" });
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
return (
|
|
36
|
+
<View style={[styles.container, { backgroundColor: tokens.colors.backgroundPrimary }]}>
|
|
37
|
+
<ExploreHeader onMagicPress={handleNavigateToGenerator} />
|
|
38
|
+
|
|
39
|
+
<ScrollView
|
|
40
|
+
showsVerticalScrollIndicator={false}
|
|
41
|
+
contentContainerStyle={{ paddingBottom: bottom + 120 }}
|
|
42
|
+
>
|
|
43
|
+
<LoveMessageHeroSection />
|
|
44
|
+
<CategoryGrid onCategoryPress={handleNavigateToCategory} />
|
|
45
|
+
<TrendingSection onViewAll={handleNavigateToTrending} />
|
|
46
|
+
</ScrollView>
|
|
47
|
+
</View>
|
|
48
|
+
);
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
const styles = StyleSheet.create({
|
|
52
|
+
container: { flex: 1 },
|
|
53
|
+
});
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Love Message Generator Screen
|
|
3
|
+
* Multi-step wizard flow
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { FC, useMemo, useCallback } from "react";
|
|
7
|
+
import { View, ScrollView, StyleSheet } from "react-native";
|
|
8
|
+
import {
|
|
9
|
+
AtomicText,
|
|
10
|
+
AtomicButton,
|
|
11
|
+
useAppNavigation,
|
|
12
|
+
useAppRoute,
|
|
13
|
+
AlertService,
|
|
14
|
+
useAppDesignTokens,
|
|
15
|
+
useSafeAreaInsets,
|
|
16
|
+
} from "@umituz/react-native-design-system";
|
|
17
|
+
|
|
18
|
+
import { useLocalization } from "@umituz/react-native-localization";
|
|
19
|
+
import { ProgressDots } from "../components/ProgressDots";
|
|
20
|
+
import { MessageResult } from "../components/MessageResult";
|
|
21
|
+
import { GeneratorHeader } from "../components/GeneratorHeader";
|
|
22
|
+
import { StepPartner } from "../components/StepPartner";
|
|
23
|
+
import { StepVibe } from "../components/StepVibe";
|
|
24
|
+
import { StepDetails } from "../components/StepDetails";
|
|
25
|
+
import { MessageType } from "../../domain/types";
|
|
26
|
+
import { useLoveMessageGenerator, GeneratorStep } from "../hooks/useLoveMessageGenerator";
|
|
27
|
+
|
|
28
|
+
type RouteParams = { initialType?: MessageType };
|
|
29
|
+
|
|
30
|
+
export const LoveMessageGeneratorScreen: FC = () => {
|
|
31
|
+
const tokens = useAppDesignTokens();
|
|
32
|
+
const { bottom } = useSafeAreaInsets();
|
|
33
|
+
const { t } = useLocalization();
|
|
34
|
+
const navigation = useAppNavigation();
|
|
35
|
+
const route = useAppRoute<{ params: RouteParams }, "params">();
|
|
36
|
+
|
|
37
|
+
const initialType = route.params?.initialType;
|
|
38
|
+
|
|
39
|
+
const handleSuccess = useCallback(() => {
|
|
40
|
+
AlertService.createSuccessAlert(
|
|
41
|
+
t("loveMessage.generator.successTitle"),
|
|
42
|
+
t("loveMessage.generator.successMessage")
|
|
43
|
+
);
|
|
44
|
+
}, [t]);
|
|
45
|
+
|
|
46
|
+
const handleError = useCallback(() => {
|
|
47
|
+
AlertService.createErrorAlert(
|
|
48
|
+
t("loveMessage.generator.errorTitle"),
|
|
49
|
+
t("loveMessage.generator.errorMessage")
|
|
50
|
+
);
|
|
51
|
+
}, [t]);
|
|
52
|
+
|
|
53
|
+
const gen = useLoveMessageGenerator({
|
|
54
|
+
onBack: () => navigation.goBack(),
|
|
55
|
+
initialType,
|
|
56
|
+
onSuccess: handleSuccess,
|
|
57
|
+
onError: handleError,
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
const handleNavigateToProfile = () => navigation.navigate("PartnerProfile");
|
|
61
|
+
|
|
62
|
+
const stepTitle = useMemo(() => {
|
|
63
|
+
switch (gen.currentStep) {
|
|
64
|
+
case GeneratorStep.PARTNER:
|
|
65
|
+
return t("loveMessage.generator.stepPartner");
|
|
66
|
+
case GeneratorStep.VIBE:
|
|
67
|
+
return t("loveMessage.generator.stepVibe");
|
|
68
|
+
case GeneratorStep.DETAILS:
|
|
69
|
+
return t("loveMessage.generator.stepDetails");
|
|
70
|
+
case GeneratorStep.RESULT:
|
|
71
|
+
return t("loveMessage.generator.stepResult");
|
|
72
|
+
default:
|
|
73
|
+
return "";
|
|
74
|
+
}
|
|
75
|
+
}, [gen.currentStep, t]);
|
|
76
|
+
|
|
77
|
+
return (
|
|
78
|
+
<View style={[styles.container, { backgroundColor: tokens.colors.backgroundPrimary }]}>
|
|
79
|
+
<GeneratorHeader
|
|
80
|
+
currentStep={gen.currentStep}
|
|
81
|
+
partnerName={gen.partnerName}
|
|
82
|
+
onBack={gen.handleBack}
|
|
83
|
+
onNext={gen.handleNext}
|
|
84
|
+
onGenerate={gen.handleGenerate}
|
|
85
|
+
isGenerating={gen.isGenerating}
|
|
86
|
+
/>
|
|
87
|
+
|
|
88
|
+
<ScrollView
|
|
89
|
+
showsVerticalScrollIndicator={false}
|
|
90
|
+
contentContainerStyle={{ paddingBottom: bottom + 120 }}
|
|
91
|
+
>
|
|
92
|
+
<View style={styles.heroSection}>
|
|
93
|
+
<ProgressDots currentStep={gen.currentStep} totalSteps={4} />
|
|
94
|
+
<AtomicText type="headlineLarge" color="textPrimary" style={styles.heroTitle}>
|
|
95
|
+
{stepTitle}
|
|
96
|
+
</AtomicText>
|
|
97
|
+
</View>
|
|
98
|
+
|
|
99
|
+
<View style={styles.formContent}>
|
|
100
|
+
{gen.currentStep === GeneratorStep.PARTNER && (
|
|
101
|
+
<View>
|
|
102
|
+
<StepPartner
|
|
103
|
+
partnerName={gen.partnerName}
|
|
104
|
+
setPartnerName={gen.setPartnerName}
|
|
105
|
+
useProfile={gen.useProfile}
|
|
106
|
+
setUseProfile={gen.setUseProfile}
|
|
107
|
+
hasProfile={gen.hasProfile}
|
|
108
|
+
onEditProfile={handleNavigateToProfile}
|
|
109
|
+
/>
|
|
110
|
+
</View>
|
|
111
|
+
)}
|
|
112
|
+
|
|
113
|
+
{gen.currentStep === GeneratorStep.VIBE && (
|
|
114
|
+
<View>
|
|
115
|
+
<StepVibe
|
|
116
|
+
selectedType={gen.selectedType}
|
|
117
|
+
setSelectedType={gen.setSelectedType}
|
|
118
|
+
selectedTone={gen.selectedTone}
|
|
119
|
+
setSelectedTone={gen.setSelectedTone}
|
|
120
|
+
/>
|
|
121
|
+
</View>
|
|
122
|
+
)}
|
|
123
|
+
|
|
124
|
+
{gen.currentStep === GeneratorStep.DETAILS && (
|
|
125
|
+
<View>
|
|
126
|
+
<StepDetails details={gen.details} setDetails={gen.setDetails} />
|
|
127
|
+
</View>
|
|
128
|
+
)}
|
|
129
|
+
|
|
130
|
+
{gen.currentStep === GeneratorStep.RESULT && (
|
|
131
|
+
<MessageResult message={gen.generatedMessage} />
|
|
132
|
+
)}
|
|
133
|
+
</View>
|
|
134
|
+
</ScrollView>
|
|
135
|
+
|
|
136
|
+
{gen.currentStep === GeneratorStep.RESULT && (
|
|
137
|
+
<View style={[styles.footer, { paddingBottom: bottom + 24 }]}>
|
|
138
|
+
<AtomicButton
|
|
139
|
+
title={t("loveMessage.generator.startOver")}
|
|
140
|
+
onPress={gen.startOver}
|
|
141
|
+
variant="outline"
|
|
142
|
+
fullWidth
|
|
143
|
+
style={styles.actionBtn}
|
|
144
|
+
/>
|
|
145
|
+
</View>
|
|
146
|
+
)}
|
|
147
|
+
</View>
|
|
148
|
+
);
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
const styles = StyleSheet.create({
|
|
152
|
+
container: { flex: 1 },
|
|
153
|
+
heroSection: { paddingVertical: 32, alignItems: "center" },
|
|
154
|
+
heroTitle: {
|
|
155
|
+
fontWeight: "bold",
|
|
156
|
+
textAlign: "center",
|
|
157
|
+
marginBottom: 8,
|
|
158
|
+
paddingHorizontal: 20,
|
|
159
|
+
},
|
|
160
|
+
formContent: { paddingHorizontal: 20 },
|
|
161
|
+
footer: {
|
|
162
|
+
position: "absolute",
|
|
163
|
+
bottom: 0,
|
|
164
|
+
left: 0,
|
|
165
|
+
right: 0,
|
|
166
|
+
padding: 24,
|
|
167
|
+
},
|
|
168
|
+
actionBtn: { height: 60, borderRadius: 30 },
|
|
169
|
+
});
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Message List Screen
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { FC, useCallback, useMemo } from "react";
|
|
6
|
+
import { View, ScrollView, StyleSheet, Pressable, Share } from "react-native";
|
|
7
|
+
import {
|
|
8
|
+
AtomicText,
|
|
9
|
+
AtomicIcon,
|
|
10
|
+
useAppNavigation,
|
|
11
|
+
useAppRoute,
|
|
12
|
+
useAppDesignTokens,
|
|
13
|
+
useSafeAreaInsets,
|
|
14
|
+
} from "@umituz/react-native-design-system";
|
|
15
|
+
import { useLocalization } from "@umituz/react-native-localization";
|
|
16
|
+
import { CATEGORY_TEMPLATES, MESSAGE_TYPES } from "../../domain/constants";
|
|
17
|
+
import { MessageListItem } from "../components/MessageListItem";
|
|
18
|
+
import type { MessageType } from "../../domain/types";
|
|
19
|
+
|
|
20
|
+
type RouteParams = { categoryId?: string };
|
|
21
|
+
|
|
22
|
+
export const MessageListScreen: FC = () => {
|
|
23
|
+
const tokens = useAppDesignTokens();
|
|
24
|
+
const { top, bottom } = useSafeAreaInsets();
|
|
25
|
+
const { t } = useLocalization();
|
|
26
|
+
const navigation = useAppNavigation();
|
|
27
|
+
const route = useAppRoute<{ params: RouteParams }, "params">();
|
|
28
|
+
|
|
29
|
+
const categoryId = route.params?.categoryId ?? "romantic";
|
|
30
|
+
const messages = useMemo(() => CATEGORY_TEMPLATES[categoryId] || [], [categoryId]);
|
|
31
|
+
|
|
32
|
+
const categoryTitle = useMemo(() => {
|
|
33
|
+
if (categoryId === "trending") return t("loveMessage.explore.trending");
|
|
34
|
+
const config = MESSAGE_TYPES.find((c) => c.type === categoryId);
|
|
35
|
+
return config ? t(config.labelKey) : categoryId;
|
|
36
|
+
}, [categoryId, t]);
|
|
37
|
+
|
|
38
|
+
const handleBack = () => navigation.goBack();
|
|
39
|
+
|
|
40
|
+
const handleNavigateToGenerator = (type?: string) => {
|
|
41
|
+
navigation.navigate("MessageGenerator", { initialType: type as MessageType });
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
const handleShare = useCallback(async (text: string) => {
|
|
45
|
+
try {
|
|
46
|
+
await Share.share({ message: text });
|
|
47
|
+
} catch {
|
|
48
|
+
/* Ignore */
|
|
49
|
+
}
|
|
50
|
+
}, []);
|
|
51
|
+
|
|
52
|
+
return (
|
|
53
|
+
<View style={[styles.container, { backgroundColor: tokens.colors.backgroundPrimary }]}>
|
|
54
|
+
<View style={[styles.header, { paddingTop: top + tokens.spacing.md }]}>
|
|
55
|
+
<Pressable onPress={handleBack} style={styles.backBtn}>
|
|
56
|
+
<AtomicIcon name="arrow-back" color="textPrimary" size="sm" />
|
|
57
|
+
</Pressable>
|
|
58
|
+
<AtomicText type="headlineSmall" color="textPrimary" style={styles.headerTitle}>
|
|
59
|
+
{categoryTitle}
|
|
60
|
+
</AtomicText>
|
|
61
|
+
<View style={styles.spacer} />
|
|
62
|
+
</View>
|
|
63
|
+
|
|
64
|
+
<ScrollView
|
|
65
|
+
showsVerticalScrollIndicator={false}
|
|
66
|
+
contentContainerStyle={{ paddingBottom: bottom + 100, paddingHorizontal: 16 }}
|
|
67
|
+
>
|
|
68
|
+
<View style={styles.headlineContainer}>
|
|
69
|
+
<AtomicText type="headlineMedium" color="textPrimary" style={styles.headline}>
|
|
70
|
+
{`${messages.length} ${t("loveMessage.messages")}`}
|
|
71
|
+
</AtomicText>
|
|
72
|
+
<AtomicText type="bodySmall" color="textTertiary">
|
|
73
|
+
{t("loveMessage.aiCrafted")}
|
|
74
|
+
</AtomicText>
|
|
75
|
+
</View>
|
|
76
|
+
|
|
77
|
+
{messages.map((item) => (
|
|
78
|
+
<MessageListItem key={item.id} item={item} onShare={handleShare} />
|
|
79
|
+
))}
|
|
80
|
+
</ScrollView>
|
|
81
|
+
|
|
82
|
+
<View style={[styles.fabContainer, { bottom: bottom + tokens.spacing.lg }]}>
|
|
83
|
+
<Pressable
|
|
84
|
+
onPress={() => handleNavigateToGenerator(categoryId !== "trending" ? categoryId : undefined)}
|
|
85
|
+
style={[styles.fab, { backgroundColor: tokens.colors.primary }]}
|
|
86
|
+
>
|
|
87
|
+
<AtomicIcon name="sparkles" color="onPrimary" size="sm" />
|
|
88
|
+
<AtomicText type="labelLarge" color="onPrimary" style={styles.fabText}>
|
|
89
|
+
{t("loveMessage.generateMore")}
|
|
90
|
+
</AtomicText>
|
|
91
|
+
</Pressable>
|
|
92
|
+
</View>
|
|
93
|
+
</View>
|
|
94
|
+
);
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
const styles = StyleSheet.create({
|
|
98
|
+
container: { flex: 1 },
|
|
99
|
+
header: {
|
|
100
|
+
flexDirection: "row",
|
|
101
|
+
justifyContent: "space-between",
|
|
102
|
+
alignItems: "center",
|
|
103
|
+
paddingHorizontal: 8,
|
|
104
|
+
paddingBottom: 16,
|
|
105
|
+
},
|
|
106
|
+
backBtn: { padding: 12 },
|
|
107
|
+
headerTitle: { fontWeight: "bold" },
|
|
108
|
+
spacer: { width: 44 },
|
|
109
|
+
headlineContainer: { paddingVertical: 24 },
|
|
110
|
+
headline: { fontWeight: "bold", marginBottom: 4 },
|
|
111
|
+
fabContainer: {
|
|
112
|
+
position: "absolute",
|
|
113
|
+
left: 20,
|
|
114
|
+
right: 20,
|
|
115
|
+
alignItems: "center",
|
|
116
|
+
},
|
|
117
|
+
fab: {
|
|
118
|
+
flexDirection: "row",
|
|
119
|
+
alignItems: "center",
|
|
120
|
+
justifyContent: "center",
|
|
121
|
+
paddingVertical: 16,
|
|
122
|
+
paddingHorizontal: 24,
|
|
123
|
+
borderRadius: 32,
|
|
124
|
+
gap: 12,
|
|
125
|
+
},
|
|
126
|
+
fabText: { fontWeight: "bold", letterSpacing: 1 },
|
|
127
|
+
});
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Partner Profile Screen
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { FC } from "react";
|
|
6
|
+
import { View, ScrollView, StyleSheet } from "react-native";
|
|
7
|
+
import {
|
|
8
|
+
AtomicText,
|
|
9
|
+
AtomicButton,
|
|
10
|
+
useAppDesignTokens,
|
|
11
|
+
useSafeAreaInsets,
|
|
12
|
+
useAppNavigation,
|
|
13
|
+
} from "@umituz/react-native-design-system";
|
|
14
|
+
import { useLocalization } from "@umituz/react-native-localization";
|
|
15
|
+
import { LOVE_LANGUAGES } from "../../domain/constants";
|
|
16
|
+
import { usePartnerProfile } from "../hooks/usePartnerProfile";
|
|
17
|
+
import { FieldInput } from "../components/FieldInput";
|
|
18
|
+
|
|
19
|
+
export const PartnerProfileScreen: FC = () => {
|
|
20
|
+
const tokens = useAppDesignTokens();
|
|
21
|
+
const { top, bottom } = useSafeAreaInsets();
|
|
22
|
+
const { t } = useLocalization();
|
|
23
|
+
const navigation = useAppNavigation();
|
|
24
|
+
const p = usePartnerProfile(() => navigation.goBack());
|
|
25
|
+
|
|
26
|
+
if (p.isLoading) return null;
|
|
27
|
+
|
|
28
|
+
return (
|
|
29
|
+
<View style={[styles.container, { backgroundColor: tokens.colors.backgroundPrimary }]}>
|
|
30
|
+
<View style={[styles.header, { paddingTop: top + tokens.spacing.md }]}>
|
|
31
|
+
<AtomicButton icon="arrow-back" onPress={() => navigation.goBack()} variant="text" size="sm" />
|
|
32
|
+
<View style={styles.headerTitle}>
|
|
33
|
+
<AtomicText type="headlineSmall" color="textPrimary" style={styles.headerText}>
|
|
34
|
+
{t("loveMessage.partnerProfile.title")}
|
|
35
|
+
</AtomicText>
|
|
36
|
+
</View>
|
|
37
|
+
</View>
|
|
38
|
+
|
|
39
|
+
<ScrollView
|
|
40
|
+
contentContainerStyle={{
|
|
41
|
+
paddingBottom: bottom + tokens.spacing.xl,
|
|
42
|
+
paddingHorizontal: tokens.spacing.lg,
|
|
43
|
+
}}
|
|
44
|
+
showsVerticalScrollIndicator={false}
|
|
45
|
+
>
|
|
46
|
+
<AtomicText type="bodyMedium" color="textSecondary" style={styles.subtitle}>
|
|
47
|
+
{t("loveMessage.partnerProfile.subtitle")}
|
|
48
|
+
</AtomicText>
|
|
49
|
+
|
|
50
|
+
<FieldInput
|
|
51
|
+
label={t("loveMessage.partnerName")}
|
|
52
|
+
value={p.profile.name}
|
|
53
|
+
onChange={(text) => p.setProfile((prev) => ({ ...prev, name: text }))}
|
|
54
|
+
placeholder={t("loveMessage.partnerNamePlaceholder")}
|
|
55
|
+
/>
|
|
56
|
+
|
|
57
|
+
<View style={styles.field}>
|
|
58
|
+
<AtomicText type="labelLarge" color="textPrimary" style={styles.label}>
|
|
59
|
+
{t("loveMessage.partnerProfile.loveLanguage")}
|
|
60
|
+
</AtomicText>
|
|
61
|
+
<View style={styles.chipContainer}>
|
|
62
|
+
{LOVE_LANGUAGES.map((lang) => (
|
|
63
|
+
<AtomicButton
|
|
64
|
+
key={lang.language}
|
|
65
|
+
title={t(lang.labelKey)}
|
|
66
|
+
onPress={() => p.setProfile((prev) => ({ ...prev, loveLanguage: lang.language }))}
|
|
67
|
+
variant={p.profile.loveLanguage === lang.language ? "primary" : "outline"}
|
|
68
|
+
size="sm"
|
|
69
|
+
style={styles.chip}
|
|
70
|
+
/>
|
|
71
|
+
))}
|
|
72
|
+
</View>
|
|
73
|
+
</View>
|
|
74
|
+
|
|
75
|
+
<FieldInput
|
|
76
|
+
label={t("loveMessage.partnerProfile.traits")}
|
|
77
|
+
value={p.profile.traits}
|
|
78
|
+
onChange={(text) => p.setProfile((prev) => ({ ...prev, traits: text }))}
|
|
79
|
+
placeholder={t("loveMessage.partnerProfile.traitsPlaceholder")}
|
|
80
|
+
/>
|
|
81
|
+
|
|
82
|
+
<FieldInput
|
|
83
|
+
label={t("loveMessage.partnerProfile.quirks")}
|
|
84
|
+
value={p.profile.quirks}
|
|
85
|
+
onChange={(text) => p.setProfile((prev) => ({ ...prev, quirks: text }))}
|
|
86
|
+
placeholder={t("loveMessage.partnerProfile.quirksPlaceholder")}
|
|
87
|
+
multiline
|
|
88
|
+
/>
|
|
89
|
+
|
|
90
|
+
<AtomicButton
|
|
91
|
+
title={t("loveMessage.partnerProfile.save")}
|
|
92
|
+
onPress={p.handleSave}
|
|
93
|
+
disabled={!p.profile.name.trim()}
|
|
94
|
+
variant="primary"
|
|
95
|
+
fullWidth
|
|
96
|
+
style={styles.saveBtn}
|
|
97
|
+
/>
|
|
98
|
+
</ScrollView>
|
|
99
|
+
</View>
|
|
100
|
+
);
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
const styles = StyleSheet.create({
|
|
104
|
+
container: { flex: 1 },
|
|
105
|
+
header: {
|
|
106
|
+
flexDirection: "row",
|
|
107
|
+
alignItems: "center",
|
|
108
|
+
paddingHorizontal: 8,
|
|
109
|
+
paddingBottom: 24,
|
|
110
|
+
},
|
|
111
|
+
headerTitle: { flex: 1, marginRight: 40, alignItems: "center" },
|
|
112
|
+
headerText: { fontWeight: "bold" },
|
|
113
|
+
subtitle: { marginBottom: 32 },
|
|
114
|
+
field: { marginBottom: 24 },
|
|
115
|
+
label: { marginBottom: 10, marginLeft: 4 },
|
|
116
|
+
chipContainer: { flexDirection: "row", flexWrap: "wrap", gap: 10 },
|
|
117
|
+
chip: { borderRadius: 20 },
|
|
118
|
+
saveBtn: { height: 56, borderRadius: 16, marginTop: 16 },
|
|
119
|
+
});
|
|
@@ -139,6 +139,55 @@ export interface ScenarioConfig {
|
|
|
139
139
|
readonly title: string;
|
|
140
140
|
}
|
|
141
141
|
|
|
142
|
+
/**
|
|
143
|
+
* Visual style option for prompt customization
|
|
144
|
+
*/
|
|
145
|
+
export interface VisualStyleOption {
|
|
146
|
+
readonly id: string;
|
|
147
|
+
readonly icon: string;
|
|
148
|
+
readonly labelKey: string;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Inspiration chip data for prompt customization
|
|
153
|
+
*/
|
|
154
|
+
export interface InspirationChipData {
|
|
155
|
+
readonly id: string;
|
|
156
|
+
readonly labelKey: string;
|
|
157
|
+
readonly promptKey: string;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Magic prompt configuration
|
|
162
|
+
*/
|
|
163
|
+
export interface MagicPromptConfig {
|
|
164
|
+
readonly headerKey: string;
|
|
165
|
+
readonly headlinePart1Key: string;
|
|
166
|
+
readonly headlinePart2Key: string;
|
|
167
|
+
readonly subtitleKey: string;
|
|
168
|
+
readonly inputLabelKey: string;
|
|
169
|
+
readonly surpriseButtonKey: string;
|
|
170
|
+
readonly placeholderKey: string;
|
|
171
|
+
readonly styleTitleKey: string;
|
|
172
|
+
readonly inspirationTitleKey: string;
|
|
173
|
+
readonly continueKey: string;
|
|
174
|
+
readonly maxLength: number;
|
|
175
|
+
readonly minLength: number;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Couple feature identifier
|
|
180
|
+
*/
|
|
181
|
+
export type CoupleFeatureId = string;
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Couple feature selection state
|
|
185
|
+
*/
|
|
186
|
+
export interface CoupleFeatureSelection {
|
|
187
|
+
readonly featureId: CoupleFeatureId | null;
|
|
188
|
+
readonly [key: string]: any;
|
|
189
|
+
}
|
|
190
|
+
|
|
142
191
|
export interface ScenarioData {
|
|
143
192
|
readonly id: string;
|
|
144
193
|
readonly category?: string;
|
package/src/index.ts
CHANGED
|
@@ -141,6 +141,7 @@ export * from "./domains/content-moderation";
|
|
|
141
141
|
export * from "./domains/creations";
|
|
142
142
|
export * from "./domains/face-detection";
|
|
143
143
|
export * from "./domains/scenarios";
|
|
144
|
+
export * from "./domains/love-message";
|
|
144
145
|
export * from "./infrastructure/orchestration";
|
|
145
146
|
|
|
146
147
|
// Generation Config Provider (App Configuration)
|