feat: 抽离 imaghe 组件,为图片增加 header

This commit is contained in:
richarjiang
2025-12-18 16:36:53 +08:00
parent feb5052fcd
commit 76c37bfeb0
47 changed files with 102 additions and 58 deletions

View File

@@ -1,10 +1,10 @@
import { Image } from '@/components/ui/Image';
import { Colors } from '@/constants/Colors';
import { useColorScheme } from '@/hooks/useColorScheme';
import { useWaterDataByDate } from '@/hooks/useWaterData';
import { getQuickWaterAmount, setQuickWaterAmount } from '@/utils/userPreferences';
import { Ionicons } from '@expo/vector-icons';
import dayjs from 'dayjs';
import { Image } from 'expo-image';
import React, { useEffect, useState } from 'react';
import {
Alert,

View File

@@ -1,9 +1,9 @@
import { Image } from '@/components/ui/Image';
import { ROUTES } from '@/constants/Routes';
import { useAppSelector } from '@/hooks/redux';
import { selectUserAge, selectUserProfile } from '@/store/userSlice';
import { fetchBasalEnergyBurned } from '@/utils/health';
import dayjs from 'dayjs';
import { Image } from 'expo-image';
import { router } from 'expo-router';
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { useTranslation } from 'react-i18next';

View File

@@ -1,10 +1,10 @@
import { ThemedText } from '@/components/ThemedText';
import { Image } from '@/components/ui/Image';
import { useI18n } from '@/hooks/useI18n';
import { useThemeColor } from '@/hooks/useThemeColor';
import { DietRecord } from '@/services/dietRecords';
import { Ionicons } from '@expo/vector-icons';
import dayjs from 'dayjs';
import { Image } from 'expo-image';
import React, { useMemo, useRef, useState } from 'react';
import { Alert, StyleSheet, Text, TouchableOpacity, View } from 'react-native';
import { RectButton, Swipeable } from 'react-native-gesture-handler';

View File

@@ -1,21 +1,21 @@
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import {
Animated,
InteractionManager,
StyleSheet,
Text,
TouchableOpacity,
View,
ViewStyle
Animated,
InteractionManager,
StyleSheet,
Text,
TouchableOpacity,
View,
ViewStyle
} from 'react-native';
import { Image } from '@/components/ui/Image';
import { useAppDispatch, useAppSelector } from '@/hooks/redux';
import { ChallengeType } from '@/services/challengesApi';
import { reportChallengeProgress, selectChallengeList } from '@/store/challengesSlice';
import { fetchHourlyStepSamples, fetchStepCount, HourlyStepData } from '@/utils/health';
import { logger } from '@/utils/logger';
import dayjs from 'dayjs';
import { Image } from 'expo-image';
import { useRouter } from 'expo-router';
import { useTranslation } from 'react-i18next';
import { AnimatedNumber } from './AnimatedNumber';

View File

@@ -1,6 +1,6 @@
import { Image } from '@/components/ui/Image';
import { fetchHRVWithStatus } from '@/utils/health';
import { convertHrvToStressIndex } from '@/utils/stress';
import { Image } from 'expo-image';
import { LinearGradient } from 'expo-linear-gradient';
import React, { useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next';

View File

@@ -1,10 +1,10 @@
import { Image } from '@/components/ui/Image';
import { useWaterDataByDate } from '@/hooks/useWaterData';
import { appStoreReviewService } from '@/services/appStoreReview';
import { getQuickWaterAmount } from '@/utils/userPreferences';
import { useFocusEffect } from '@react-navigation/native';
import dayjs from 'dayjs';
import * as Haptics from 'expo-haptics';
import { Image } from 'expo-image';
import { useRouter } from 'expo-router';
import LottieView from 'lottie-react-native';
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';

View File

@@ -1,6 +1,6 @@
import { Image } from '@/components/ui/Image';
import { MaterialCommunityIcons } from '@expo/vector-icons';
import dayjs from 'dayjs';
import { Image } from 'expo-image';
import { useRouter } from 'expo-router';
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { useTranslation } from 'react-i18next';

View File

@@ -1,10 +1,10 @@
import { Image } from '@/components/ui/Image';
import { Toast } from '@/utils/toast.utils';
import { Ionicons } from '@expo/vector-icons';
import dayjs from 'dayjs';
import { BlurView } from 'expo-blur';
import { GlassView, isLiquidGlassAvailable } from 'expo-glass-effect';
import { Image } from 'expo-image';
import { LinearGradient } from 'expo-linear-gradient';
import dayjs from 'dayjs';
import React, { useCallback, useEffect, useRef, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { Animated, Modal, Platform, Pressable, Share, StyleSheet, Text, View } from 'react-native';

View File

@@ -1,7 +1,7 @@
import { Image } from '@/components/ui/Image';
import { useI18n } from '@/hooks/useI18n';
import type { RankingItem } from '@/store/challengesSlice';
import { Ionicons } from '@expo/vector-icons';
import { Image } from 'expo-image';
import React from 'react';
import { StyleSheet, Text, View } from 'react-native';

View File

@@ -1,8 +1,8 @@
import { Image } from '@/components/ui/Image';
import { Colors } from '@/constants/Colors';
import { useColorScheme } from '@/hooks/useColorScheme';
import { Ionicons } from '@expo/vector-icons';
import { BlurView } from 'expo-blur';
import { Image } from 'expo-image';
import React from 'react';
import { ScrollView, StyleSheet, Text, TextInput, TouchableOpacity, View } from 'react-native';
import QuickChips from './QuickChips';

View File

@@ -1,7 +1,7 @@
import { Image } from '@/components/ui/Image';
import { Colors } from '@/constants/Colors';
import { useColorScheme } from '@/hooks/useColorScheme';
import { Ionicons } from '@expo/vector-icons';
import { Image } from 'expo-image';
import React from 'react';
import { StyleSheet, Text, TouchableOpacity, View } from 'react-native';
import Markdown from 'react-native-markdown-display';

View File

@@ -1,8 +1,8 @@
import { Colors, palette } from '@/constants/Colors';
import { Image } from '@/components/ui/Image';
import { palette } from '@/constants/Colors';
import { MedicalRecordItem } from '@/services/healthProfile';
import { Ionicons } from '@expo/vector-icons';
import dayjs from 'dayjs';
import { Image } from 'expo-image';
import React from 'react';
import { StyleSheet, Text, TouchableOpacity, View } from 'react-native';

View File

@@ -1,4 +1,5 @@
import { MedicalRecordCard } from '@/components/health/MedicalRecordCard';
import { Image } from '@/components/ui/Image';
import { palette } from '@/constants/Colors';
import { useAppDispatch, useAppSelector } from '@/hooks/redux';
import { useCosUpload } from '@/hooks/useCosUpload';
@@ -13,7 +14,6 @@ import {
import { Ionicons } from '@expo/vector-icons';
import dayjs from 'dayjs';
import * as DocumentPicker from 'expo-document-picker';
import { Image } from 'expo-image';
import * as ImagePicker from 'expo-image-picker';
import { LinearGradient } from 'expo-linear-gradient';
import React, { useEffect, useState } from 'react';

View File

@@ -1,5 +1,5 @@
import { Image } from '@/components/ui/Image';
import { Ionicons } from '@expo/vector-icons';
import { Image } from 'expo-image';
import { LinearGradient } from 'expo-linear-gradient';
import React, { useEffect, useRef, useState } from 'react';
import { Animated, Modal, Pressable, StyleSheet, Text, TouchableOpacity, View } from 'react-native';

View File

@@ -1,4 +1,5 @@
import { ThemedText } from '@/components/ThemedText';
import { Image } from '@/components/ui/Image';
import { useAppDispatch } from '@/hooks/redux';
import { useI18n } from '@/hooks/useI18n';
import { skipMedicationAction, takeMedicationAction } from '@/store/medicationsSlice';
@@ -6,7 +7,6 @@ import type { MedicationDisplayItem } from '@/types/medication';
import { Ionicons } from '@expo/vector-icons';
import dayjs, { Dayjs } from 'dayjs';
import { GlassView, isLiquidGlassAvailable } from 'expo-glass-effect';
import { Image } from 'expo-image';
import React, { useEffect, useState } from 'react';
import { Alert, StyleSheet, TouchableOpacity, View } from 'react-native';

View File

@@ -1,7 +1,7 @@
import { Image } from '@/components/ui/Image';
import { useI18n } from '@/hooks/useI18n';
import { Ionicons } from '@expo/vector-icons';
import { GlassView, isLiquidGlassAvailable } from 'expo-glass-effect';
import { Image } from 'expo-image';
import { LinearGradient } from 'expo-linear-gradient';
import React from 'react';
import {

View File

@@ -1,9 +1,9 @@
import { Image } from '@/components/ui/Image';
import { useAppSelector } from '@/hooks/redux';
import { useCosUpload } from '@/hooks/useCosUpload';
import { useI18n } from '@/hooks/useI18n';
import { Ionicons } from '@expo/vector-icons';
import { BlurView } from 'expo-blur';
import { Image } from 'expo-image';
import * as ImagePicker from 'expo-image-picker';
import { LinearGradient } from 'expo-linear-gradient';
import React, { useEffect, useMemo, useState } from 'react';

View File

@@ -15,10 +15,10 @@ import {
View,
} from 'react-native';
// 导入统一的食物类型定义
import { Image } from '@/components/ui/Image';
import { Colors } from '@/constants/Colors';
import { DEFAULT_IMAGE_FOOD } from '@/constants/Image';
import type { FoodItem } from '@/types/food';
import { Image } from 'expo-image';
// 导入统一的食物类型定义

View File

@@ -1,4 +1,4 @@
import { Image } from 'expo-image';
import { Image } from '@/components/ui/Image';
import React from 'react';
import { Pressable, StyleSheet, Text, View } from 'react-native';
import Animated, { FadeIn, FadeOut } from 'react-native-reanimated';

View File

@@ -1,10 +1,10 @@
import { Image } from '@/components/ui/Image';
import { useAppDispatch, useAppSelector } from '@/hooks/redux';
import { ChallengeType } from '@/services/challengesApi';
import { reportChallengeProgress, selectChallengeList } from '@/store/challengesSlice';
import { logger } from '@/utils/logger';
import { fetchCompleteSleepData, formatSleepTime } from '@/utils/sleepHealthKit';
import dayjs from 'dayjs';
import { Image } from 'expo-image';
import { router } from 'expo-router';
import React, { useEffect, useMemo, useRef, useState } from 'react';
import { useTranslation } from 'react-i18next';

44
components/ui/Image.tsx Normal file
View File

@@ -0,0 +1,44 @@
import { API_ORIGIN } from '@/constants/Api';
import Constants from 'expo-constants';
import { Image as ExpoImage, ImageProps as ExpoImageProps } from 'expo-image';
import React, { forwardRef, useMemo } from 'react';
// Construct User-Agent
const APP_NAME = Constants.expoConfig?.name || 'Out Live';
const APP_VERSION = Constants.expoConfig?.version || '1.1.5';
const USER_AGENT = `${APP_NAME}/${APP_VERSION} (iOS)`;
export type ImageProps = ExpoImageProps;
export const Image = forwardRef<ExpoImage, ImageProps>(({ source, ...props }, ref) => {
const finalSource = useMemo(() => {
if (!source) return source;
const headers = {
'User-Agent': USER_AGENT,
'Referer': API_ORIGIN,
};
const addHeaders = (src: any) => {
if (typeof src === 'number' || src === null || src === undefined) return src;
if (typeof src === 'string') return { uri: src, headers };
if (typeof src === 'object' && 'uri' in src) {
return {
...src,
headers: { ...headers, ...(src.headers || {}) }
};
}
return src;
};
if (Array.isArray(source)) {
return source.map(addHeaders);
}
return addHeaders(source);
}, [source]);
return <ExpoImage {...props} source={finalSource} ref={ref} />;
});
Image.displayName = 'Image';

View File

@@ -1,7 +1,7 @@
import { Image } from '@/components/ui/Image';
import { Ionicons } from '@expo/vector-icons';
import { GlassView, isLiquidGlassAvailable } from 'expo-glass-effect';
import * as Haptics from 'expo-haptics';
import { Image } from 'expo-image';
import React, { useCallback, useEffect, useRef, useState } from 'react';
import {
ActivityIndicator,

View File

@@ -1,3 +1,4 @@
import { Image } from '@/components/ui/Image';
import { Colors } from '@/constants/Colors';
import { ROUTES } from '@/constants/Routes';
import { useAppDispatch, useAppSelector } from '@/hooks/redux';
@@ -7,7 +8,6 @@ import { fetchWeightHistory } from '@/store/userSlice';
import { BMI_CATEGORIES } from '@/utils/bmi';
import { Ionicons } from '@expo/vector-icons';
import { GlassView, isLiquidGlassAvailable } from 'expo-glass-effect';
import { Image } from 'expo-image';
import { LinearGradient } from 'expo-linear-gradient';
import { useRouter } from 'expo-router';
import React, { useEffect, useState } from 'react';