Projet Niv. 2 — Habitudes
Le brief : le tracker d’habitudes (« méditer », « lire 20 min », « pas de sucre ») : cocher chaque jour, entretenir des séries, voir la grille de chaleur des 3 derniers mois. Le projet des STREAKS — la mécanique psychologique la plus puissante du mobile.
Ce que vous allez pratiquer
La logique de dates/séries en lib/ pur (testée à fond — c’est piégeux), la grille de chaleur custom (flexbox + dérivation SQL), les notifications par habitude (channels, ch. 9.2), et la première vraie complexité de domaine. Chapitres liés : 6.1, 8.3, 9.2, 14.2.
Les features
- CRUD habitudes : nom, emoji, fréquence (quotidienne — hebdo en bonus), heure de rappel optionnelle.
- Le check du jour : un tap = fait (haptic Success !), re-tap = annulé.
- Streaks : série courante et record, par habitude — avec la règle de grâce explicite (rater AUJOURD’HUI ne casse la série qu’à minuit).
- La grille de chaleur (90 jours, façon GitHub) par habitude.
- Rappels par habitude à son heure (et le channel « Rappels d’habitudes »).
L’architecture recommandée
- Le schéma :
habits(id, name, emoji, reminder_hour, notification_id, created_at)checks(habit_id, day TEXT ‘YYYY-MM-DD’, UNIQUE(habit_id, day)). Le jour en TEXTE local (pas un timestamp !) : « fait le 12 mars » est un fait de CALENDRIER, pas d’horloge — ça élimine toute la classe de bugs fuseaux/minuit.
- La logique de streak en lib/streaks.ts, PURE — et c’est le cœur du projet :
// computeStreak(checkedDays: Set<string>, today: string): { current: number; best: number }
// Règles : consécutifs jusqu'à hier (ou aujourd'hui si coché) ;
// aujourd'hui non coché ≠ cassé (la grâce court jusqu'à minuit).Écrivez les tests AVANT (ch. 14.2) : série qui traverse un mois, série de 1, aujourd’hui
coché/pas coché, trou d’hier — la table des cas fait la moitié de la conception. today
est un PARAMÈTRE (l’horloge s’injecte — testabilité).
- La grille de chaleur : 13 semaines × 7 — un simple flexWrap de Views 10×10 teintées par
intensité (0 → ink-900, fait → brand). Pas de lib : ~40 lignes avec la dérivation
SELECT day FROM checks WHERE habit_id = ? AND day >= ?.
Les jalons
- lib/streaks.ts + la suite de tests COMPLÈTE (le jalon le plus important).
- Schéma + CRUD habitudes + le check du jour (l’écran principal en liste).
- Streaks affichées (badge 🔥 N) + la règle de grâce vérifiée en manuel.
- La grille de chaleur.
- Rappels par habitude (planification/annulation cohérentes — le pattern du Todo).
- APK + une VRAIE habitude suivie 2 semaines.
Critères de réussite
- La suite de tests de streaks passe — y compris le cas « 23 h 59 vs 00 h 01 »
- Cocher hier soir + aujourd’hui matin = série de 2 (pas de doublon, pas de trou)
- La grille affiche exactement les 90 derniers jours locaux, alignée sur les semaines
- Supprimer une habitude annule son rappel ET efface ses checks (CASCADE vérifié)
- Le re-tap du check du jour décoche (l’UNIQUE(habit_id, day) rend l’upsert propre)
- 2 semaines d’usage réel : votre streak à VOUS tient
Pièges connus
- Le jour local :
new Date().toISOString().slice(0,10)est UTC — FAUX après 22-23 h en France. La fonctionlocalDay()(getFullYear/Month/Date locaux) va dans lib/ et s’utilise PARTOUT. - Ne recalculez pas les streaks en SQL (les gaps consécutifs en SQL = douleur) : SELECT des jours → Set → la fonction pure. La base stocke des FAITS, lib/ calcule.
- La notification « tu vas perdre ta série de 12 ! » à 21 h est LE rappel qui marche (bonus : conditionnez le message à la streak courante — replanification quotidienne au premier lancement du jour).
💡 L’upgrade : les habitudes hebdomadaires (« 3 fois par semaine » — la logique de streak devient un vrai sujet de conception : qu’est-ce qu’une « semaine réussie » ?), et le partage de la grille en image (le pattern view-shot du ch. 9.4).