feat: 兼容
This commit is contained in:
parent
39b768f2cc
commit
436b44a107
@ -1,3 +1,4 @@
|
|||||||
|
import IP from '@/assets/icons/svg/ip.svg';
|
||||||
import * as MediaLibrary from 'expo-media-library';
|
import * as MediaLibrary from 'expo-media-library';
|
||||||
import { useRouter } from 'expo-router';
|
import { useRouter } from 'expo-router';
|
||||||
import * as SecureStore from 'expo-secure-store';
|
import * as SecureStore from 'expo-secure-store';
|
||||||
@ -96,7 +97,7 @@ export default function HomeScreen() {
|
|||||||
isLoggedIn ? <MemoList /> :
|
isLoggedIn ? <MemoList /> :
|
||||||
<View className="flex-1 bg-bgPrimary px-[1rem] h-screen overflow-auto py-[2rem] " style={{ paddingTop: insets.top + 48 }}>
|
<View className="flex-1 bg-bgPrimary px-[1rem] h-screen overflow-auto py-[2rem] " style={{ paddingTop: insets.top + 48 }}>
|
||||||
{/* 标题区域 */}
|
{/* 标题区域 */}
|
||||||
<View className="items-center mb-10 w-full px-5">
|
<View className="mb-10 w-full px-5">
|
||||||
<Text className="text-white text-3xl font-bold mb-3 text-left">
|
<Text className="text-white text-3xl font-bold mb-3 text-left">
|
||||||
{t('auth.welcomeAwaken.awaken', { ns: 'login' })}
|
{t('auth.welcomeAwaken.awaken', { ns: 'login' })}
|
||||||
{"\n"}
|
{"\n"}
|
||||||
@ -110,9 +111,9 @@ export default function HomeScreen() {
|
|||||||
</View>
|
</View>
|
||||||
|
|
||||||
{/* Memo 形象区域 */}
|
{/* Memo 形象区域 */}
|
||||||
{/* <View className="items-center">
|
<View className="items-center">
|
||||||
<IP />
|
<IP />
|
||||||
</View> */}
|
</View>
|
||||||
|
|
||||||
{/* 介绍文本 */}
|
{/* 介绍文本 */}
|
||||||
<Text className="text-white text-base text-center mb-[1rem] leading-6 opacity-90 px-10 -mt-[4rem]">
|
<Text className="text-white text-base text-center mb-[1rem] leading-6 opacity-90 px-10 -mt-[4rem]">
|
||||||
|
|||||||
45
components/ask/VideoPlayer.tsx
Normal file
45
components/ask/VideoPlayer.tsx
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
import { useVideoPlayer, VideoView } from 'expo-video';
|
||||||
|
import {
|
||||||
|
Pressable,
|
||||||
|
StyleProp,
|
||||||
|
ViewStyle
|
||||||
|
} from 'react-native';
|
||||||
|
|
||||||
|
const VideoPlayer = ({
|
||||||
|
videoUrl,
|
||||||
|
style,
|
||||||
|
onPress
|
||||||
|
}: {
|
||||||
|
videoUrl: string;
|
||||||
|
style?: StyleProp<ViewStyle>;
|
||||||
|
onPress?: () => void;
|
||||||
|
}) => {
|
||||||
|
const player = useVideoPlayer(videoUrl, (player) => {
|
||||||
|
player.loop = true;
|
||||||
|
player.play();
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Pressable
|
||||||
|
style={[{
|
||||||
|
flex: 1,
|
||||||
|
justifyContent: 'center',
|
||||||
|
alignItems: 'center',
|
||||||
|
}, style]}
|
||||||
|
onPress={onPress}
|
||||||
|
>
|
||||||
|
<VideoView
|
||||||
|
style={{
|
||||||
|
width: '100%',
|
||||||
|
height: '100%',
|
||||||
|
backgroundColor: '#000', // 添加背景色
|
||||||
|
}}
|
||||||
|
player={player}
|
||||||
|
allowsFullscreen
|
||||||
|
allowsPictureInPicture
|
||||||
|
/>
|
||||||
|
</Pressable>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default VideoPlayer
|
||||||
@ -5,24 +5,22 @@ import ReturnArrow from "@/assets/icons/svg/returnArrow.svg";
|
|||||||
import YesSvg from "@/assets/icons/svg/yes.svg";
|
import YesSvg from "@/assets/icons/svg/yes.svg";
|
||||||
import { Message, Video } from "@/types/ask";
|
import { Message, Video } from "@/types/ask";
|
||||||
import { MaterialItem } from "@/types/personal-info";
|
import { MaterialItem } from "@/types/personal-info";
|
||||||
import { useVideoPlayer, VideoView } from 'expo-video';
|
import { TFunction } from "i18next";
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { useTranslation } from "react-i18next";
|
|
||||||
import {
|
import {
|
||||||
FlatList,
|
FlatList,
|
||||||
Image,
|
Image,
|
||||||
Modal,
|
Modal,
|
||||||
Pressable,
|
Pressable,
|
||||||
StyleProp,
|
|
||||||
StyleSheet,
|
StyleSheet,
|
||||||
Text,
|
Text,
|
||||||
TouchableOpacity,
|
TouchableOpacity,
|
||||||
View,
|
View
|
||||||
ViewStyle
|
|
||||||
} from 'react-native';
|
} from 'react-native';
|
||||||
import { ThemedText } from "../ThemedText";
|
import { ThemedText } from "../ThemedText";
|
||||||
import TypewriterText from "./typewriterText";
|
import TypewriterText from "./typewriterText";
|
||||||
import { mergeArrays } from "./utils";
|
import { mergeArrays } from "./utils";
|
||||||
|
import VideoPlayer from "./VideoPlayer";
|
||||||
|
|
||||||
interface RenderMessageProps {
|
interface RenderMessageProps {
|
||||||
insets: { top: number };
|
insets: { top: number };
|
||||||
@ -34,51 +32,14 @@ interface RenderMessageProps {
|
|||||||
modalDetailsVisible: boolean;
|
modalDetailsVisible: boolean;
|
||||||
setSelectedImages: React.Dispatch<React.SetStateAction<string[]>>;
|
setSelectedImages: React.Dispatch<React.SetStateAction<string[]>>;
|
||||||
selectedImages: string[];
|
selectedImages: string[];
|
||||||
|
t: TFunction;
|
||||||
}
|
}
|
||||||
|
|
||||||
const renderMessage = ({ insets, item, sessionId, setModalVisible, modalVisible, setModalDetailsVisible, modalDetailsVisible, setSelectedImages, selectedImages }: RenderMessageProps) => {
|
const MessageItem = ({ t, insets, item, sessionId, setModalVisible, modalVisible, setModalDetailsVisible, modalDetailsVisible, setSelectedImages, selectedImages }: RenderMessageProps) => {
|
||||||
const isUser = item.role === 'User';
|
const isUser = item.role === 'User';
|
||||||
const isVideo = (data: Video | MaterialItem): data is Video => {
|
const isVideo = (data: Video | MaterialItem): data is Video => {
|
||||||
return 'video' in data;
|
return 'video' in data;
|
||||||
};
|
};
|
||||||
const { t } = useTranslation();
|
|
||||||
// 创建一个新的 VideoPlayer 组件
|
|
||||||
const VideoPlayer = ({
|
|
||||||
videoUrl,
|
|
||||||
style,
|
|
||||||
onPress
|
|
||||||
}: {
|
|
||||||
videoUrl: string;
|
|
||||||
style?: StyleProp<ViewStyle>;
|
|
||||||
onPress?: () => void;
|
|
||||||
}) => {
|
|
||||||
const player = useVideoPlayer(videoUrl, (player) => {
|
|
||||||
player.loop = true;
|
|
||||||
player.play();
|
|
||||||
});
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Pressable
|
|
||||||
style={[{
|
|
||||||
flex: 1,
|
|
||||||
justifyContent: 'center',
|
|
||||||
alignItems: 'center',
|
|
||||||
}, style]}
|
|
||||||
onPress={onPress}
|
|
||||||
>
|
|
||||||
<VideoView
|
|
||||||
style={{
|
|
||||||
width: '100%',
|
|
||||||
height: '100%',
|
|
||||||
backgroundColor: '#000', // 添加背景色
|
|
||||||
}}
|
|
||||||
player={player}
|
|
||||||
allowsFullscreen
|
|
||||||
allowsPictureInPicture
|
|
||||||
/>
|
|
||||||
</Pressable>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View className={`flex-row items-start gap-2 w-full ${isUser ? 'justify-end' : 'justify-start'}`}>
|
<View className={`flex-row items-start gap-2 w-full ${isUser ? 'justify-end' : 'justify-start'}`}>
|
||||||
@ -304,7 +265,7 @@ const renderMessage = ({ insets, item, sessionId, setModalVisible, modalVisible,
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default renderMessage;
|
export default MessageItem;
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
imageGridContainer: {
|
imageGridContainer: {
|
||||||
|
|||||||
@ -1,12 +1,13 @@
|
|||||||
import { Message, Video } from '@/types/ask';
|
import { Message, Video } from '@/types/ask';
|
||||||
import { MaterialItem } from '@/types/personal-info';
|
import { MaterialItem } from '@/types/personal-info';
|
||||||
import React, { Dispatch, memo, SetStateAction, useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
import React, { Dispatch, memo, SetStateAction, useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
import {
|
import {
|
||||||
FlatList,
|
FlatList,
|
||||||
SafeAreaView
|
SafeAreaView
|
||||||
} from 'react-native';
|
} from 'react-native';
|
||||||
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
||||||
import renderMessage from "./aiChat";
|
import MessageItem from './aiChat';
|
||||||
|
|
||||||
interface ChatProps {
|
interface ChatProps {
|
||||||
userMessages: Message[];
|
userMessages: Message[];
|
||||||
@ -19,7 +20,7 @@ function ChatComponent({ userMessages, sessionId, setSelectedImages, selectedIma
|
|||||||
const flatListRef = useRef<FlatList>(null);
|
const flatListRef = useRef<FlatList>(null);
|
||||||
const insets = useSafeAreaInsets();
|
const insets = useSafeAreaInsets();
|
||||||
const [modalVisible, setModalVisible] = React.useState({ visible: false, data: {} as Video | MaterialItem });
|
const [modalVisible, setModalVisible] = React.useState({ visible: false, data: {} as Video | MaterialItem });
|
||||||
|
const { t } = useTranslation();
|
||||||
// 使用 useCallback 缓存 keyExtractor 函数
|
// 使用 useCallback 缓存 keyExtractor 函数
|
||||||
const keyExtractor = useCallback((item: Message) => `${item.role}-${item.timestamp}`, []);
|
const keyExtractor = useCallback((item: Message) => `${item.role}-${item.timestamp}`, []);
|
||||||
|
|
||||||
@ -51,7 +52,7 @@ function ChatComponent({ userMessages, sessionId, setSelectedImages, selectedIma
|
|||||||
updateCellsBatchingPeriod={50}
|
updateCellsBatchingPeriod={50}
|
||||||
initialNumToRender={10}
|
initialNumToRender={10}
|
||||||
windowSize={11}
|
windowSize={11}
|
||||||
renderItem={({ item }) => renderMessage({ setSelectedImages, selectedImages, insets, item, sessionId, modalVisible, setModalVisible, setModalDetailsVisible, modalDetailsVisible })}
|
renderItem={({ item }) => MessageItem({ t, setSelectedImages, selectedImages, insets, item, sessionId, modalVisible, setModalVisible, setModalDetailsVisible, modalDetailsVisible })}
|
||||||
/>
|
/>
|
||||||
</SafeAreaView>
|
</SafeAreaView>
|
||||||
);
|
);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user