feat: 适配 headerbar ios26

This commit is contained in:
richarjiang
2025-10-14 16:31:19 +08:00
parent cf069f3537
commit 435f5cc65c
41 changed files with 493 additions and 5445 deletions

View File

@@ -3,6 +3,7 @@ import { HeaderBar } from '@/components/ui/HeaderBar';
import { Colors } from '@/constants/Colors';
import { useAppDispatch, useAppSelector } from '@/hooks/redux';
import { useColorScheme } from '@/hooks/useColorScheme';
import { useSafeAreaTop } from '@/hooks/useSafeAreaWithPadding';
import { completeTask, skipTask } from '@/store/tasksSlice';
import MaterialIcons from '@expo/vector-icons/MaterialIcons';
import { useLocalSearchParams, useRouter } from 'expo-router';
@@ -19,17 +20,18 @@ import {
} from 'react-native';
export default function TaskDetailScreen() {
const safeAreaTop = useSafeAreaTop()
const { taskId } = useLocalSearchParams<{ taskId: string }>();
const router = useRouter();
const theme = useColorScheme() ?? 'light';
const colorTokens = Colors[theme];
const dispatch = useAppDispatch();
const { showConfirm } = useGlobalDialog();
// 从Redux中获取任务数据
const { tasks, tasksLoading } = useAppSelector(state => state.tasks);
const task = tasks.find(t => t.id === taskId) || null;
const [comment, setComment] = useState('');
const getStatusText = (status: string) => {
@@ -98,10 +100,10 @@ export default function TaskDetailScreen() {
const formatDate = (dateString: string) => {
const date = new Date(dateString);
const options: Intl.DateTimeFormatOptions = {
year: 'numeric',
month: 'long',
day: 'numeric'
const options: Intl.DateTimeFormatOptions = {
year: 'numeric',
month: 'long',
day: 'numeric'
};
return `创建于 ${date.toLocaleDateString('zh-CN', options)}`;
};
@@ -112,14 +114,14 @@ export default function TaskDetailScreen() {
}
try {
await dispatch(completeTask({
taskId: task.id,
completionData: {
await dispatch(completeTask({
taskId: task.id,
completionData: {
count: 1,
notes: '通过任务详情页面完成'
}
}
})).unwrap();
// 检查任务是否真正完成(当前完成次数是否达到目标次数)
const updatedTask = tasks.find(t => t.id === task.id);
if (updatedTask && updatedTask.currentCount >= updatedTask.targetCount) {
@@ -150,13 +152,13 @@ export default function TaskDetailScreen() {
},
async () => {
try {
await dispatch(skipTask({
taskId: task.id,
skipData: {
await dispatch(skipTask({
taskId: task.id,
skipData: {
reason: '用户主动跳过'
}
}
})).unwrap();
Alert.alert('成功', '任务已跳过!');
router.back();
} catch (error) {
@@ -178,10 +180,13 @@ export default function TaskDetailScreen() {
if (tasksLoading) {
return (
<View style={[styles.container, { backgroundColor: colorTokens.background }]}>
<HeaderBar
title="任务详情"
<HeaderBar
title="任务详情"
onBack={() => router.back()}
/>
<View style={{
paddingTop: safeAreaTop
}} />
<View style={styles.loadingContainer}>
<Text style={[styles.loadingText, { color: colorTokens.text }]}>...</Text>
</View>
@@ -192,10 +197,13 @@ export default function TaskDetailScreen() {
if (!task) {
return (
<View style={[styles.container, { backgroundColor: colorTokens.background }]}>
<HeaderBar
title="任务详情"
<HeaderBar
title="任务详情"
onBack={() => router.back()}
/>
<View style={{
paddingTop: safeAreaTop
}} />
<View style={styles.errorContainer}>
<Text style={[styles.errorText, { color: colorTokens.text }]}></Text>
</View>
@@ -206,8 +214,8 @@ export default function TaskDetailScreen() {
return (
<View style={[styles.container, { backgroundColor: colorTokens.background }]}>
{/* 使用HeaderBar组件 */}
<HeaderBar
title="任务详情"
<HeaderBar
title="任务详情"
onBack={() => router.back()}
right={
task.status !== 'completed' && task.status !== 'skipped' && task.currentCount < task.targetCount ? (
@@ -222,7 +230,9 @@ export default function TaskDetailScreen() {
}
/>
<ScrollView style={styles.scrollView} showsVerticalScrollIndicator={false}>
<ScrollView style={styles.scrollView} contentContainerStyle={{
paddingTop: safeAreaTop
}} showsVerticalScrollIndicator={false}>
{/* 任务标题和创建时间 */}
<View style={styles.titleSection}>
<Text style={[styles.taskTitle, { color: colorTokens.text }]}>{task.title}</Text>
@@ -255,7 +265,7 @@ export default function TaskDetailScreen() {
<Text style={styles.priorityTagText}></Text>
</View>
</View>
<View style={styles.infoItem}>
<Text style={[styles.infoLabel, { color: colorTokens.text }]}></Text>
<View style={[styles.difficultyTag, { backgroundColor: getDifficultyColor('very_easy') }]}>
@@ -268,7 +278,7 @@ export default function TaskDetailScreen() {
{/* 任务进度信息 */}
<View style={styles.progressSection}>
<Text style={[styles.sectionTitle, { color: colorTokens.text }]}></Text>
{/* 进度条 */}
<View style={styles.progressBar}>
<View
@@ -276,13 +286,13 @@ export default function TaskDetailScreen() {
styles.progressFill,
{
width: task.progressPercentage > 0 ? `${Math.min(task.progressPercentage, 100)}%` : '2%',
backgroundColor: task.progressPercentage >= 100
? '#10B981'
: task.progressPercentage >= 50
? '#F59E0B'
: task.progressPercentage > 0
? colorTokens.primary
: '#E5E7EB',
backgroundColor: task.progressPercentage >= 100
? '#10B981'
: task.progressPercentage >= 50
? '#F59E0B'
: task.progressPercentage > 0
? colorTokens.primary
: '#E5E7EB',
},
]}
/>
@@ -315,8 +325,8 @@ export default function TaskDetailScreen() {
{/* 底部操作按钮 */}
{task.status !== 'completed' && task.status !== 'skipped' && task.currentCount < task.targetCount && (
<View style={styles.actionButtons}>
<TouchableOpacity
style={[styles.actionButton, styles.skipButton]}
<TouchableOpacity
style={[styles.actionButton, styles.skipButton]}
onPress={handleSkipTask}
>
<MaterialIcons name="skip-next" size={20} color="#6B7280" />
@@ -338,7 +348,7 @@ export default function TaskDetailScreen() {
</View>
<View style={styles.commentInputWrapper}>
<TextInput
style={[styles.commentInput, {
style={[styles.commentInput, {
color: colorTokens.text,
backgroundColor: '#F3F4F6'
}]}
@@ -349,9 +359,9 @@ export default function TaskDetailScreen() {
multiline
maxLength={500}
/>
<TouchableOpacity
style={[styles.sendButton, {
backgroundColor: comment.trim() ? '#6B7280' : '#D1D5DB'
<TouchableOpacity
style={[styles.sendButton, {
backgroundColor: comment.trim() ? '#6B7280' : '#D1D5DB'
}]}
onPress={handleSendComment}
disabled={!comment.trim()}