import { Ionicons } from '@expo/vector-icons';
import type { ReactNode } from 'react';
import { ActivityIndicator, Pressable, StyleSheet, Text, View } from 'react-native';
import { colors } from '../theme';
/* ===================== 通用状态视图 =====================
* 统一承载「加载中 / 加载失败 / 空数据」三态,供数据页复用,
* 避免各页面重复编写 ActivityIndicator + 重试按钮样板代码。
* 颜色全部走主题 token,遵守 AGENTS.md 配色约束。
*/
function StateBox({ children }: { children: ReactNode }) {
return {children};
}
/** 加载中 */
export function LoadingState({ text = '加载中…' }: { text?: string }) {
return (
{text}
);
}
/** 加载失败(可重试) */
export function ErrorState({
message = '加载失败,请重试',
onRetry,
}: {
message?: string;
onRetry?: () => void;
}) {
return (
{message}
{onRetry ? (
重试
) : null}
);
}
/** 空数据 / 占位 */
export function EmptyState({
icon = 'document-text-outline',
title,
subtitle,
actionLabel,
onAction,
}: {
icon?: keyof typeof Ionicons.glyphMap;
title: string;
subtitle?: string;
actionLabel?: string;
onAction?: () => void;
}) {
return (
{title}
{subtitle ? {subtitle} : null}
{actionLabel && onAction ? (
{actionLabel}
) : null}
);
}
const styles = StyleSheet.create({
box: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
gap: 12,
paddingHorizontal: 32,
},
text: {
marginTop: 4,
fontSize: 14,
color: colors.textSecondary,
textAlign: 'center',
},
title: {
marginTop: 12,
fontSize: 20,
fontWeight: '700',
color: colors.textPrimary,
},
retryBtn: {
marginTop: 16,
paddingHorizontal: 24,
paddingVertical: 8,
borderRadius: 18,
backgroundColor: colors.primaryBtn,
},
retryText: {
fontSize: 13,
fontWeight: '600',
color: colors.white,
},
});