diff --git a/components/ask/aiChat.tsx b/components/ask/aiChat.tsx index 1163829..58dcc95 100644 --- a/components/ask/aiChat.tsx +++ b/components/ask/aiChat.tsx @@ -18,7 +18,7 @@ import ContextMenu from "../gusture/contextMenu"; import { ThemedText } from "../ThemedText"; import SelectModel from "./selectModel"; import SingleContentModel from "./singleContentModel"; -import TypewriterText from "./typewriterText"; +import Loading from './threeCircle'; import { mergeArrays, saveMediaToGallery } from "./utils"; interface RenderMessageProps { @@ -42,102 +42,112 @@ const MessageItem = ({ setCancel, cancel = true, t, insets, item, sessionId, set return ( {!isUser && } - - 0 || item.content.image_material_infos && item.content.image_material_infos.length > 0) ? '!rounded-t-3xl !rounded-b-2xl' : '!rounded-3xl'}`} - > - - - {!isUser - ? - sessionId ? item.content.text : - : item.content.text - } - + + + 0 || item.content.image_material_infos && item.content.image_material_infos.length > 0) ? '!rounded-t-3xl !rounded-b-2xl' : '!rounded-3xl'}`} + style={[ + styles.messageBubble, + isUser ? styles.userBubble : styles.aiBubble, + { marginRight: item.content.text == "正在寻找,请稍等..." ? 0 : isUser ? 0 : 10 } + ]} + > + + + {!isUser + ? + sessionId ? item.content.text : item.content.text == "正在寻找,请稍等..." ? : item.content.text + : item.content.text + } + - {(mergeArrays(item.content.image_material_infos || [], item.content.video_material_infos || [])?.length || 0 > 0) && ( - - - {mergeArrays(item.content.image_material_infos || [], item.content.video_material_infos || [])?.slice(0, 3)?.map((image) => ( - { - setModalVisible({ visible: true, data: image }); - }} - style={{ - width: '32%', - aspectRatio: 1, - marginBottom: 8, - }} - > - , - label: t("ask:ask.save"), - onPress: () => { - const imageUrl = image?.preview_file_info?.url || image.video?.preview_file_info?.url; - if (imageUrl) { - saveMediaToGallery(imageUrl, t); - } - }, - textStyle: { color: '#4C320C' } - }, - { - svg: , - label: t("ask:ask.cancel"), - onPress: () => { - setCancel(true); - }, - textStyle: { color: 'red' } - } - ]} - cancel={cancel} - menuStyle={{ - backgroundColor: 'white', - borderRadius: 8, - padding: 8, - minWidth: 150, - shadowColor: '#000', - shadowOffset: { width: 0, height: 2 }, - shadowOpacity: 0.25, - shadowRadius: 4, - elevation: 5, + {(mergeArrays(item.content.image_material_infos || [], item.content.video_material_infos || [])?.length || 0 > 0) && ( + + + {mergeArrays(item.content.image_material_infos || [], item.content.video_material_infos || [])?.slice(0, 3)?.map((image) => ( + { + setModalVisible({ visible: true, data: image }); + }} + style={{ + width: '32%', + aspectRatio: 1, + marginBottom: 8, }} > - , + label: t("ask:ask.save"), + onPress: () => { + const imageUrl = image?.preview_file_info?.url || image.video?.preview_file_info?.url; + if (imageUrl) { + saveMediaToGallery(imageUrl, t); + } + }, + textStyle: { color: '#4C320C' } + }, + { + svg: , + label: t("ask:ask.cancel"), + onPress: () => { + setCancel(true); + }, + textStyle: { color: 'red' } + } + ]} + cancel={cancel} + menuStyle={{ + backgroundColor: 'white', + borderRadius: 8, + padding: 8, + minWidth: 150, + shadowColor: '#000', + shadowOffset: { width: 0, height: 2 }, + shadowOpacity: 0.25, + shadowRadius: 4, + elevation: 5, }} - resizeMode="cover" - loadingIndicatorSource={require('@/assets/images/png/placeholder.png')} - /> - - - ))} + > + + + + ))} + + { + ((item.content.video_material_infos?.length || 0) + (item.content.image_material_infos?.length || 0)) > 3 + && { + setSelectedImages([]) + setModalDetailsVisible({ visible: true, content: item.content }); + }}> + {((item.content.video_material_infos?.length || 0) + (item.content.image_material_infos?.length || 0))} + + + + + } - { - ((item.content.video_material_infos?.length || 0) + (item.content.image_material_infos?.length || 0)) > 3 - && { - setSelectedImages([]) - setModalDetailsVisible({ visible: true, content: item.content }); - }}> - {((item.content.video_material_infos?.length || 0) + (item.content.image_material_infos?.length || 0))} - - - - - } - - )} + )} + + { + item.content.text == "正在寻找,请稍等..." + && + + {t("ask:ask.think")} + + } {/* {item.askAgain && item.askAgain.length > 0 && ( @@ -247,10 +257,12 @@ const styles = StyleSheet.create({ userText: { color: '#4C320C', fontSize: 16, + lineHeight: 24, }, aiText: { color: '#000', fontSize: 16, + lineHeight: 24, }, }); diff --git a/components/ask/send.tsx b/components/ask/send.tsx index 08543cd..fef9621 100644 --- a/components/ask/send.tsx +++ b/components/ask/send.tsx @@ -170,11 +170,11 @@ export default function SendMessage(props: Props) { returnKeyType="send" /> - + @@ -204,18 +204,18 @@ const styles = StyleSheet.create({ borderWidth: 1, borderRadius: 25, paddingHorizontal: 20, - paddingVertical: 12, + paddingVertical: 13, fontSize: 16, width: '100%', // 确保输入框宽度撑满 paddingRight: 50 }, voiceButton: { - width: 40, - height: 40, + padding: 8, borderRadius: 20, backgroundColor: '#FF9500', justifyContent: 'center', alignItems: 'center', - marginRight: 8, // 添加一点 + position: 'absolute', + transform: [{ translateY: -12 }], }, }); \ No newline at end of file diff --git a/components/ask/threeCircle.tsx b/components/ask/threeCircle.tsx new file mode 100644 index 0000000..767dd3b --- /dev/null +++ b/components/ask/threeCircle.tsx @@ -0,0 +1,114 @@ +import React, { useEffect, useRef } from 'react'; +import { Animated, StyleSheet, View } from 'react-native'; + +const Loading = () => { + // 创建三个动画值,控制每个点的大小变化 + const anim1 = useRef(new Animated.Value(0)).current; + const anim2 = useRef(new Animated.Value(0)).current; + const anim3 = useRef(new Animated.Value(0)).current; + + // 定义动画序列 + const startAnimation = () => { + // 重置动画值 + anim1.setValue(0); + anim2.setValue(0); + anim3.setValue(0); + + // 创建动画序列 + Animated.loop( + Animated.stagger(200, [ + // 第一个点动画 + Animated.sequence([ + Animated.timing(anim1, { + toValue: 1, + duration: 400, + useNativeDriver: true, + }), + Animated.timing(anim1, { + toValue: 0, + duration: 400, + useNativeDriver: true, + }), + ]), + // 第二个点动画 + Animated.sequence([ + Animated.timing(anim2, { + toValue: 1, + duration: 400, + useNativeDriver: true, + }), + Animated.timing(anim2, { + toValue: 0, + duration: 400, + useNativeDriver: true, + }), + ]), + // 第三个点动画 + Animated.sequence([ + Animated.timing(anim3, { + toValue: 1, + duration: 400, + useNativeDriver: true, + }), + Animated.timing(anim3, { + toValue: 0, + duration: 400, + useNativeDriver: true, + }), + ]), + ]) + ).start(); + }; + + useEffect(() => { + startAnimation(); + return () => { + // 清理动画 + anim1.stopAnimation(); + anim2.stopAnimation(); + anim3.stopAnimation(); + }; + }, []); + + // 颜色插值 + const color1 = anim1.interpolate({ + inputRange: [0, 0.5, 1], + outputRange: ['#999999', '#4C320C', '#999999'], + }); + + const color2 = anim2.interpolate({ + inputRange: [0, 0.5, 1], + outputRange: ['#999999', '#4C320C', '#999999'], + }); + + const color3 = anim3.interpolate({ + inputRange: [0, 0.5, 1], + outputRange: ['#999999', '#4C320C', '#999999'], + }); + + return ( + + + + + + ); +}; + +const styles = StyleSheet.create({ + container: { + flexDirection: 'row', + alignItems: 'center', + justifyContent: 'center', + padding: 8, + }, + dot: { + width: 8, + height: 8, + borderRadius: 4, + marginHorizontal: 4, + backgroundColor: '#999999', + }, +}); + +export default Loading; \ No newline at end of file diff --git a/i18n/locales/en/ask.json b/i18n/locales/en/ask.json index cff67f7..1337485 100644 --- a/i18n/locales/en/ask.json +++ b/i18n/locales/en/ask.json @@ -30,6 +30,7 @@ "introduction2": "Looking for the perfect image? Try these search tips for better results:\n\n• Be specific: Try 'autumn forest', 'minimalist desk', or 'vintage poster design'\n\n• Add details: For specific styles, try 'watercolor cat' or 'cyberpunk city nightscape'; for specific uses, try 'royalty-free landscape' or 'commercial use icons'\n\n• Describe the scene: Try 'sunlight through leaves' or 'rainy day coffee shop window'\n\nEnter these keywords, and you might just find the perfect shot!", "introduction3": "Want to make your videos more engaging and story-driven? Start with an image search!\n\nFirst, decide on your video's theme—whether it's healing natural landscapes, retro cityscapes, or vibrant life moments. Then search for related images. For example, if your theme is 'Spring Limited,' search for 'cherry blossoms falling,' 'picnic in the grass,' or 'first buds of spring.'\n\nThese images can help you visualize your video's flow and even spark new ideas—like how an old photo of a vintage object might inspire a story about time, or how a series of starry sky images could connect into a narrative about dreams and distant places. String these images together with the right music and captions, and you've got yourself a heartwarming video. Give it a try!", "search": "Search Assets", - "video": "Create Video" + "video": "Create Video", + "think": "Thinking..." } } \ No newline at end of file diff --git a/i18n/locales/zh/ask.json b/i18n/locales/zh/ask.json index 5f46082..f933fb0 100644 --- a/i18n/locales/zh/ask.json +++ b/i18n/locales/zh/ask.json @@ -30,6 +30,7 @@ "introduction2": "想找合适的图片?试试这样搜更精准:\n\n• 明确主题:比如'秋日森林'、'极简风书桌'、'复古海报设计'\n\n• 加上细节:想找特定风格?试试'水彩风猫咪'、'赛博朋克城市夜景';需要特定用途?比如'无版权风景图'、'可商用图标'\n\n• 描述场景:比如'阳光透过树叶的光斑'、'雨天咖啡馆窗外'\n\n输入这些关键词,说不定就能找到你想要的画面啦~", "introduction3": "想让你的视频内容更吸睛、更有故事感吗?不妨试试从搜索图片入手吧!\n\n你可以先确定视频的主题——是治愈系的自然风景,还是复古风的城市街景,或是充满活力的生活瞬间?然后根据主题去搜索相关的图片,比如想做'春日限定'主题,就搜'樱花飘落''草地野餐''嫩芽初绽'之类的画面。\n\n这些图片能帮你快速理清视频的画面脉络,甚至能激发新的创意——比如一张老照片里的复古物件,或许能延伸出一段关于时光的故事;一组星空图片,说不定能串联成关于梦想与远方的叙事。把这些图片按你的想法串联起来,配上合适的音乐和文案,一段有温度的视频就诞生啦,试试看吧~", "search": "检索素材", - "video": "创作视频" + "video": "创作视频", + "think": "思考中..." } } \ No newline at end of file