# Simpl-Liste Application mobile de gestion de tâches minimaliste par La Compagnie Maximus. Bundle ID : `com.lacompagniemaximus.simpliste` — Scheme : `simplliste` ## Stack - **React Native 0.81** + **Expo SDK 54** (New Architecture) - **Expo Router 6** (file-based, typed routes) - **TypeScript 5.9** (strict) - **NativeWind 4.2** (Tailwind CSS 3.4 pour RN) - **Drizzle ORM 0.45** + **expo-sqlite 16** (SQLite local, `simpliste.db`) - **Zustand 5** + AsyncStorage (state UI persisté) - **i18next 25** + react-i18next (FR/EN, français par défaut) - **lucide-react-native** (icônes) - **date-fns 4** (dates) ## Scripts ```bash npm start # Expo dev server npm run android # Lancer sur Android npm run ios # Lancer sur iOS ``` ## Structure ``` app/ ├── _layout.tsx # Root stack (fonts, migrations, theme) ├── (tabs)/ │ ├── _layout.tsx # Tab bar (3 onglets) │ ├── index.tsx # Inbox │ ├── lists.tsx # Toutes les listes │ └── settings.tsx # Paramètres + gestion tags ├── task/ │ ├── new.tsx # Création de tâche (modal) │ └── [id].tsx # Détail/édition tâche └── list/ └── [id].tsx # Détail d'une liste src/ ├── components/ │ ├── FilterMenu.tsx # Modal filtres (bottom sheet) │ ├── SortMenu.tsx # Modal tri (bottom sheet) │ └── task/ │ ├── TagChip.tsx # Pill tag réutilisable │ └── TaskItem.tsx # Rangée de tâche ├── db/ │ ├── client.ts # Config SQLite + Drizzle │ ├── schema.ts # Tables : lists, tasks, tags, task_tags │ ├── migrations/ # SQL migrations (auto-appliquées au démarrage) │ └── repository/ │ ├── lists.ts # CRUD listes + ensureInbox() │ ├── tags.ts # CRUD tags + relations task-tag │ └── tasks.ts # CRUD tâches, filtres, tri, sous-tâches ├── i18n/ │ ├── index.ts # Init i18next (détection locale appareil) │ ├── fr.json # Traductions françaises │ └── en.json # Traductions anglaises ├── lib/ │ ├── priority.ts # Helpers couleurs priorité │ ├── recurrence.ts # Types récurrence + calcul prochaine occurrence │ ├── uuid.ts # Wrapper expo-crypto randomUUID │ └── validation.ts # Validation UUID pour deep links ├── services/ │ ├── calendar.ts # Sync expo-calendar │ ├── icsExport.ts # Export .ics + partage │ ├── notifications.ts # Planification expo-notifications │ └── widgetSync.ts # Sync tâches + thème vers widget Android ├── stores/ │ ├── useSettingsStore.ts # Thème, locale, notifs, calendrier │ └── useTaskStore.ts # État tri/filtre ├── theme/ │ └── colors.ts # Palette centralisée (bleu, crème, terracotta) └── widgets/ ├── TaskListWidget.tsx # Composant widget Android (3 tailles, dark mode) └── widgetTaskHandler.ts # Handler headless pour actions widget ``` ## Base de données 4 tables SQLite gérées par Drizzle ORM. Migrations auto-appliquées via `useMigrations()`. - **lists** : id, name, color, icon, position, is_inbox, timestamps - **tasks** : id, title, notes, completed, priority (0-3), due_date, list_id → lists, parent_id (sous-tâches), position, recurrence, calendar_event_id, timestamps - **tags** : id, name, color, timestamps - **task_tags** : task_id → tasks (CASCADE), tag_id → tags (CASCADE) ### Générer une migration ```bash npx drizzle-kit generate ``` Puis mettre à jour `src/db/migrations/migrations.js` si nécessaire. ## Conventions - **Français par défaut**, anglais en second. Toutes les chaînes visibles dans `fr.json`/`en.json` - **Dark mode** : résolu localement avec `isDark` ternary (pas de NativeWind dark: prefix) - **Composants** : headers custom par écran (pas de React Navigation header) - **Polling 500ms** : les écrans rechargent les données par intervalle (pas de live queries) - **Pas de state global pour les tâches** : chargées depuis SQLite par écran - Icônes via lucide-react-native, polices Inter (400/500/600/700) - UUID générés via `expo-crypto` - Sous-tâches = tâches avec `parentId` non-null ## Palette de couleurs | Token | Valeur | |-------|--------| | bleu | `#4A90A4` | | crème | `#FFF8F0` | | terracotta | `#C17767` | | vert | `#8BA889` | | sable | `#D4A574` | | violet | `#7B68EE` | | rouge | `#E57373` | | teal | `#4DB6AC` | Couleurs sombres : fond `#1A1A1A`, surface `#2A2A2A`, bordure `#3A3A3A`, texte `#F5F5F5`, secondaire `#A0A0A0` ## Widget Android 3 tailles configurées dans `app.json` (plugin `react-native-android-widget`) : - **SimplListeSmall** (2×2) — Compteur de tâches + bouton ajout - **SimplListeMedium** (2×4) — Liste de 4 tâches avec indicateur couleur de liste - **SimplListeLarge** (4×4) — Liste de 8 tâches ### Sync des données - `widgetSync.ts` lit les tâches depuis SQLite et les cache dans AsyncStorage (`widget:tasks`) - Le thème est lu depuis AsyncStorage (`simpl-liste-settings` → `state.theme`), résolu si `system` via `Appearance.getColorScheme()`, et stocké dans `widget:isDark` - `widgetTaskHandler.ts` gère le rendu headless (quand l'app n'est pas ouverte) en lisant les deux clés AsyncStorage - Les couleurs du widget suivent la même palette que l'app (voir `LIGHT_COLORS` / `DARK_COLORS` dans `TaskListWidget.tsx`) ### Clés AsyncStorage utilisées par le widget | Clé | Contenu | |-----|---------| | `widget:tasks` | `WidgetTask[]` sérialisé JSON | | `widget:isDark` | `boolean` sérialisé JSON | | `simpl-liste-settings` | Store Zustand persisté (contient `state.theme`) | ## Build & déploiement Profiles EAS dans `eas.json` : - **development** — APK avec dev client - **preview** — APK de distribution directe (hors Play Store) - **production** — AAB pour le Play Store, `autoIncrement: true` sur `versionCode` ### Commandes de build ```bash npx eas-cli build --platform android --profile preview --non-interactive # APK npx eas-cli build --platform android --profile production --non-interactive # AAB ``` **Important** : `eas` n'est pas installé globalement, utiliser `npx --yes eas-cli` (pas `npx eas`). ### Processus de release 1. Bumper `version` dans `app.json` ET `package.json` 2. Le `versionCode` Android est auto-incrémenté par EAS (`autoIncrement: true`) 3. Build preview (APK) + production (AAB) 4. Créer la release sur Forgejo via API : ```bash # Créer la release curl -X POST ".../api/v1/repos/maximus/simpl-liste/releases" -d '{"tag_name":"vX.Y.Z",...}' # Attacher l'APK curl -X POST ".../releases/{id}/assets?name=simpl-liste-vX.Y.Z.apk" -F "attachment=@fichier.apk" ``` 5. Le bouton « Vérifier les mises à jour » dans l'app utilise l'endpoint `/releases/latest` et propose le téléchargement de l'asset `.apk` ### Repo Forgejo - URL : `https://git.lacompagniemaximus.com/maximus/simpl-liste` - Remote git : `origin` (push via HTTPS avec token dans `~/.git-credentials`) - Issues : utilisées pour le suivi des bugs/features - Releases : distribution APK avec assets attachés ## Mises à jour in-app Le bouton dans Paramètres > À propos appelle `GET /api/v1/repos/maximus/simpl-liste/releases/latest` (repo public, pas d'auth nécessaire). Compare `release.tag_name` (ex: `v1.0.1`) avec `Constants.expoConfig.version`. Si différent, affiche une Alert avec le changelog (`release.body`) et un lien vers le premier asset `.apk` trouvé.