feat: 更新依赖项并优化组件结构

- 在 package.json 和 package-lock.json 中新增 @sentry/react-native、react-native-device-info 和 react-native-purchases 依赖
- 更新统计页面,替换 CircularRing 组件为 FitnessRingsCard,增强健身数据展示
- 在布局文件中引入 ToastProvider,优化用户通知体验
- 新增 SuccessToast 组件,提供全局成功提示功能
- 更新健康数据获取逻辑,支持健身圆环数据的提取
- 优化多个组件的样式和交互,提升用户体验
This commit is contained in:
richarjiang
2025-08-21 09:51:25 +08:00
parent 19b92547e1
commit 78620f18ee
21 changed files with 2494 additions and 108 deletions

107
contexts/ToastContext.tsx Normal file
View File

@@ -0,0 +1,107 @@
import SuccessToast from '@/components/ui/SuccessToast';
import { setToastRef } from '@/utils/toast.utils';
import React, { createContext, useContext, useEffect, useRef, useState } from 'react';
interface ToastConfig {
message: string;
duration?: number;
backgroundColor?: string;
textColor?: string;
icon?: string;
}
export interface ToastContextType {
showToast: (config: ToastConfig) => void;
showSuccess: (message: string, duration?: number) => void;
showError: (message: string, duration?: number) => void;
showWarning: (message: string, duration?: number) => void;
}
const ToastContext = createContext<ToastContextType | undefined>(undefined);
export function ToastProvider({ children }: { children: React.ReactNode }) {
const [visible, setVisible] = useState(false);
const [config, setConfig] = useState<ToastConfig>({ message: '' });
const timeoutRef = useRef<NodeJS.Timeout | null>(null);
const showToast = (toastConfig: ToastConfig) => {
// 如果已有Toast显示先隐藏
if (visible) {
setVisible(false);
// 短暂延迟后显示新Toast
setTimeout(() => {
setConfig(toastConfig);
setVisible(true);
}, 100);
} else {
setConfig(toastConfig);
setVisible(true);
}
};
const showSuccess = (message: string, duration?: number) => {
showToast({
message,
duration,
backgroundColor: '#DF42D0', // 主题色
icon: '✓',
});
};
const showError = (message: string, duration?: number) => {
showToast({
message,
duration,
backgroundColor: '#f44336', // 红色
icon: '✕',
});
};
const showWarning = (message: string, duration?: number) => {
showToast({
message,
duration,
backgroundColor: '#ff9800', // 橙色
icon: '⚠',
});
};
const handleHide = () => {
setVisible(false);
};
const value: ToastContextType = {
showToast,
showSuccess,
showError,
showWarning,
};
// 设置全局引用
useEffect(() => {
setToastRef(value);
}, [value]);
return (
<ToastContext.Provider value={value}>
{children}
<SuccessToast
visible={visible}
message={config.message}
duration={config.duration}
backgroundColor={config.backgroundColor}
textColor={config.textColor}
icon={config.icon}
onHide={handleHide}
/>
</ToastContext.Provider>
);
}
export function useToast(): ToastContextType {
const context = useContext(ToastContext);
if (context === undefined) {
throw new Error('useToast must be used within a ToastProvider');
}
return context;
}