Une seule SearchScreen modale gère la recherche depuis Home, MyPlants,
Guides et Map. La SearchBar partagée passe en mode trigger sur ces pages,
ouvrant la modal au tap.
Animation par contexte (native-stack) :
- Home/MyPlants/Guides → 'fade_from_bottom' (fade + léger glissement)
- Map → 'fade' pur (la barre est déjà en haut, pas de mouvement vertical)
via param de route { fromMap: true }
SearchScreen — mode global :
- 3 catégories : Maladies (red), Guides pratiques (blue), Mes plantes (green)
- Filter chips scrollable horizontal : Tout / Maladies / Guides / Plantes
avec count par catégorie
- Sections en accordion (chevron) avec count par section
- Tag coloré sur chaque résultat indiquant la catégorie
- Plantes scannées incluses (recherche par customName / cépage)
- Tap résultat : DiseaseDetail / GuideDetail / Map+focusScanId / ScanDetail
SearchScreen — mode Map (fromMap=true) :
- Liste plate des plantes localisées uniquement
- Distance haversine depuis position courante (formatDistance helper)
- Tri par distance croissante
- Tap → navigate Main/Map avec focusScanId
MapScreen :
- useEffect sur route.params?.focusScanId : animation 2 étapes (zoom large
450ms → zoom serré 500ms) + ouverture du preview
- Caméra décalée vers le sud (lat - delta * 0.18) pour que le marker soit
visible AU-DESSUS du bottom sheet, pas masqué dessous
- Reset du param après usage via setParams
Recents :
- Hook useRecentSearches (AsyncStorage @vineye:recent_searches)
- Max 10, déduplication insensible à la casse
- Affichés quand pas de query, avec clear all + remove individuel
SearchBar partagée :
- Refactorisée 100% Tailwind (sauf 2-3 props RN-spécifiques sur TextInput)
- Nouvelle prop onTriggerPress : devient un Pressable avec Text placeholder
qui navigate vers Search au lieu d'être un input local
Wirings :
- SearchSection (Home + Guides) : trigger
- MyPlantsScreen : trigger (suppression de l'inline filtering, plus utilisé)
- FloatingSearch (Map) : trigger avec fromMap: true
- RootNavigator : Stack.Screen Search avec options dynamique selon param
i18n FR + EN :
- search.{placeholder, placeholderMap, recentTitle, clearAll, noRecent,
resultsTitle, noResults, nearbyPlantsTitle, noPlants}
- search.filter.{all, diseases, guides, plants}
- search.section.{diseases, guides, plants}
- search.tag.{disease, guide, plant}
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
EditNameBottomSheet :
- Render conditionnel (mounted seulement quand editingName=true) pour ne plus
ouvrir le clavier auto à l'arrivée sur ScanDetail
- BottomSheetScrollView avec contentContainerStyle inline (Tailwind pour le
reste) + insets.bottom pour padding bas
- isDirty disable du Save quand le nom n'a pas changé
- Boutons Annuler/Enregistrer en row via inner View avec icônes X/Check,
font-bold, minHeight 56px
EditProfileModal :
- BottomSheetScrollView : actions déplacées DANS le scroll (juste après le
dernier input email) → toujours visibles sous le formulaire, jamais
poussées en bas du sheet
- snap 95% + topInset safe-area
- Boutons même style (icônes + ghost grisé bordé + primary shadow)
MapBottomSheet rename inline :
- useImperativeHandle pour forwarder le ref correctement et avoir un
internalRef accessible côté composant
- snapToIndex(2) à l'ouverture du form (85%) puis snapToIndex(0) après
save/cancel pour redonner la map
- BottomSheetScrollView pour le rename form avec keyboardShouldPersistTaps
- keyboardBehavior 'interactive' + android_keyboardInputMode 'adjustResize'
- containerStyle { zIndex:100, elevation:100 } pour passer au-dessus des
FloatingActions
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Remplace le Modal+KeyboardAvoidingView+ScrollView par un BottomSheet
(@gorhom/bottom-sheet) avec snap 95% + topInset safe-area +
keyboardBehavior 'interactive' + android_keyboardInputMode 'adjustResize'.
L'API publique du composant (visible/onClose/onSave) est inchangée.
Boutons Cancel/Save dans le BottomSheetScrollView (juste après le dernier
input email) avec icônes X/Check, layout row via inner View, ghost grisé
bordé + primary shadow.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Nouveau composant EditNameBottomSheet (gorhom BottomSheet +
BottomSheetTextInput + BottomSheetScrollView) avec snap 92%, topInset
safe-area, keyboardBehavior interactive, autoFocus
- Mounted conditionnellement (state editingName) pour éviter que l'autoFocus
ouvre le clavier dès l'arrivée sur ScanDetail
- Boutons Annuler / Enregistrer avec icônes X / Check, ghost grisé bordé +
primary shadow, alignés en row via inner View, isDirty disable du Save si
le nom n'a pas changé
- ScanDetailScreen : bouton Pencil flottant à côté du favori, heroTitle
utilise customName en priorité
- useScanDetail : nouvelle méthode renameScan(newName) avec persist storage
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Comportement 2-clicks sur la liste des scans :
- 1er clic : map zoom sur le scan + sheet snap au plus bas + tile preview
unique avec hint 'Appuyez à nouveau pour voir les détails'
- 2e clic même scan : navigate vers ScanDetail
- Clic autre scan en preview : switch preview + zoom
Rename inline dans le BottomSheet existant (plus de 2e sheet superposé) :
- Bouton retour (ChevronLeft) au lieu de croix
- Form (BottomSheetTextInput) avec keyboardBehavior='interactive' +
android_keyboardInputMode='adjustResize' pour ne pas masquer l'input
- Boutons Annuler/Enregistrer avec icônes (X / Check), border 1.5px primary,
shadow primary[900] sur le Save, minHeight 56px
- snapToIndex(2) à l'ouverture du form (85%) puis snapToIndex(0) après
save/cancel pour redonner la map à voir
- containerStyle { zIndex:100, elevation:100 } pour passer au-dessus des
FloatingActions quand le sheet s'expand
FloatingActions : couleur d'icône via prop color (className n'est pas
supporté pour la couleur sur lucide-react-native sans cssInterop).
actionsSlot : zIndex/elevation 1 pour passer derrière le sheet expanded.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Refonte HomeScreen :
- 'Commencer votre collection' (HomeCta) → conditionnellement remplacé par
les 3 derniers scans en mode \"grouped card\" via le nouveau composant
RecentScans (fallback HomeCta si historique vide)
- 'Maladies fréquentes' → SmallDiseaseCard remplacé par LargeDiseaseCard
en mode compact, en scroll horizontal (FrequentDiseasesHorizontal)
- Comment temporairement <SeasonAlert /> en attendant la page Notifications
LargeDiseaseCard : nouvelle prop compact qui réduit hauteur (260→220),
padding, font-sizes et lignes de description (3→2). Border + radius +
shadow Android forcés en style inline pour clip elevation correctement.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Aligne le rendu des date groups sur le pattern PracticalGuides : items
encapsulés dans une card blanche rounded-16, séparés par une ligne grise
indentée.
- ScanListItem : nouvelles props grouped + showSeparator → désactive
borderRadius/margins/border individuels et active la ligne séparatrice
alignée sous le texte
- DateGroupAccordion : wrappe les ScanListItem dans une View card avec
shadow iOS / elevation Android
Le même pattern est réutilisé par RecentScans (Home) — voir commit suivant.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Extrait la barre de recherche en composant partagé
(components/shared/SearchBar.tsx) avec props placeholder/value/onChangeText/
showFilter.
- Home (SearchSection) : utilise le composant partagé
- Map (FloatingSearch) : remplace l'input custom + ajuste les chips (border
primary, font-size 15→12, MapPin couleur primary)
- MyPlants : remplace l'input custom + son bouton clear
Bonus : SearchBar gère proprement le clavier Android via numberOfLines={1},
multiline={false}, scrollEnabled={false}, lineHeight 20 + textAlignVertical
center + includeFontPadding false → le placeholder ne wrappe plus sur 2 lignes.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Commente (sans supprimer) les liens et imports de NotificationsScreen :
- HeaderActionButtons : bouton cloche commenté → seul Settings reste
- RootNavigator : import + Stack.Screen commentés
- linking : deep-link 'notifications' commenté
- types/navigation : route param 'Notifications' commenté
À réactiver via la recherche de \"// TODO: réactiver quand la page Notifications\".
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
ConfidenceTile multipliait par 100 une valeur déjà 0-100 (résultat 7000%).
Aligne le composant sur la convention 0-100 utilisée partout dans le projet
(useGameProgress, ScanCard, ScanDetail, ResultScreen, model.ts).
Corrige aussi mockSeed (0.94 → 94, etc.) pour matcher la convention.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Contexte
- Build Android C++ instable sur Windows (CMake/Ninja path too long, Nitro
headers manquants au clean). Modèle .tflite final pas encore prêt.
- Désinstall temporaire des deux libs natives, le mock JS dans model.ts
continue de servir les détections simulées pondérées.
Changements
- package.json : retire react-native-fast-tflite (3.0.1)
- pnpm-lock.yaml : régénéré, -72 packages dont nitro-modules
- src/services/tflite/model.ts : refactor pur mock, interface publique
inchangée (loadModel + runInference), procédure de réintégration
documentée en tête du fichier
- plugins/withCmakeFix.js : plugin Expo config qui injecte les flags
CMake (response files + ninja 1.12.1 + OBJECT_PATH_MAX) à chaque
prebuild — dormant tant que fast-tflite n'est pas réintégré
- app.json : référence le plugin
- CLAUDE.md + .claude/notes/android-build : doc de l'état actuel et
des étapes de réintégration (idéalement via EAS Build)
Reste
- src/assets/models/grapevine_v1.tflite conservé pour la réintégration
- metro.config.js continue de déclarer .tflite dans assetExts
- TypeScript check: 1 erreur préexistante (homeheader.tsx, palette[50]),
non liée à ce changement
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds a "Add mock plants" entry under a new Developer section in the
Settings screen, gated by __DEV__ so it never ships in release. It
calls useHistory.seedTestData() which prepends 5 fake ScanRecords
spread across Bordeaux / Bourgogne / Champagne so all the map
features (region chips, markers, rename) can be exercised without
having to actually walk into a vineyard.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Replace the Google-Maps-backed react-native-maps screen with a self-
contained WebView running Leaflet + Carto/OSM tiles. No API key, no
native compilation surface. The map is now driven by the real scan
history (useHistory) instead of mock parcels.
What's on the screen now:
- Markers for every ScanRecord that carries lat/lng, colored by
status (healthy / infected / uncertain) derived from diseaseClass.
- Tapping a marker animates the camera and opens ScanDetail.
- Bottom sheet lists the same located scans with rename support: a
pencil opens a modal-input that calls renameScan() to set
ScanRecord.customName (empty value clears it). When the history is
empty the sheet auto-snaps higher and shows a CTA to the Scanner.
- Region chips (Bordeaux/Bourgogne/Champagne) animate the camera and
draw the actual department polygon as a dashed green outline. The
GeoJSON is fetched on the React Native side (avoids the opaque
origin CORS issue inside `source={{ html }}`) and cached in a
useRef Map.
- "Ma position" filter + Locate FAB drop a circular green pin with a
smiley SVG and a pulse halo at the user's GPS coords.
- FloatingActions and FloatingSearch tags restyled to match the
Apple-inspired Bento spec (rounded-full FABs, 56x56, soft shadows,
primary[900] active state).
VineyardMarker (orphan since markers are SVG inside the WebView) and
the data/mockScans.ts file were removed.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Capture the user's location in parallel with TFLite inference so saving
the scan doesn't slow down the camera flow. Permission is requested
just-in-time on the first capture (not at app boot) and refusals are
surfaced once via toast — repeat refusals stay silent (flag persisted
in AsyncStorage under @vineye:location-permission-asked).
- ScanRecord gains optional latitude / longitude / locationCapturedAt
(plus customName + getScanStatus helper used by the Map screen).
All fields optional so older scans keep working unchanged.
- New useScanLocation hook: requestForegroundPermissionsAsync +
getCurrentPositionAsync(Balanced) with a 5s timeout. On any failure
returns null so the scan still saves without coordinates.
- ScannerScreen runs analyze() and requestAndGetLocation() through
Promise.all so GPS acquisition does not block inference.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Add VinEye/.npmrc with node-linker=hoisted to avoid Windows MAX_PATH
crashes with .pnpm/<hash>/ deep paths during native compilation
- Replace react-native-maps (Google Maps SDK requires API key) with
react-native-webview (renders Leaflet + OSM tiles, no key needed)
- Add expo-location for GPS capture during scans
- Add expo-dev-client for proper HMR + deep-link launch in dev builds
- Configure expo-location plugin in app.json with FR permission strings
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
New screens: Guides, Library, Map, Notifications, Settings.
Home refactored with modular components (SearchHeader, HomeCta, FrequentDiseases, SeasonAlert, PracticalGuides).
Replaced hardcoded colors with theme tokens in SeasonAlert and HomeCta.
Updated navigation, i18n, and CLAUDE.md.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Replace floating pill tab bar with classic anchored bottom bar (Home | FAB Scan | Map)
- Add central FAB button (green, elevated) for Scanner
- Move History → Notifications and Profile → Settings (accessible via header icons)
- Add SearchHeader with bell (notifications) and settings icons
- Add MapScreen placeholder
- Extract SearchHeader component from HomeScreen
- Switch to lucide-react-native icons for bottom tab bar
- Fix react-dom version mismatch (19.2.4 → 19.1.0)
- Clean up unused imports in homeheader.tsx
- Update navigation types, deep links, and i18n keys
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>