feat: ask页面
This commit is contained in:
parent
6efc508fa0
commit
d7e07b327a
@ -57,6 +57,7 @@ export default function AskScreen() {
|
||||
if (translationX > threshold) {
|
||||
// 从左向右滑动,跳转页面
|
||||
runOnJS(router.replace)("/memo-list");
|
||||
runOnJS(setConversationId)("")
|
||||
}
|
||||
})
|
||||
.minPointers(1)
|
||||
@ -244,11 +245,12 @@ export default function AskScreen() {
|
||||
|
||||
useFocusEffect(
|
||||
useCallback(() => {
|
||||
Keyboard.dismiss();
|
||||
if (!sessionId) {
|
||||
setIsHello(true);
|
||||
setUserMessages([])
|
||||
}
|
||||
}, [sessionId])
|
||||
}, [sessionId, Keyboard])
|
||||
);
|
||||
|
||||
return (
|
||||
|
||||
@ -13,6 +13,7 @@ import UploaderProgress from '@/components/file-upload/upload-progress/uploader-
|
||||
import SkeletonItem from '@/components/memo/SkeletonItem';
|
||||
|
||||
// 类型定义
|
||||
import { Fonts } from '@/constants/Fonts';
|
||||
import { useUploadManager } from '@/hooks/useUploadManager';
|
||||
import { getCachedData, prefetchChatDetail, prefetchChats } from '@/lib/prefetch';
|
||||
import { fetchApi } from '@/lib/server-api-util';
|
||||
@ -227,7 +228,7 @@ const MemoList = () => {
|
||||
|
||||
return (
|
||||
<ErrorBoundary>
|
||||
<View style={[styles.container, { paddingTop: insets.top }]}>
|
||||
<View style={[styles.container, { paddingTop: insets.top + 8 }]}>
|
||||
<FlatList
|
||||
ref={flatListRef}
|
||||
data={historyList}
|
||||
@ -273,7 +274,7 @@ const styles = StyleSheet.create({
|
||||
backgroundColor: '#fff',
|
||||
},
|
||||
headerContainer: {
|
||||
paddingBottom: 16,
|
||||
paddingBottom: 8,
|
||||
backgroundColor: '#fff',
|
||||
},
|
||||
title: {
|
||||
@ -281,7 +282,8 @@ const styles = StyleSheet.create({
|
||||
fontWeight: 'bold',
|
||||
color: '#4C320C',
|
||||
textAlign: 'center',
|
||||
marginBottom: 16,
|
||||
marginBottom: 8,
|
||||
fontFamily: Fonts["quicksand"]
|
||||
},
|
||||
listContent: {
|
||||
paddingBottom: Platform.select({
|
||||
@ -314,13 +316,15 @@ const styles = StyleSheet.create({
|
||||
},
|
||||
memoTitle: {
|
||||
fontSize: 16,
|
||||
fontWeight: '500',
|
||||
fontWeight: 'bold',
|
||||
color: '#4C320C',
|
||||
marginBottom: 4,
|
||||
fontFamily: Fonts['sfPro']
|
||||
},
|
||||
memoSubtitle: {
|
||||
fontSize: 14,
|
||||
color: '#AC7E35',
|
||||
fontFamily: Fonts['inter']
|
||||
},
|
||||
separator: {
|
||||
height: 1 / PixelRatio.get(),
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { StyleProp, StyleSheet, Text, TextStyle, type TextProps } from 'react-native';
|
||||
|
||||
import { Colors } from '@/constants/Colors';
|
||||
import { FontColor, Fonts } from '@/constants/Fonts';
|
||||
import { FontColor, Fonts, FontSize, FontWeight } from '@/constants/Fonts';
|
||||
import { useThemeColor } from '@/hooks/useThemeColor';
|
||||
|
||||
export type ThemeColor = keyof typeof Colors.light & keyof typeof Colors.dark;
|
||||
@ -11,9 +11,9 @@ export type ThemedTextProps = TextProps & {
|
||||
lightColor?: string;
|
||||
darkColor?: string;
|
||||
type?: 'default' | 'title' | 'defaultSemiBold' | 'subtitle' | 'link' | 'sfPro' | 'inter';
|
||||
weight?: 'regular' | 'medium' | 'semiBold' | 'bold';
|
||||
size?: 'xxs' | 'xs' | 'sm' | 'base' | 'lg' | 'xl' | '2xl' | '3xl' | '4xl' | '5xl';
|
||||
radius?: 'xs' | 'sm' | 'base' | 'lg' | 'xl' | '2xl' | '3xl' | '4xl' | '5xl';
|
||||
weight?: FontWeight;
|
||||
size?: FontSize;
|
||||
radius?: FontSize
|
||||
color?: ThemeColor | FontColor | ColorValue;
|
||||
};
|
||||
|
||||
|
||||
@ -1,9 +1,11 @@
|
||||
import { ContentPart, Message } from '@/types/ask';
|
||||
import { useFocusEffect } from 'expo-router';
|
||||
import React, { Dispatch, ForwardedRef, forwardRef, SetStateAction, useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import {
|
||||
FlatList,
|
||||
FlatListProps,
|
||||
Keyboard,
|
||||
SafeAreaView,
|
||||
View
|
||||
} from 'react-native';
|
||||
@ -52,6 +54,13 @@ function ChatComponent(
|
||||
}
|
||||
}, [userMessages.length]);
|
||||
|
||||
useFocusEffect(
|
||||
useCallback(() => {
|
||||
Keyboard.dismiss();
|
||||
}, [Keyboard, sessionId])
|
||||
);
|
||||
|
||||
|
||||
const renderMessageItem = useCallback(({ item, index }: { item: Message, index: number }) => {
|
||||
const itemStyle = index === 0 ? { marginTop: 16, marginHorizontal: 16 } : { marginHorizontal: 16 };
|
||||
return (
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import { ThemedText } from "@/components/ThemedText";
|
||||
import { Fonts } from "@/constants/Fonts";
|
||||
import { webSocketManager } from "@/lib/websocket-util";
|
||||
import { Message } from "@/types/ask";
|
||||
import { Dispatch, SetStateAction } from "react";
|
||||
@ -58,15 +59,13 @@ export default function AskHello({ setUserMessages, setConversationId, setIsHell
|
||||
keyboardShouldPersistTaps="handled"
|
||||
>
|
||||
<View className="items-center">
|
||||
<ThemedText style={{ fontSize: 32, fontWeight: 'bold', textAlign: 'center', lineHeight: 40, }}>
|
||||
<ThemedText style={{ textAlign: 'center', lineHeight: 40, }} size="title" weight="bold">
|
||||
{t('ask.hi', { ns: 'ask' })}
|
||||
{"\n"}
|
||||
{t('ask.iAmMemo', { ns: 'ask' })}
|
||||
</ThemedText>
|
||||
<View>
|
||||
<Image source={require('@/assets/images/png/icon/ip.png')} style={{ width: width * 0.5, height: height * 0.3 }} />
|
||||
</View>
|
||||
<ThemedText className="!text-textPrimary text-center -mt-10" style={{ fontSize: 16 }}>
|
||||
<Image source={require('@/assets/images/png/icon/ip.png')} style={{ width: width * 0.4, height: height * 0.25 }} />
|
||||
<ThemedText className="text-center -mt-10" size='base' color="textPrimary" type="sfPro" weight="medium">
|
||||
{t('ask.ready', { ns: 'ask' })}
|
||||
{"\n"}
|
||||
{t('ask.justAsk', { ns: 'ask' })}
|
||||
@ -112,11 +111,14 @@ const styles = StyleSheet.create({
|
||||
},
|
||||
case: {
|
||||
borderWidth: 1,
|
||||
borderColor: "#AC7E35",
|
||||
borderColor: Fonts["textPrimary"],
|
||||
borderRadius: 10,
|
||||
paddingHorizontal: 8,
|
||||
paddingVertical: 2,
|
||||
width: 'auto',
|
||||
fontSize: 14,
|
||||
color: "#4C320C"
|
||||
fontSize: Fonts["sm"],
|
||||
color: Fonts["textSecondary"],
|
||||
fontFamily: Fonts["sfPro"]
|
||||
|
||||
}
|
||||
})
|
||||
@ -12,6 +12,7 @@ import {
|
||||
View
|
||||
} from 'react-native';
|
||||
|
||||
import { Fonts } from '@/constants/Fonts';
|
||||
import { webSocketManager, WsMessage } from '@/lib/websocket-util';
|
||||
import { Message } from '@/types/ask';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
@ -190,37 +191,33 @@ export default function SendMessage(props: Props) {
|
||||
}
|
||||
]));
|
||||
let currentSessionId = conversationId;
|
||||
console.log("currentSessionIdcurrentSessionId", currentSessionId);
|
||||
|
||||
// 如果没有对话ID,先创建一个新对话
|
||||
if (!currentSessionId) {
|
||||
const newCurrentSessionId = await createNewConversation(text);
|
||||
if (newCurrentSessionId) {
|
||||
setConversationId(newCurrentSessionId);
|
||||
webSocketManager.send({
|
||||
type: 'Chat',
|
||||
session_id: newCurrentSessionId,
|
||||
message: text,
|
||||
image_material_ids: selectedImages.length > 0 ? selectedImages : undefined,
|
||||
});
|
||||
setSelectedImages([]);
|
||||
} else {
|
||||
console.error("无法获取 session_id,消息发送失败。");
|
||||
console.error("无法获取 session_id,消息发送失败1。");
|
||||
setUserMessages(prev => prev.filter(item => item.content !== 'keepSearchIng'));
|
||||
}
|
||||
}
|
||||
|
||||
// 通过 WebSocket 发送消息
|
||||
if (currentSessionId) {
|
||||
webSocketManager.send({
|
||||
type: 'Chat',
|
||||
session_id: currentSessionId,
|
||||
message: text,
|
||||
image_material_ids: selectedImages.length > 0 ? selectedImages : undefined,
|
||||
});
|
||||
setSelectedImages([]);
|
||||
} else {
|
||||
console.error("无法获取 session_id,消息发送失败。");
|
||||
// 可以在这里处理错误,例如显示一个提示
|
||||
setUserMessages(prev => prev.filter(item => item.content !== 'keepSearchIng'));
|
||||
try {
|
||||
webSocketManager.send({
|
||||
type: 'Chat',
|
||||
session_id: currentSessionId,
|
||||
message: text,
|
||||
image_material_ids: selectedImages.length > 0 ? selectedImages : undefined,
|
||||
});
|
||||
setSelectedImages([]);
|
||||
} catch (error) {
|
||||
console.error("无法获取 session_id,消息发送失败2。", error);
|
||||
setUserMessages(prev => prev.filter(item => item.content !== 'keepSearchIng'));
|
||||
}
|
||||
}
|
||||
// 将输入框清空
|
||||
setInputValue('');
|
||||
@ -252,16 +249,17 @@ export default function SendMessage(props: Props) {
|
||||
<ScrollView horizontal={true} style={{ display: isHello ? 'flex' : 'none' }}>
|
||||
<TouchableOpacity style={[styles.button, { borderColor: '#FFB645' }]} onPress={() => handleQuitly('search')}>
|
||||
<SunSvg width={18} height={18} />
|
||||
<ThemedText>{t("ask:ask.search")}</ThemedText>
|
||||
</TouchableOpacity><TouchableOpacity style={[styles.button, { borderColor: '#E2793F' }]} onPress={() => handleQuitly('video')}>
|
||||
<ThemedText type="sfPro" size="sm" weight='regular' color='textSecondary'>{t("ask:ask.search")}</ThemedText>
|
||||
</TouchableOpacity>
|
||||
<TouchableOpacity style={[styles.button, { borderColor: '#E2793F' }]} onPress={() => handleQuitly('video')}>
|
||||
<VideoSvg width={18} height={18} />
|
||||
<ThemedText>{t("ask:ask.video")}</ThemedText>
|
||||
<ThemedText type="sfPro" size="sm" weight='regular' color='textSecondary'>{t("ask:ask.video")}</ThemedText>
|
||||
</TouchableOpacity>
|
||||
</ScrollView>
|
||||
<TextInput
|
||||
style={styles.input}
|
||||
placeholder="Ask MeMo Anything..."
|
||||
placeholderTextColor="#999"
|
||||
placeholderTextColor={Fonts["textPrimary"]}
|
||||
value={inputValue}
|
||||
onChangeText={(text: string) => {
|
||||
setInputValue(text);
|
||||
@ -296,25 +294,23 @@ const styles = StyleSheet.create({
|
||||
display: 'flex',
|
||||
flexDirection: 'row',
|
||||
gap: 5,
|
||||
// backgroundColor: '#F8F8F8'
|
||||
},
|
||||
container: {
|
||||
justifyContent: 'center',
|
||||
backgroundColor: '#transparent',
|
||||
},
|
||||
input: {
|
||||
// borderColor: '#d9d9d9',
|
||||
color: Fonts["textPrimary"],
|
||||
borderColor: '#AC7E35',
|
||||
borderWidth: 1,
|
||||
// borderRadius: 18,
|
||||
borderRadius: 25,
|
||||
borderRadius: 28,
|
||||
paddingHorizontal: 20,
|
||||
paddingVertical: 13,
|
||||
paddingVertical: 16,
|
||||
lineHeight: 20,
|
||||
fontSize: 16,
|
||||
width: '100%', // 确保输入框宽度撑满
|
||||
width: '100%',
|
||||
paddingRight: 50,
|
||||
backgroundColor: '#fff', // Required for shadow to show on iOS
|
||||
backgroundColor: '#fff',
|
||||
shadowColor: '#000',
|
||||
shadowOffset: {
|
||||
width: 0,
|
||||
@ -322,7 +318,6 @@ const styles = StyleSheet.create({
|
||||
},
|
||||
shadowOpacity: 0.15,
|
||||
shadowRadius: 3.84,
|
||||
// Shadow for Android
|
||||
elevation: 5,
|
||||
},
|
||||
voiceButton: {
|
||||
|
||||
@ -26,7 +26,7 @@ const MessageBubble = ({
|
||||
}: MessageBubbleProps) => {
|
||||
return (
|
||||
<View
|
||||
className={`${isUser ? '!bg-bgPrimary ml-10 rounded-full' : '!bg-aiBubble rounded-2xl'} border-0 ${!isUser && isMessageContainMedia(item) ? '!rounded-t-3xl !rounded-b-2xl' : '!rounded-3xl'} px-3`}
|
||||
className={`${isUser ? '!bg-bgPrimary ml-10 rounded-full' : '!bg-aiBubble rounded-2xl'} border-0 ${!isUser && isMessageContainMedia(item) ? '!rounded-3xl' : '!rounded-3xl'} px-3`}
|
||||
style={{ marginRight: getMessageText(item) == "keepSearchIng" ? 0 : isUser ? 0 : 10 }}
|
||||
>
|
||||
<MessageContent
|
||||
|
||||
@ -4,11 +4,10 @@ import { TFunction } from "i18next";
|
||||
import React from 'react';
|
||||
import {
|
||||
StyleSheet,
|
||||
TouchableOpacity,
|
||||
View
|
||||
} from 'react-native';
|
||||
|
||||
import { ThemedText } from "@/components/ThemedText";
|
||||
import { Fonts } from "@/constants/Fonts";
|
||||
import MessageRow from './MessageRow';
|
||||
|
||||
interface RenderMessageProps {
|
||||
@ -24,10 +23,9 @@ interface RenderMessageProps {
|
||||
t: TFunction;
|
||||
setCancel: React.Dispatch<React.SetStateAction<boolean>>;
|
||||
cancel: boolean;
|
||||
setUserMessages: React.Dispatch<React.SetStateAction<Message[]>>;
|
||||
}
|
||||
|
||||
const MessageItem = ({ setCancel, cancel = true, t, insets, item, sessionId, setModalVisible, modalVisible, setModalDetailsVisible, modalDetailsVisible, setSelectedImages, selectedImages, setUserMessages }: RenderMessageProps) => {
|
||||
const MessageItem = ({ setCancel, cancel = true, t, insets, item, sessionId, setModalVisible, modalVisible, setModalDetailsVisible, modalDetailsVisible, setSelectedImages, selectedImages }: RenderMessageProps) => {
|
||||
const isUser = item.role === User;
|
||||
|
||||
return (
|
||||
@ -44,7 +42,7 @@ const MessageItem = ({ setCancel, cancel = true, t, insets, item, sessionId, set
|
||||
setSelectedImages={setSelectedImages}
|
||||
setModalDetailsVisible={setModalDetailsVisible}
|
||||
/>
|
||||
{item.content instanceof Array && item.content.filter((media: ContentPart) => media.type !== 'text').length > 0 && (
|
||||
{/* {item.content instanceof Array && item.content.filter((media: ContentPart) => media.type !== 'text').length > 0 && (
|
||||
<View style={styles.tips}>
|
||||
<TouchableOpacity style={[styles.tip, { borderRadius: 16 }]} onPress={() => {
|
||||
|
||||
@ -55,7 +53,7 @@ const MessageItem = ({ setCancel, cancel = true, t, insets, item, sessionId, set
|
||||
<ThemedText style={styles.tipText}>Help me find materials for subsequent operations.</ThemedText>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
)}
|
||||
)} */}
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
@ -74,7 +72,8 @@ const styles = StyleSheet.create({
|
||||
},
|
||||
tipText: {
|
||||
color: '#4C320C',
|
||||
fontSize: 14
|
||||
fontSize: 14,
|
||||
fontFamily: Fonts['inter']
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@ -22,6 +22,7 @@ export const Fonts = {
|
||||
'3xl': 30,
|
||||
'4xl': 36,
|
||||
'5xl': 48,
|
||||
"title": 32,
|
||||
|
||||
// color
|
||||
bgPrimary: '#FFB645',
|
||||
@ -37,6 +38,6 @@ export const Fonts = {
|
||||
} as const;
|
||||
|
||||
export type FontWeight = keyof Omit<typeof Fonts, 'quicksand' | 'sfPro' | 'inter' | 'xs' | 'sm' | 'base' | 'lg' | 'xl' | '2xl' | '3xl' | '4xl' | '5xl'>;
|
||||
export type FontSize = 'xs' | 'sm' | 'base' | 'lg' | 'xl' | '2xl' | '3xl' | '4xl' | '5xl';
|
||||
export type FontSize = 'xs' | 'sm' | 'base' | 'lg' | 'xl' | '2xl' | '3xl' | '4xl' | '5xl' | 'title';
|
||||
export type FontColor = 'bgPrimary' | 'bgSecondary' | 'textPrimary' | 'textSecondary' | 'textThird' | 'textWhite';
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user