Skip to Content

Projet Niv. 1 — Todo

Le brief : la liste de tâches — LE classique, fait proprement : SQLite, swipe, sections « aujourd’hui / plus tard », échéances avec rappels. Volontairement sans surprise : c’est la solidité qui est notée.

Ce que vous allez pratiquer

Le CRUD SQLite complet avec migrations (P8), FlatList et ses états (ch. 3.4), swipe-to-delete + annulation (ch. 10.4), TextInput/clavier (ch. 3.5), les notifications d’échéance (ch. 9.2). Chapitres liés : P8, 3.4, 3.5, 10.4, 9.2.

Les features

  1. CRUD : ajouter (champ en haut, retour clavier = valider), cocher/décocher, éditer (tap), supprimer (swipe + toast Annuler).
  2. Sections : En retard / Aujourd’hui / À venir / Un jour (tri par échéance).
  3. Échéance optionnelle avec rappel notification à l’heure dite.
  4. Le compteur : « 3 restantes aujourd’hui » — l’agrégat SQL en header.
  5. État vide soigné (la première impression).

L’architecture recommandée

  • Le schéma (v1 — via le moteur de migrations du ch. 8.2, recopié tel quel) :
CREATE TABLE tasks ( id INTEGER PRIMARY KEY AUTOINCREMENT, title TEXT NOT NULL, done INTEGER NOT NULL DEFAULT 0, due_at INTEGER, -- nullable : « un jour » notification_id TEXT, -- pour annuler le rappel si la tâche bouge created_at INTEGER NOT NULL ); CREATE INDEX idx_tasks_due ON tasks(done, due_at);
  • La colonne notification_id est LA leçon du projet : une tâche avec rappel stocke l’identifiant de SA notification planifiée — cocher/supprimer/reporter la tâche annule et replanifie. La cohérence données ↔ notifications est un vrai sujet d’app réelle.
  • Une seule requête pour les sections : SELECT …, CASE WHEN … END AS section (ou le tri par due_at et le groupement en JS via SectionList — les deux se défendent : choisissez et justifiez dans le README).
  • TanStack Query sur les hooks de données + invalidation après mutations (ch. 8.3) — le pattern se recopie.

Les jalons

  1. Schéma + migrations + lib/db/tasks.ts (insert, toggle, update, delete, listBySections).
  2. La liste : sections, ajout au clavier, cocher (avec le barré animé — LayoutAnimation).
  3. Swipe-to-delete + toast d’annulation (suppression optimiste, écriture différée).
  4. Échéances : le picker (badges Aujourd’hui/Demain/Date), le rappel notification, et la cohérence annulation/replanification.
  5. Header d’agrégats + état vide + APK.

Critères de réussite

  • 200 tâches insérées (script de seed) : la liste reste fluide (items mémoïsés)
  • Cocher une tâche à rappel futur ANNULE sa notification (vérifiable : getAllScheduledNotificationsAsync)
  • Le swipe supprimé + Annuler dans les 5 s : la tâche revient, la base n’a jamais bougé
  • Kill + relance : tout est là (SQLite), les sections justes (dates recalculées)
  • Le clavier ne masque jamais le champ d’ajout, le premier tap sur une tâche passe (keyboardShouldPersistTaps)
  • APK installé, utilisé une semaine RÉELLE (le seul vrai test d’un todo)

Pièges connus

  • « Aujourd’hui » se calcule en heure locale (le strftime localtime du ch. 8.3 — ou le calcul JS du début de journée locale) : une tâche de 23 h 50 n’est pas « en retard » à 00 h 01 UTC.
  • Ne stockez pas la SECTION en base (elle dérive de due_at et de MAINTENANT — dériver, jamais stocker, ch. 6.1).
  • L’édition inline (tap → TextInput à la place du Text) est plus délicate qu’un écran d’édition — commencez par l’écran, l’inline en bonus.

💡 L’upgrade : les sous-tâches (une colonne parent_id — et la récursivité SQL WITH RECURSIVE en cadeau d’apprentissage), ou le widget « ajouter depuis le partage » (l’app reçoit du texte partagé — expo-share-intent, module natif : votre premier hors-SDK).