feat: 完善训练
This commit is contained in:
@@ -6,8 +6,7 @@ import React, { useEffect, useMemo, useState } from 'react';
|
||||
import { Alert, FlatList, Modal, SafeAreaView, StyleSheet, Text, TouchableOpacity, View } from 'react-native';
|
||||
import Animated, { FadeInUp } from 'react-native-reanimated';
|
||||
|
||||
import { CircularRing } from '@/components/CircularRing';
|
||||
import { ThemedText } from '@/components/ThemedText';
|
||||
import { useGlobalDialog } from '@/components/ui/DialogProvider';
|
||||
import { HeaderBar } from '@/components/ui/HeaderBar';
|
||||
import { palette } from '@/constants/Colors';
|
||||
import { useAppDispatch, useAppSelector } from '@/hooks/redux';
|
||||
@@ -15,20 +14,22 @@ import type { WorkoutExercise } from '@/services/workoutsApi';
|
||||
import {
|
||||
clearWorkoutError,
|
||||
completeWorkoutExercise,
|
||||
createWorkoutSession,
|
||||
deleteWorkoutSession,
|
||||
loadTodayWorkout,
|
||||
loadWorkoutSessions,
|
||||
skipWorkoutExercise,
|
||||
startWorkoutExercise,
|
||||
startWorkoutSession
|
||||
} from '@/store/workoutSlice';
|
||||
import dayjs from 'dayjs';
|
||||
|
||||
// ==================== 工具函数 ====================
|
||||
|
||||
// 计算两个时间之间的耗时(秒)
|
||||
const calculateDuration = (startTime: string, endTime: string): number => {
|
||||
const start = new Date(startTime);
|
||||
const end = new Date(endTime);
|
||||
return Math.floor((end.getTime() - start.getTime()) / 1000);
|
||||
const start = dayjs(startTime);
|
||||
const end = dayjs(endTime);
|
||||
return Math.floor((end.valueOf() - start.valueOf()) / 1000);
|
||||
};
|
||||
|
||||
// 格式化耗时显示(分钟:秒)
|
||||
@@ -77,7 +78,11 @@ function DynamicBackground({ color }: { color: string }) {
|
||||
export default function TodayWorkoutScreen() {
|
||||
const router = useRouter();
|
||||
const dispatch = useAppDispatch();
|
||||
const { currentSession, exercises, loading, exerciseLoading, error } = useAppSelector((s) => s.workout);
|
||||
const { currentSession, exercises, sessions, sessionsPagination, loading, exerciseLoading, error } = useAppSelector((s) => s.workout);
|
||||
const { showConfirm, showActionSheet } = useGlobalDialog();
|
||||
|
||||
const [refreshing, setRefreshing] = useState(false);
|
||||
const [loadingMore, setLoadingMore] = useState(false);
|
||||
|
||||
// 本地状态
|
||||
const [completionModal, setCompletionModal] = useState<{
|
||||
@@ -92,15 +97,52 @@ export default function TodayWorkoutScreen() {
|
||||
reps: 0,
|
||||
});
|
||||
|
||||
|
||||
|
||||
const goalConfig = currentSession?.trainingPlan
|
||||
? (GOAL_TEXT[currentSession.trainingPlan.goal] || { title: '今日训练', color: palette.primary, description: '开始你的训练之旅' })
|
||||
: { title: '今日训练', color: palette.primary, description: '开始你的训练之旅' };
|
||||
|
||||
// 加载今日训练数据
|
||||
// 加载训练会话列表
|
||||
useEffect(() => {
|
||||
dispatch(loadTodayWorkout());
|
||||
dispatch(loadWorkoutSessions({ page: 1, limit: 10 }));
|
||||
}, [dispatch]);
|
||||
|
||||
// 刷新数据
|
||||
const handleRefresh = async () => {
|
||||
setRefreshing(true);
|
||||
try {
|
||||
await dispatch(loadWorkoutSessions({ page: 1, limit: 10 })).unwrap();
|
||||
} catch (error) {
|
||||
console.error('刷新失败:', error);
|
||||
} finally {
|
||||
setRefreshing(false);
|
||||
}
|
||||
};
|
||||
|
||||
// 加载更多数据
|
||||
const handleLoadMore = async () => {
|
||||
if (loadingMore || loading || !sessionsPagination) return;
|
||||
|
||||
const currentPage = sessionsPagination.page;
|
||||
const totalPages = sessionsPagination.totalPages;
|
||||
|
||||
if (currentPage >= totalPages) return; // 已经是最后一页
|
||||
|
||||
setLoadingMore(true);
|
||||
try {
|
||||
await dispatch(loadWorkoutSessions({
|
||||
page: currentPage + 1,
|
||||
limit: 10,
|
||||
append: true // 追加数据而不是替换
|
||||
})).unwrap();
|
||||
} catch (error) {
|
||||
console.error('加载更多失败:', error);
|
||||
} finally {
|
||||
setLoadingMore(false);
|
||||
}
|
||||
};
|
||||
|
||||
// 错误处理
|
||||
useEffect(() => {
|
||||
if (error) {
|
||||
@@ -130,19 +172,16 @@ export default function TodayWorkoutScreen() {
|
||||
const handleStartWorkout = () => {
|
||||
if (!currentSession) return;
|
||||
|
||||
Alert.alert(
|
||||
'开始训练',
|
||||
'准备好开始今日的训练了吗?',
|
||||
[
|
||||
{ text: '取消', style: 'cancel' },
|
||||
{
|
||||
text: '开始',
|
||||
onPress: () => {
|
||||
dispatch(startWorkoutSession({ sessionId: currentSession.id }));
|
||||
Haptics.notificationAsync(Haptics.NotificationFeedbackType.Success);
|
||||
}
|
||||
}
|
||||
]
|
||||
showConfirm(
|
||||
{
|
||||
title: '开始训练',
|
||||
message: '准备好开始今日的训练了吗?',
|
||||
icon: 'fitness-outline',
|
||||
},
|
||||
() => {
|
||||
dispatch(startWorkoutSession({ sessionId: currentSession.id }));
|
||||
Haptics.notificationAsync(Haptics.NotificationFeedbackType.Success);
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
@@ -189,20 +228,55 @@ export default function TodayWorkoutScreen() {
|
||||
const handleSkipExercise = (exercise: WorkoutExercise) => {
|
||||
if (!currentSession) return;
|
||||
|
||||
Alert.alert(
|
||||
'跳过动作',
|
||||
`确定要跳过"${exercise.name}"吗?`,
|
||||
showConfirm(
|
||||
{
|
||||
title: '跳过动作',
|
||||
message: `确定要跳过"${exercise.name}"吗?`,
|
||||
icon: 'play-skip-forward-outline',
|
||||
destructive: true,
|
||||
},
|
||||
() => {
|
||||
dispatch(skipWorkoutExercise({
|
||||
sessionId: currentSession.id,
|
||||
exerciseId: exercise.id
|
||||
}));
|
||||
Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light);
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
// 创建新的训练会话
|
||||
const handleCreateSession = () => {
|
||||
showActionSheet(
|
||||
{
|
||||
title: '新建训练',
|
||||
subtitle: '选择创建方式开始你的训练',
|
||||
},
|
||||
[
|
||||
{ text: '取消', style: 'cancel' },
|
||||
{
|
||||
text: '跳过',
|
||||
style: 'destructive',
|
||||
id: 'custom',
|
||||
title: '自定义训练',
|
||||
subtitle: '创建一个空的训练,可以自由添加动作',
|
||||
icon: 'create-outline',
|
||||
iconColor: '#3B82F6',
|
||||
onPress: () => {
|
||||
dispatch(skipWorkoutExercise({
|
||||
sessionId: currentSession.id,
|
||||
exerciseId: exercise.id
|
||||
// 创建空的自定义会话
|
||||
const sessionName = `训练 ${dayjs().format('YYYY年MM月DD日')}`;
|
||||
dispatch(createWorkoutSession({
|
||||
name: sessionName,
|
||||
scheduledDate: dayjs().format('YYYY-MM-DD')
|
||||
}));
|
||||
Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light);
|
||||
}
|
||||
},
|
||||
{
|
||||
id: 'from-plan',
|
||||
title: '从训练计划导入',
|
||||
subtitle: '基于现有训练计划创建训练',
|
||||
icon: 'library-outline',
|
||||
iconColor: '#10B981',
|
||||
onPress: () => {
|
||||
// 跳转到创建页面选择训练计划
|
||||
router.push('/workout/create-session');
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -213,22 +287,19 @@ export default function TodayWorkoutScreen() {
|
||||
const handleDeleteSession = () => {
|
||||
if (!currentSession) return;
|
||||
|
||||
Alert.alert(
|
||||
'删除训练会话',
|
||||
'确定要删除这个训练会话吗?删除后无法恢复。',
|
||||
[
|
||||
{ text: '取消', style: 'cancel' },
|
||||
{
|
||||
text: '删除',
|
||||
style: 'destructive',
|
||||
onPress: () => {
|
||||
dispatch(deleteWorkoutSession(currentSession.id));
|
||||
Haptics.notificationAsync(Haptics.NotificationFeedbackType.Warning);
|
||||
// 删除成功后返回上一页
|
||||
router.back();
|
||||
}
|
||||
}
|
||||
]
|
||||
showConfirm(
|
||||
{
|
||||
title: '删除训练会话',
|
||||
message: '确定要删除这个训练会话吗?删除后无法恢复。',
|
||||
icon: 'trash-outline',
|
||||
destructive: true,
|
||||
},
|
||||
() => {
|
||||
dispatch(deleteWorkoutSession(currentSession.id));
|
||||
Haptics.notificationAsync(Haptics.NotificationFeedbackType.Warning);
|
||||
// 删除成功后清空当前会话
|
||||
// 不需要返回上一页,因为现在显示的是会话列表
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
@@ -390,10 +461,85 @@ export default function TodayWorkoutScreen() {
|
||||
);
|
||||
};
|
||||
|
||||
if (loading && !currentSession) {
|
||||
// 渲染训练会话卡片
|
||||
const renderSessionItem = ({ item, index }: { item: any; index: number }) => {
|
||||
const goalConfig = item.trainingPlan?.goal
|
||||
? (GOAL_TEXT[item.trainingPlan.goal] || { title: '训练会话', color: palette.primary, description: '开始你的训练之旅' })
|
||||
: { title: '训练会话', color: palette.primary, description: '开始你的训练之旅' };
|
||||
|
||||
const exerciseCount = item.exercises?.length || 0;
|
||||
const completedCount = item.exercises?.filter((ex: any) => ex.status === 'completed').length || 0;
|
||||
|
||||
return (
|
||||
<Animated.View
|
||||
entering={FadeInUp.delay(index * 100)}
|
||||
style={[styles.sessionCard, { borderLeftColor: goalConfig.color }]}
|
||||
>
|
||||
<TouchableOpacity
|
||||
style={styles.sessionCardContent}
|
||||
onPress={() => {
|
||||
router.push(`/workout/session/${item.id}`);
|
||||
}}
|
||||
activeOpacity={0.9}
|
||||
>
|
||||
<View style={styles.sessionHeader}>
|
||||
<View style={styles.sessionInfo}>
|
||||
<Text style={styles.sessionName}>{item.name}</Text>
|
||||
{item.trainingPlan && (
|
||||
<Text style={styles.sessionPlan}>{item.trainingPlan.name}</Text>
|
||||
)}
|
||||
<Text style={styles.sessionDate}>
|
||||
创建时间 {dayjs(item.createdAt).format('YYYY-MM-DD HH:mm:ss')}
|
||||
</Text>
|
||||
<Text style={styles.sessionDate}>
|
||||
计划时间 {dayjs(item.scheduledDate ).format('YYYY-MM-DD HH:mm:ss')}
|
||||
</Text>
|
||||
</View>
|
||||
|
||||
<View style={styles.sessionStats}>
|
||||
{item.status === 'completed' ? (
|
||||
<View style={[styles.statusBadge, { backgroundColor: '#22C55E15' }]}>
|
||||
<Text style={[styles.statusText, { color: '#22C55E' }]}>已完成</Text>
|
||||
</View>
|
||||
) : item.status === 'in_progress' ? (
|
||||
<View style={[styles.statusBadge, { backgroundColor: '#F59E0B15' }]}>
|
||||
<Text style={[styles.statusText, { color: '#F59E0B' }]}>进行中</Text>
|
||||
</View>
|
||||
) : (
|
||||
<View style={[styles.statusBadge, { backgroundColor: '#6B728015' }]}>
|
||||
<Text style={[styles.statusText, { color: '#6B7280' }]}>待开始</Text>
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
</View>
|
||||
|
||||
{exerciseCount > 0 && (
|
||||
<View style={styles.sessionProgress}>
|
||||
<Text style={styles.progressText}>
|
||||
{completedCount}/{exerciseCount} 个动作已完成
|
||||
</Text>
|
||||
<View style={styles.progressBar}>
|
||||
<View
|
||||
style={[
|
||||
styles.progressFill,
|
||||
{
|
||||
width: `${exerciseCount > 0 ? (completedCount / exerciseCount) * 100 : 0}%`,
|
||||
backgroundColor: goalConfig.color
|
||||
}
|
||||
]}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
)}
|
||||
</TouchableOpacity>
|
||||
</Animated.View>
|
||||
);
|
||||
};
|
||||
|
||||
if (loading && sessions.length === 0) {
|
||||
return (
|
||||
<SafeAreaView style={styles.safeArea}>
|
||||
<HeaderBar title="今日训练" onBack={() => router.back()} />
|
||||
<HeaderBar title="训练记录" onBack={() => router.back()} />
|
||||
<View style={styles.loadingContainer}>
|
||||
<Text style={styles.loadingText}>加载中...</Text>
|
||||
</View>
|
||||
@@ -401,19 +547,19 @@ export default function TodayWorkoutScreen() {
|
||||
);
|
||||
}
|
||||
|
||||
if (!currentSession) {
|
||||
if (sessions.length === 0 && !loading) {
|
||||
return (
|
||||
<View style={styles.safeArea}>
|
||||
<HeaderBar title="今日训练" onBack={() => router.back()} />
|
||||
<HeaderBar title="训练记录" onBack={() => router.back()} />
|
||||
<View style={styles.emptyContainer}>
|
||||
<Ionicons name="calendar-outline" size={64} color="#9CA3AF" />
|
||||
<Text style={styles.emptyTitle}>暂无今日训练</Text>
|
||||
<Text style={styles.emptyText}>请先激活一个训练计划</Text>
|
||||
<Ionicons name="fitness-outline" size={64} color="#9CA3AF" />
|
||||
<Text style={styles.emptyTitle}>暂无训练记录</Text>
|
||||
<Text style={styles.emptyText}>开始你的第一次训练吧</Text>
|
||||
<TouchableOpacity
|
||||
style={styles.createPlanBtn}
|
||||
onPress={() => router.push('/training-plan' as any)}
|
||||
style={styles.createSessionBtn}
|
||||
onPress={handleCreateSession}
|
||||
>
|
||||
<Text style={styles.createPlanBtnText}>去创建训练计划</Text>
|
||||
<Text style={styles.createSessionBtnText}>新建训练会话</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</View>
|
||||
@@ -423,101 +569,49 @@ export default function TodayWorkoutScreen() {
|
||||
return (
|
||||
<View style={styles.safeArea}>
|
||||
{/* 动态背景 */}
|
||||
<DynamicBackground color={goalConfig.color} />
|
||||
<DynamicBackground color={palette.primary} />
|
||||
|
||||
<SafeAreaView style={styles.contentWrapper}>
|
||||
<HeaderBar
|
||||
title="开始训练"
|
||||
title="训练记录"
|
||||
onBack={() => router.back()}
|
||||
withSafeTop={false}
|
||||
transparent={true}
|
||||
tone="light"
|
||||
right={
|
||||
currentSession?.status === 'in_progress' ? (
|
||||
<TouchableOpacity
|
||||
style={[styles.addExerciseBtn, { backgroundColor: palette.primary }]}
|
||||
onPress={() => router.push(`/training-plan/schedule/select?sessionId=${currentSession.id}` as any)}
|
||||
disabled={loading}
|
||||
>
|
||||
<Ionicons name="add" size={16} color={palette.ink} />
|
||||
</TouchableOpacity>
|
||||
) : null
|
||||
<TouchableOpacity
|
||||
style={[styles.addSessionBtn, { backgroundColor: palette.primary }]}
|
||||
onPress={handleCreateSession}
|
||||
disabled={loading}
|
||||
>
|
||||
<Ionicons name="add" size={20} color={palette.ink} />
|
||||
</TouchableOpacity>
|
||||
}
|
||||
/>
|
||||
|
||||
<View style={styles.content}>
|
||||
{/* 训练计划信息头部 */}
|
||||
<TouchableOpacity onPress={() => router.push(`/training-plan`)}>
|
||||
<View style={[styles.planHeader, { backgroundColor: `${goalConfig.color}20` }]}>
|
||||
|
||||
{/* 删除按钮 - 右上角 */}
|
||||
<TouchableOpacity
|
||||
style={styles.deleteBtn}
|
||||
onPress={handleDeleteSession}
|
||||
disabled={loading}
|
||||
>
|
||||
<Ionicons name="trash-outline" size={18} color="#EF4444" />
|
||||
</TouchableOpacity>
|
||||
|
||||
<View style={[styles.planColorIndicator, { backgroundColor: goalConfig.color }]} />
|
||||
<View style={styles.planInfo}>
|
||||
<ThemedText style={styles.planTitle}>{goalConfig.title}</ThemedText>
|
||||
<ThemedText style={styles.planDescription}>
|
||||
{currentSession.trainingPlan?.name || '今日训练'}
|
||||
</ThemedText>
|
||||
{/* 进度统计文字 */}
|
||||
{currentSession.status !== 'planned' && (
|
||||
<Text style={styles.planProgressStats}>
|
||||
{workoutStats.completed}/{workoutStats.total} 个动作已完成
|
||||
</Text>
|
||||
)}
|
||||
</View>
|
||||
|
||||
{/* 右侧区域:圆环进度或开始按钮 */}
|
||||
{currentSession.status === 'planned' ? (
|
||||
<TouchableOpacity
|
||||
style={[styles.planStartBtn, { backgroundColor: goalConfig.color }]}
|
||||
onPress={handleStartWorkout}
|
||||
disabled={loading}
|
||||
>
|
||||
<Ionicons name="play" size={20} color="#FFFFFF" />
|
||||
</TouchableOpacity>
|
||||
) : (
|
||||
<View style={styles.circularProgressContainer}>
|
||||
<CircularRing
|
||||
size={60}
|
||||
strokeWidth={6}
|
||||
trackColor={`${goalConfig.color}20`}
|
||||
progressColor={goalConfig.color}
|
||||
progress={completionPercentage / 100}
|
||||
showCenterText={false}
|
||||
durationMs={800}
|
||||
/>
|
||||
<View style={styles.circularProgressText}>
|
||||
<Text style={[styles.circularProgressPercentage, { color: goalConfig.color }]}>
|
||||
{completionPercentage}%
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
</TouchableOpacity>
|
||||
|
||||
{/* 训练完成提示 */}
|
||||
{currentSession.status === 'completed' && (
|
||||
<View style={styles.completedBanner}>
|
||||
<Ionicons name="checkmark-circle" size={24} color="#22C55E" />
|
||||
<Text style={styles.completedBannerText}>训练已完成!</Text>
|
||||
</View>
|
||||
)}
|
||||
|
||||
{/* 动作列表 */}
|
||||
{/* 会话列表 */}
|
||||
<FlatList
|
||||
data={exercises}
|
||||
data={sessions}
|
||||
keyExtractor={(item) => item.id}
|
||||
renderItem={renderExerciseItem}
|
||||
renderItem={renderSessionItem}
|
||||
contentContainerStyle={styles.listContent}
|
||||
showsVerticalScrollIndicator={false}
|
||||
refreshing={refreshing}
|
||||
onRefresh={handleRefresh}
|
||||
onEndReached={handleLoadMore}
|
||||
onEndReachedThreshold={0.1}
|
||||
ListFooterComponent={
|
||||
loadingMore ? (
|
||||
<View style={styles.loadMoreContainer}>
|
||||
<Text style={styles.loadMoreText}>加载更多...</Text>
|
||||
</View>
|
||||
) : sessionsPagination && sessionsPagination.page >= sessionsPagination.totalPages ? (
|
||||
<View style={styles.loadMoreContainer}>
|
||||
<Text style={styles.loadMoreText}>已加载全部数据</Text>
|
||||
</View>
|
||||
) : null
|
||||
}
|
||||
/>
|
||||
</View>
|
||||
</SafeAreaView>
|
||||
@@ -603,6 +697,7 @@ export default function TodayWorkoutScreen() {
|
||||
</TouchableOpacity>
|
||||
</TouchableOpacity>
|
||||
</Modal>
|
||||
|
||||
</View>
|
||||
);
|
||||
}
|
||||
@@ -944,13 +1039,13 @@ const styles = StyleSheet.create({
|
||||
textAlign: 'center',
|
||||
marginBottom: 24,
|
||||
},
|
||||
createPlanBtn: {
|
||||
createSessionBtn: {
|
||||
backgroundColor: '#22C55E',
|
||||
paddingVertical: 12,
|
||||
paddingHorizontal: 24,
|
||||
borderRadius: 8,
|
||||
},
|
||||
createPlanBtnText: {
|
||||
createSessionBtnText: {
|
||||
color: '#FFFFFF',
|
||||
fontSize: 14,
|
||||
fontWeight: '700',
|
||||
@@ -1054,11 +1149,11 @@ const styles = StyleSheet.create({
|
||||
fontSize: 16,
|
||||
},
|
||||
|
||||
// 添加动作按钮
|
||||
addExerciseBtn: {
|
||||
width: 28,
|
||||
height: 28,
|
||||
borderRadius: 14,
|
||||
// 添加会话按钮
|
||||
addSessionBtn: {
|
||||
width: 32,
|
||||
height: 32,
|
||||
borderRadius: 16,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
shadowColor: '#000',
|
||||
@@ -1067,4 +1162,75 @@ const styles = StyleSheet.create({
|
||||
shadowOffset: { width: 0, height: 2 },
|
||||
elevation: 2,
|
||||
},
|
||||
|
||||
// 会话卡片
|
||||
sessionCard: {
|
||||
backgroundColor: '#FFFFFF',
|
||||
borderRadius: 16,
|
||||
marginBottom: 12,
|
||||
borderLeftWidth: 4,
|
||||
shadowColor: '#000',
|
||||
shadowOpacity: 0.06,
|
||||
shadowRadius: 12,
|
||||
shadowOffset: { width: 0, height: 6 },
|
||||
elevation: 3,
|
||||
},
|
||||
sessionCardContent: {
|
||||
padding: 16,
|
||||
},
|
||||
sessionHeader: {
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'flex-start',
|
||||
marginBottom: 12,
|
||||
},
|
||||
sessionInfo: {
|
||||
flex: 1,
|
||||
},
|
||||
sessionName: {
|
||||
fontSize: 16,
|
||||
fontWeight: '800',
|
||||
color: '#192126',
|
||||
marginBottom: 4,
|
||||
},
|
||||
sessionPlan: {
|
||||
fontSize: 12,
|
||||
color: '#888F92',
|
||||
marginBottom: 2,
|
||||
},
|
||||
sessionDate: {
|
||||
fontSize: 11,
|
||||
color: '#6B7280',
|
||||
},
|
||||
sessionStats: {
|
||||
alignItems: 'flex-end',
|
||||
},
|
||||
sessionProgress: {
|
||||
marginTop: 8,
|
||||
},
|
||||
progressText: {
|
||||
fontSize: 12,
|
||||
color: '#6B7280',
|
||||
marginTop: 6
|
||||
},
|
||||
progressBar: {
|
||||
height: 4,
|
||||
backgroundColor: '#F3F4F6',
|
||||
borderRadius: 2,
|
||||
overflow: 'hidden',
|
||||
},
|
||||
progressFill: {
|
||||
height: '100%',
|
||||
borderRadius: 2,
|
||||
},
|
||||
|
||||
// 加载更多
|
||||
loadMoreContainer: {
|
||||
paddingVertical: 16,
|
||||
alignItems: 'center',
|
||||
},
|
||||
loadMoreText: {
|
||||
fontSize: 12,
|
||||
color: '#6B7280',
|
||||
},
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user