primeiro commit
This commit is contained in:
349
app/(tabs)/inicio.tsx
Normal file
349
app/(tabs)/inicio.tsx
Normal file
@@ -0,0 +1,349 @@
|
||||
import React, { useState, useEffect, useRef } from 'react';
|
||||
import {
|
||||
View,
|
||||
Text,
|
||||
TouchableOpacity,
|
||||
StyleSheet,
|
||||
SafeAreaView,
|
||||
ScrollView,
|
||||
Alert,
|
||||
} from 'react-native';
|
||||
import { useRouter } from 'expo-router';
|
||||
import {
|
||||
Home,
|
||||
FileText,
|
||||
BarChart2,
|
||||
Settings,
|
||||
Star,
|
||||
} from 'lucide-react-native';
|
||||
|
||||
const PURPLE = '#6a00fa';
|
||||
const CARD_BG = '#fff';
|
||||
|
||||
export default function InicioScreen() {
|
||||
const router = useRouter();
|
||||
|
||||
// --- authentication guard (placeholder) ---
|
||||
useEffect(() => {
|
||||
const isAuthenticated = true; // trocar por verificação real
|
||||
if (!isAuthenticated) {
|
||||
router.replace('/login');
|
||||
}
|
||||
}, [router]);
|
||||
|
||||
// --- checklist state ---
|
||||
const [tasks, setTasks] = useState([
|
||||
{ id: 1, label: 'Estudar para intermédio', done: false },
|
||||
{ id: 2, label: 'Ler artigo técnico', done: false },
|
||||
{ id: 3, label: 'Fazer exercícios', done: false },
|
||||
]);
|
||||
const toggleTask = (id: number) => {
|
||||
setTasks((prev) =>
|
||||
prev.map((t) => (t.id === id ? { ...t, done: !t.done } : t))
|
||||
);
|
||||
};
|
||||
|
||||
// --- habits rating ---
|
||||
const [rating, setRating] = useState(4);
|
||||
|
||||
// --- pomodoro timer ---
|
||||
const [secondsLeft, setSecondsLeft] = useState(25 * 60);
|
||||
const [running, setRunning] = useState(false);
|
||||
const intervalRef = useRef<number | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (running) {
|
||||
const id = setInterval(() => {
|
||||
setSecondsLeft((s) => {
|
||||
if (s <= 1) {
|
||||
if (intervalRef.current !== null) {
|
||||
clearInterval(intervalRef.current);
|
||||
}
|
||||
setRunning(false);
|
||||
return 0;
|
||||
}
|
||||
return s - 1;
|
||||
});
|
||||
}, 1000) as unknown as number;
|
||||
intervalRef.current = id;
|
||||
} else {
|
||||
if (intervalRef.current !== null) {
|
||||
clearInterval(intervalRef.current);
|
||||
}
|
||||
}
|
||||
return () => {
|
||||
if (intervalRef.current !== null) {
|
||||
clearInterval(intervalRef.current);
|
||||
}
|
||||
};
|
||||
}, [running]);
|
||||
|
||||
const startTimer = () => {
|
||||
if (!running) {
|
||||
setSecondsLeft(25 * 60);
|
||||
setRunning(true);
|
||||
}
|
||||
};
|
||||
|
||||
const formatTime = (sec: number) => {
|
||||
const m = Math.floor(sec / 60)
|
||||
.toString()
|
||||
.padStart(2, '0');
|
||||
const s = (sec % 60).toString().padStart(2, '0');
|
||||
return `${m}:${s}`;
|
||||
};
|
||||
|
||||
return (
|
||||
<SafeAreaView style={styles.safe}>
|
||||
<ScrollView contentContainerStyle={styles.scroll}>
|
||||
{/* header */}
|
||||
<View style={styles.header}>
|
||||
<View>
|
||||
<Text style={styles.greeting}>Hoje é um bom dia</Text>
|
||||
<Text style={styles.subtitle}>
|
||||
Olá, Matheus! Preparado para o seu dia de produtividade?
|
||||
</Text>
|
||||
</View>
|
||||
<Text style={styles.waveEmoji}>👋</Text>
|
||||
</View>
|
||||
|
||||
{/* desafios do dia card */}
|
||||
<View style={styles.card}>
|
||||
<Text style={styles.cardTitle}>Desafios do Dia</Text>
|
||||
{tasks.map((t) => (
|
||||
<TouchableOpacity
|
||||
key={t.id}
|
||||
style={styles.checkItem}
|
||||
onPress={() => toggleTask(t.id)}
|
||||
>
|
||||
<Text style={[styles.checkBox, t.done && styles.done]}>✓</Text>
|
||||
<Text
|
||||
style={[
|
||||
styles.checkLabel,
|
||||
t.done && styles.checkLabelDone,
|
||||
]}
|
||||
>
|
||||
{t.label}
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
))}
|
||||
<TouchableOpacity
|
||||
style={styles.addButton}
|
||||
onPress={() => Alert.alert('Adicionar','implementação futura')}
|
||||
>
|
||||
<Text style={styles.addButtonText}>+ Adicionar desafios diários</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
|
||||
{/* hábitos card */}
|
||||
<View style={styles.card}>
|
||||
<Text style={styles.cardTitle}>Hábitos</Text>
|
||||
<View style={styles.ratingRow}>
|
||||
{Array.from({ length: 5 }).map((_, i) => (
|
||||
<TouchableOpacity key={i} onPress={() => setRating(i + 1)} activeOpacity={0.7}>
|
||||
<Star
|
||||
size={20}
|
||||
stroke={i < rating ? '#f5c518' : '#ccc'}
|
||||
/>
|
||||
</TouchableOpacity>
|
||||
))}
|
||||
</View>
|
||||
<View style={styles.habitsRow}>
|
||||
<TouchableOpacity style={[styles.habitButton, { backgroundColor: '#A0E9FD' }]}
|
||||
activeOpacity={0.7}
|
||||
>
|
||||
<Text>📘</Text>
|
||||
</TouchableOpacity>
|
||||
<TouchableOpacity style={[styles.habitButton, { backgroundColor: '#B2F59C' }]}
|
||||
activeOpacity={0.7}
|
||||
>
|
||||
<Text>🧘</Text>
|
||||
</TouchableOpacity>
|
||||
<TouchableOpacity style={[styles.habitButton, { backgroundColor: '#FFD59C' }]}
|
||||
activeOpacity={0.7}
|
||||
>
|
||||
<Text>🏋️♂️</Text>
|
||||
</TouchableOpacity>
|
||||
<TouchableOpacity style={[styles.habitButton, styles.habitAdd]}
|
||||
activeOpacity={0.7}
|
||||
>
|
||||
<Text>+</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
{/* modo foco card */}
|
||||
<View style={styles.card}>
|
||||
<Text style={styles.cardTitle}>Modo Foco</Text>
|
||||
<View style={styles.focusRow}>
|
||||
<TouchableOpacity
|
||||
style={styles.timerBlock}
|
||||
onPress={startTimer}
|
||||
>
|
||||
<Text style={styles.timerText}>{formatTime(secondsLeft)}</Text>
|
||||
</TouchableOpacity>
|
||||
<Text style={styles.focusText}>
|
||||
Produtividade é o segredo do sucesso
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
</ScrollView>
|
||||
|
||||
{/* bottom navigation */}
|
||||
<View style={styles.bottomNav}>
|
||||
<TouchableOpacity style={styles.navItem} disabled>
|
||||
<Home size={24} stroke={PURPLE} />
|
||||
</TouchableOpacity>
|
||||
<TouchableOpacity style={styles.navItem}>
|
||||
<FileText size={24} stroke="#666" />
|
||||
</TouchableOpacity>
|
||||
<TouchableOpacity style={styles.navItem}>
|
||||
<BarChart2 size={24} stroke="#666" />
|
||||
</TouchableOpacity>
|
||||
<TouchableOpacity style={styles.navItem}>
|
||||
<Settings size={24} stroke="#666" />
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</SafeAreaView>
|
||||
);
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
safe: {
|
||||
flex: 1,
|
||||
backgroundColor: PURPLE,
|
||||
},
|
||||
scroll: {
|
||||
padding: 20,
|
||||
paddingBottom: 80,
|
||||
},
|
||||
header: {
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'center',
|
||||
marginBottom: 20,
|
||||
},
|
||||
greeting: {
|
||||
fontSize: 24,
|
||||
fontWeight: 'bold',
|
||||
color: '#fff',
|
||||
},
|
||||
subtitle: {
|
||||
fontSize: 14,
|
||||
color: '#eee',
|
||||
marginTop: 4,
|
||||
},
|
||||
waveEmoji: {
|
||||
fontSize: 28,
|
||||
},
|
||||
card: {
|
||||
backgroundColor: CARD_BG,
|
||||
borderRadius: 24,
|
||||
padding: 16,
|
||||
marginBottom: 20,
|
||||
},
|
||||
cardTitle: {
|
||||
fontSize: 18,
|
||||
fontWeight: '600',
|
||||
marginBottom: 12,
|
||||
},
|
||||
checkItem: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
marginBottom: 8,
|
||||
},
|
||||
checkBox: {
|
||||
width: 24,
|
||||
height: 24,
|
||||
borderWidth: 1,
|
||||
borderColor: '#666',
|
||||
marginRight: 8,
|
||||
textAlign: 'center',
|
||||
lineHeight: 24,
|
||||
},
|
||||
done: {
|
||||
backgroundColor: '#6a0fa0',
|
||||
color: '#fff',
|
||||
borderColor: '#6a0fa0',
|
||||
},
|
||||
checkLabel: {
|
||||
fontSize: 16,
|
||||
color: '#333',
|
||||
},
|
||||
checkLabelDone: {
|
||||
textDecorationLine: 'line-through',
|
||||
color: '#999',
|
||||
},
|
||||
addButton: {
|
||||
marginTop: 12,
|
||||
backgroundColor: PURPLE,
|
||||
padding: 12,
|
||||
borderRadius: 8,
|
||||
alignItems: 'center',
|
||||
},
|
||||
addButtonText: {
|
||||
color: '#fff',
|
||||
fontWeight: '600',
|
||||
},
|
||||
ratingRow: {
|
||||
flexDirection: 'row',
|
||||
marginBottom: 12,
|
||||
},
|
||||
habitsRow: {
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between',
|
||||
},
|
||||
habitButton: {
|
||||
width: 50,
|
||||
height: 50,
|
||||
borderRadius: 8,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
},
|
||||
habitAdd: {
|
||||
borderWidth: 1,
|
||||
borderStyle: 'dashed',
|
||||
borderColor: '#666',
|
||||
backgroundColor: 'transparent',
|
||||
},
|
||||
focusRow: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
},
|
||||
timerBlock: {
|
||||
width: 80,
|
||||
height: 80,
|
||||
backgroundColor: '#3b44f6',
|
||||
borderRadius: 12,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
marginRight: 12,
|
||||
},
|
||||
timerText: {
|
||||
color: '#fff',
|
||||
fontSize: 20,
|
||||
fontWeight: 'bold',
|
||||
},
|
||||
focusText: {
|
||||
flex: 1,
|
||||
fontSize: 14,
|
||||
color: '#333',
|
||||
},
|
||||
bottomNav: {
|
||||
position: 'absolute',
|
||||
bottom: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
height: 60,
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-around',
|
||||
alignItems: 'center',
|
||||
backgroundColor: CARD_BG,
|
||||
borderTopWidth: 1,
|
||||
borderColor: '#ddd',
|
||||
},
|
||||
navItem: {
|
||||
flex: 1,
|
||||
alignItems: 'center',
|
||||
},
|
||||
});
|
||||
Reference in New Issue
Block a user