refactor navigation: classic bottom tab bar with FAB + header icons

- 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>
This commit is contained in:
Yanis 2026-04-02 20:14:27 +02:00
parent a964cc3836
commit 001658898e
19 changed files with 504 additions and 195 deletions

3
.gitignore vendored
View file

@ -23,3 +23,6 @@ VinEye/.expo/
VinEye/dist/ VinEye/dist/
VinEye/ios/ VinEye/ios/
VinEye/android/ VinEye/android/
# dependances
node_modules/

65
AGENTS.md Normal file
View file

@ -0,0 +1,65 @@
# Repository Guidelines
Monorepo with two components: a **Python/TensorFlow CNN** for grapevine disease detection and a **React Native (Expo) mobile app** (VinEye) that runs the model on-device via TFLite.
## Project Structure & Module Organization
```
venv/src/ # Python ML pipeline (training, evaluation, attribution)
venv/models/ # Trained model artifacts (.keras, .tflite)
docs/images/ # Dataset & results visualizations
VinEye/ # Expo React Native mobile app
src/screens/ # 6 screens: Splash, Home, Scanner, Result, History, Profile
src/components/ # UI grouped by feature (gamification/, scanner/, history/, ui/)
src/services/ # TFLite inference, AsyncStorage, haptics
src/hooks/ # useDetection, useGameProgress, useHistory
src/navigation/ # React Navigation v7 (BottomTabs + NativeStack)
src/i18n/ # FR + EN translations (i18next)
src/theme/ # Design tokens (primary #2D6A4F, accent #7C3AED)
```
The ML model currently uses a mock TFLite detector in the mobile app (weighted random: 70% vine / 20% uncertain / 10% not_vine). The CNN trains on 9027 images (256x256) across 4 classes: Black Rot, ESCA, Healthy, Leaf Blight.
## Build, Test, and Development Commands
### VinEye (Mobile)
```bash
cd VinEye
pnpm install # Install dependencies (pnpm only, never npm/yarn)
pnpm start # Start Expo dev server
pnpm android # Run on Android
pnpm ios # Run on iOS
pnpm web # Run on web
```
### Python ML Pipeline
```bash
cd venv/src
python data_split.py # Split raw data into train/val/test (80/10/10)
python data_explore.py # EDA: class distribution, sample visualization
python model_train.py # Train CNN, exports .keras + .tflite to venv/models/
python evaluate_model.py # Accuracy/loss curves, confusion matrix, top-k predictions
python gradient.py # Integrated gradients attribution masks
```
Scripts must be run from `venv/src/` — paths are derived relative to that directory.
## Coding Style & Naming Conventions
**TypeScript (VinEye):**
- Strict mode enabled, path alias `@/*` maps to `src/*`
- Max 300 lines per file
- NativeWind (TailwindCSS) for styling — no inline styles
- `useEffect` must be imported from `react`, never from `react-native-reanimated`
- React Navigation v7 only (Expo Router is forbidden)
- RN-native UI components only (no web-based component libraries)
**Python:** TensorFlow/Keras Sequential API, scripts use `from module import *` pattern.
No linter or formatter configs are enforced.
## Commit Guidelines
Commit messages are informal, descriptive, lowercase. No conventional commits format is enforced. Examples from history: `add VinEye frontend app + fix hardcoded paths + gitignore`, `update`, `maj`.

BIN
VinEye/assets/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

View file

@ -28,8 +28,10 @@
"expo-status-bar": "~3.0.9", "expo-status-bar": "~3.0.9",
"i18next": "^26.0.1", "i18next": "^26.0.1",
"lottie-react-native": "^7.3.6", "lottie-react-native": "^7.3.6",
"lucide-react-native": "^1.7.0",
"nativewind": "^4.2.3", "nativewind": "^4.2.3",
"react": "19.1.0", "react": "19.1.0",
"react-dom": "19.1.0",
"react-i18next": "^17.0.1", "react-i18next": "^17.0.1",
"react-lucid": "^0.0.1", "react-lucid": "^0.0.1",
"react-native": "0.81.5", "react-native": "0.81.5",
@ -37,6 +39,7 @@
"react-native-safe-area-context": "~5.6.0", "react-native-safe-area-context": "~5.6.0",
"react-native-screens": "~4.16.0", "react-native-screens": "~4.16.0",
"react-native-svg": "^15.12.1", "react-native-svg": "^15.12.1",
"react-native-web": "^0.21.2",
"react-native-worklets": "0.5.1", "react-native-worklets": "0.5.1",
"tailwind-merge": "^3.5.0", "tailwind-merge": "^3.5.0",
"tailwindcss": "3.4.17" "tailwindcss": "3.4.17"

View file

@ -25,13 +25,13 @@ importers:
version: 7.14.10(@react-navigation/native@7.2.2(react-native@0.81.5(@babel/core@7.29.0)(@react-native/metro-config@0.84.1(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native-safe-area-context@5.6.2(react-native@0.81.5(@babel/core@7.29.0)(@react-native/metro-config@0.84.1(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native-screens@4.16.0(react-native@0.81.5(@babel/core@7.29.0)(@react-native/metro-config@0.84.1(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.29.0)(@react-native/metro-config@0.84.1(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) version: 7.14.10(@react-navigation/native@7.2.2(react-native@0.81.5(@babel/core@7.29.0)(@react-native/metro-config@0.84.1(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native-safe-area-context@5.6.2(react-native@0.81.5(@babel/core@7.29.0)(@react-native/metro-config@0.84.1(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native-screens@4.16.0(react-native@0.81.5(@babel/core@7.29.0)(@react-native/metro-config@0.84.1(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.29.0)(@react-native/metro-config@0.84.1(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)
'@rn-primitives/portal': '@rn-primitives/portal':
specifier: ^1.4.0 specifier: ^1.4.0
version: 1.4.0(@types/react@19.1.17)(react-native@0.81.5(@babel/core@7.29.0)(@react-native/metro-config@0.84.1(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)(use-sync-external-store@1.6.0(react@19.1.0)) version: 1.4.0(@types/react@19.1.17)(react-native-web@0.21.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.29.0)(@react-native/metro-config@0.84.1(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)(use-sync-external-store@1.6.0(react@19.1.0))
'@rn-primitives/separator': '@rn-primitives/separator':
specifier: ^1.4.0 specifier: ^1.4.0
version: 1.4.0(@types/react@19.1.17)(react-dom@19.2.4(react@19.1.0))(react-native@0.81.5(@babel/core@7.29.0)(@react-native/metro-config@0.84.1(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) version: 1.4.0(@types/react@19.1.17)(react-dom@19.1.0(react@19.1.0))(react-native-web@0.21.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.29.0)(@react-native/metro-config@0.84.1(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)
'@rn-primitives/slot': '@rn-primitives/slot':
specifier: ^1.4.0 specifier: ^1.4.0
version: 1.4.0(react-native@0.81.5(@babel/core@7.29.0)(@react-native/metro-config@0.84.1(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) version: 1.4.0(react-native-web@0.21.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.29.0)(@react-native/metro-config@0.84.1(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)
class-variance-authority: class-variance-authority:
specifier: ^0.7.1 specifier: ^0.7.1
version: 0.7.1 version: 0.7.1
@ -43,13 +43,13 @@ importers:
version: 54.0.33(@babel/core@7.29.0)(react-native@0.81.5(@babel/core@7.29.0)(@react-native/metro-config@0.84.1(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) version: 54.0.33(@babel/core@7.29.0)(react-native@0.81.5(@babel/core@7.29.0)(@react-native/metro-config@0.84.1(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)
expo-camera: expo-camera:
specifier: ~17.0.10 specifier: ~17.0.10
version: 17.0.10(expo@54.0.33(@babel/core@7.29.0)(react-native@0.81.5(@babel/core@7.29.0)(@react-native/metro-config@0.84.1(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.29.0)(@react-native/metro-config@0.84.1(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) version: 17.0.10(expo@54.0.33(@babel/core@7.29.0)(react-native@0.81.5(@babel/core@7.29.0)(@react-native/metro-config@0.84.1(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native-web@0.21.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.29.0)(@react-native/metro-config@0.84.1(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)
expo-haptics: expo-haptics:
specifier: ~15.0.8 specifier: ~15.0.8
version: 15.0.8(expo@54.0.33(@babel/core@7.29.0)(react-native@0.81.5(@babel/core@7.29.0)(@react-native/metro-config@0.84.1(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)) version: 15.0.8(expo@54.0.33(@babel/core@7.29.0)(react-native@0.81.5(@babel/core@7.29.0)(@react-native/metro-config@0.84.1(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))
expo-image: expo-image:
specifier: ~3.0.11 specifier: ~3.0.11
version: 3.0.11(expo@54.0.33(@babel/core@7.29.0)(react-native@0.81.5(@babel/core@7.29.0)(@react-native/metro-config@0.84.1(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.29.0)(@react-native/metro-config@0.84.1(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) version: 3.0.11(expo@54.0.33(@babel/core@7.29.0)(react-native@0.81.5(@babel/core@7.29.0)(@react-native/metro-config@0.84.1(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native-web@0.21.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.29.0)(@react-native/metro-config@0.84.1(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)
expo-linear-gradient: expo-linear-gradient:
specifier: ~15.0.8 specifier: ~15.0.8
version: 15.0.8(expo@54.0.33(@babel/core@7.29.0)(react-native@0.81.5(@babel/core@7.29.0)(@react-native/metro-config@0.84.1(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.29.0)(@react-native/metro-config@0.84.1(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) version: 15.0.8(expo@54.0.33(@babel/core@7.29.0)(react-native@0.81.5(@babel/core@7.29.0)(@react-native/metro-config@0.84.1(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.29.0)(@react-native/metro-config@0.84.1(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)
@ -65,15 +65,21 @@ importers:
lottie-react-native: lottie-react-native:
specifier: ^7.3.6 specifier: ^7.3.6
version: 7.3.6(react-native@0.81.5(@babel/core@7.29.0)(@react-native/metro-config@0.84.1(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) version: 7.3.6(react-native@0.81.5(@babel/core@7.29.0)(@react-native/metro-config@0.84.1(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)
lucide-react-native:
specifier: ^1.7.0
version: 1.7.0(react-native-svg@15.12.1(react-native@0.81.5(@babel/core@7.29.0)(@react-native/metro-config@0.84.1(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.29.0)(@react-native/metro-config@0.84.1(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)
nativewind: nativewind:
specifier: ^4.2.3 specifier: ^4.2.3
version: 4.2.3(react-native-reanimated@4.1.7(react-native-worklets@0.5.1(@babel/core@7.29.0)(react-native@0.81.5(@babel/core@7.29.0)(@react-native/metro-config@0.84.1(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.29.0)(@react-native/metro-config@0.84.1(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native-safe-area-context@5.6.2(react-native@0.81.5(@babel/core@7.29.0)(@react-native/metro-config@0.84.1(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native-svg@15.12.1(react-native@0.81.5(@babel/core@7.29.0)(@react-native/metro-config@0.84.1(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.29.0)(@react-native/metro-config@0.84.1(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)(tailwindcss@3.4.17) version: 4.2.3(react-native-reanimated@4.1.7(react-native-worklets@0.5.1(@babel/core@7.29.0)(react-native@0.81.5(@babel/core@7.29.0)(@react-native/metro-config@0.84.1(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.29.0)(@react-native/metro-config@0.84.1(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native-safe-area-context@5.6.2(react-native@0.81.5(@babel/core@7.29.0)(@react-native/metro-config@0.84.1(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native-svg@15.12.1(react-native@0.81.5(@babel/core@7.29.0)(@react-native/metro-config@0.84.1(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.29.0)(@react-native/metro-config@0.84.1(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)(tailwindcss@3.4.17)
react: react:
specifier: 19.1.0 specifier: 19.1.0
version: 19.1.0 version: 19.1.0
react-dom:
specifier: 19.1.0
version: 19.1.0(react@19.1.0)
react-i18next: react-i18next:
specifier: ^17.0.1 specifier: ^17.0.1
version: 17.0.1(i18next@26.0.1(typescript@5.9.3))(react-dom@19.2.4(react@19.1.0))(react-native@0.81.5(@babel/core@7.29.0)(@react-native/metro-config@0.84.1(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)(typescript@5.9.3) version: 17.0.1(i18next@26.0.1(typescript@5.9.3))(react-dom@19.1.0(react@19.1.0))(react-native@0.81.5(@babel/core@7.29.0)(@react-native/metro-config@0.84.1(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)(typescript@5.9.3)
react-lucid: react-lucid:
specifier: ^0.0.1 specifier: ^0.0.1
version: 0.0.1 version: 0.0.1
@ -92,6 +98,9 @@ importers:
react-native-svg: react-native-svg:
specifier: ^15.12.1 specifier: ^15.12.1
version: 15.12.1(react-native@0.81.5(@babel/core@7.29.0)(@react-native/metro-config@0.84.1(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) version: 15.12.1(react-native@0.81.5(@babel/core@7.29.0)(@react-native/metro-config@0.84.1(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)
react-native-web:
specifier: ^0.21.2
version: 0.21.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
react-native-worklets: react-native-worklets:
specifier: 0.5.1 specifier: 0.5.1
version: 0.5.1(@babel/core@7.29.0)(react-native@0.81.5(@babel/core@7.29.0)(@react-native/metro-config@0.84.1(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) version: 0.5.1(@babel/core@7.29.0)(react-native@0.81.5(@babel/core@7.29.0)(@react-native/metro-config@0.84.1(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)
@ -932,6 +941,9 @@ packages:
resolution: {integrity: sha512-KlRawK4aXxRLlR3HYVfZKhfQp7sejQefQ/LttUWUkErhKO0AFt+yznoSLq7xwIrH9K3A3YwImHuFVtUtuDmurA==} resolution: {integrity: sha512-KlRawK4aXxRLlR3HYVfZKhfQp7sejQefQ/LttUWUkErhKO0AFt+yznoSLq7xwIrH9K3A3YwImHuFVtUtuDmurA==}
engines: {node: '>= 20.19.4'} engines: {node: '>= 20.19.4'}
'@react-native/normalize-colors@0.74.89':
resolution: {integrity: sha512-qoMMXddVKVhZ8PA1AbUCk83trpd6N+1nF2A6k1i6LsQObyS92fELuk8kU/lQs6M7BsMHwqyLCpQJ1uFgNvIQXg==}
'@react-native/normalize-colors@0.81.5': '@react-native/normalize-colors@0.81.5':
resolution: {integrity: sha512-0HuJ8YtqlTVRXGZuGeBejLE04wSQsibpTI+RGOyVqxZvgtlLLC/Ssw0UmbHhT4lYMp2fhdtvKZSs5emWB1zR/g==} resolution: {integrity: sha512-0HuJ8YtqlTVRXGZuGeBejLE04wSQsibpTI+RGOyVqxZvgtlLLC/Ssw0UmbHhT4lYMp2fhdtvKZSs5emWB1zR/g==}
@ -1443,10 +1455,16 @@ packages:
core-js-compat@3.49.0: core-js-compat@3.49.0:
resolution: {integrity: sha512-VQXt1jr9cBz03b331DFDCCP90b3fanciLkgiOoy8SBHy06gNf+vQ1A3WFLqG7I8TipYIKeYK9wxd0tUrvHcOZA==} resolution: {integrity: sha512-VQXt1jr9cBz03b331DFDCCP90b3fanciLkgiOoy8SBHy06gNf+vQ1A3WFLqG7I8TipYIKeYK9wxd0tUrvHcOZA==}
cross-fetch@3.2.0:
resolution: {integrity: sha512-Q+xVJLoGOeIMXZmbUK4HYk+69cQH6LudR0Vu/pRm2YlU/hDV9CiS0gKUMaWY5f2NeUH9C1nV3bsTlCo0FsTV1Q==}
cross-spawn@7.0.6: cross-spawn@7.0.6:
resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==}
engines: {node: '>= 8'} engines: {node: '>= 8'}
css-in-js-utils@3.1.0:
resolution: {integrity: sha512-fJAcud6B3rRu+KHYk+Bwf+WFL2MDCJJ1XG9x137tJQ0xYxor7XziQtuGFbWNdqrvF4Tk26O3H73nfVqXt/fW1A==}
css-select@5.2.2: css-select@5.2.2:
resolution: {integrity: sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==} resolution: {integrity: sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==}
@ -1742,6 +1760,12 @@ packages:
fb-watchman@2.0.2: fb-watchman@2.0.2:
resolution: {integrity: sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==} resolution: {integrity: sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==}
fbjs-css-vars@1.0.2:
resolution: {integrity: sha512-b2XGFAFdWZWg0phtAWLHCk836A1Xann+I+Dgd3Gk64MHKZO44FfoD1KxyvbSh0qZsIoXQGGlVztIY+oitJPpRQ==}
fbjs@3.0.5:
resolution: {integrity: sha512-ztsSx77JBtkuMrEypfhgc3cI0+0h+svqeie7xHbh1k/IKdcydnvadp/mUaGgjAOXQmQSxsqgaRhS3q9fy+1kxg==}
fdir@6.5.0: fdir@6.5.0:
resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==}
engines: {node: '>=12.0.0'} engines: {node: '>=12.0.0'}
@ -1872,6 +1896,9 @@ packages:
resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==} resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==}
engines: {node: '>= 14'} engines: {node: '>= 14'}
hyphenate-style-name@1.1.0:
resolution: {integrity: sha512-WDC/ui2VVRrz3jOVi+XtjqkDjiVjTtFaAGiW37k6b+ohyQ5wYDOGkvCZa8+H0nx3gyvv0+BST9xuOgIyGQ00gw==}
i18next@26.0.1: i18next@26.0.1:
resolution: {integrity: sha512-vtz5sXU4+nkCm8yEU+JJ6yYIx0mkg9e68W0G0PXpnOsmzLajNsW5o28DJMqbajxfsfq0gV3XdrBudsDQnwxfsQ==} resolution: {integrity: sha512-vtz5sXU4+nkCm8yEU+JJ6yYIx0mkg9e68W0G0PXpnOsmzLajNsW5o28DJMqbajxfsfq0gV3XdrBudsDQnwxfsQ==}
peerDependencies: peerDependencies:
@ -1906,6 +1933,9 @@ packages:
ini@1.3.8: ini@1.3.8:
resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==} resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==}
inline-style-prefixer@7.0.1:
resolution: {integrity: sha512-lhYo5qNTQp3EvSSp3sRvXMbVQTLrvGV6DycRMJ5dm2BLMiJ30wpXKdDdgX+GmJZ5uQMucwRKHamXSst3Sj/Giw==}
invariant@2.2.4: invariant@2.2.4:
resolution: {integrity: sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==} resolution: {integrity: sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==}
@ -2224,6 +2254,13 @@ packages:
lru-cache@5.1.1: lru-cache@5.1.1:
resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==}
lucide-react-native@1.7.0:
resolution: {integrity: sha512-wGJY5nosSawh028jg8r1ZKqnGPDIVfIL9xvKOs4wPYFQHeJMHsADYm/lmuFYXMXXatSkHhpsCjeqIRgeFGzf8g==}
peerDependencies:
react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0
react-native: '*'
react-native-svg: ^12.0.0 || ^13.0.0 || ^14.0.0 || ^15.0.0
makeerror@1.0.12: makeerror@1.0.12:
resolution: {integrity: sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==} resolution: {integrity: sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==}
@ -2236,6 +2273,9 @@ packages:
memoize-one@5.2.1: memoize-one@5.2.1:
resolution: {integrity: sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==} resolution: {integrity: sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==}
memoize-one@6.0.0:
resolution: {integrity: sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==}
merge-options@3.0.4: merge-options@3.0.4:
resolution: {integrity: sha512-2Sug1+knBjkaMsMgf1ctR1Ujx+Ayku4EdJN4Z+C2+JzoeF7A3OZ9KM2GY0CpQS51NR61LTurMJrRKPhSs3ZRTQ==} resolution: {integrity: sha512-2Sug1+knBjkaMsMgf1ctR1Ujx+Ayku4EdJN4Z+C2+JzoeF7A3OZ9KM2GY0CpQS51NR61LTurMJrRKPhSs3ZRTQ==}
engines: {node: '>=10'} engines: {node: '>=10'}
@ -2454,6 +2494,15 @@ packages:
nested-error-stacks@2.0.1: nested-error-stacks@2.0.1:
resolution: {integrity: sha512-SrQrok4CATudVzBS7coSz26QRSmlK9TzzoFbeKfcPBUFPjcQM9Rqvr/DlJkOrwI/0KcgvMub1n1g5Jt9EgRn4A==} resolution: {integrity: sha512-SrQrok4CATudVzBS7coSz26QRSmlK9TzzoFbeKfcPBUFPjcQM9Rqvr/DlJkOrwI/0KcgvMub1n1g5Jt9EgRn4A==}
node-fetch@2.7.0:
resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==}
engines: {node: 4.x || >=6.0.0}
peerDependencies:
encoding: ^0.1.0
peerDependenciesMeta:
encoding:
optional: true
node-forge@1.4.0: node-forge@1.4.0:
resolution: {integrity: sha512-LarFH0+6VfriEhqMMcLX2F7SwSXeWwnEAJEsYm5QKWchiVYVvJyV9v7UDvUv+w5HO23ZpQTXDv/GxdDdMyOuoQ==} resolution: {integrity: sha512-LarFH0+6VfriEhqMMcLX2F7SwSXeWwnEAJEsYm5QKWchiVYVvJyV9v7UDvUv+w5HO23ZpQTXDv/GxdDdMyOuoQ==}
engines: {node: '>= 6.13.0'} engines: {node: '>= 6.13.0'}
@ -2656,6 +2705,9 @@ packages:
resolution: {integrity: sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==} resolution: {integrity: sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==}
engines: {node: '>=0.4.0'} engines: {node: '>=0.4.0'}
promise@7.3.1:
resolution: {integrity: sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==}
promise@8.3.0: promise@8.3.0:
resolution: {integrity: sha512-rZPNPKTOYVNEEKFaq1HqTgOwZD+4/YHS5ukLzQCypkj+OkYx7iv0mA91lJlpPPZ8vMau3IIGj5Qlwrx+8iiSmg==} resolution: {integrity: sha512-rZPNPKTOYVNEEKFaq1HqTgOwZD+4/YHS5ukLzQCypkj+OkYx7iv0mA91lJlpPPZ8vMau3IIGj5Qlwrx+8iiSmg==}
@ -2692,10 +2744,10 @@ packages:
react-devtools-core@6.1.5: react-devtools-core@6.1.5:
resolution: {integrity: sha512-ePrwPfxAnB+7hgnEr8vpKxL9cmnp7F322t8oqcPshbIQQhDKgFDW4tjhF2wjVbdXF9O/nyuy3sQWd9JGpiLPvA==} resolution: {integrity: sha512-ePrwPfxAnB+7hgnEr8vpKxL9cmnp7F322t8oqcPshbIQQhDKgFDW4tjhF2wjVbdXF9O/nyuy3sQWd9JGpiLPvA==}
react-dom@19.2.4: react-dom@19.1.0:
resolution: {integrity: sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==} resolution: {integrity: sha512-Xs1hdnE+DyKgeHJeJznQmYMIBG3TKIHJJT95Q58nHLSrElKlGQqDTR2HQ9fx5CN/Gk6Vh/kupBTDLU11/nDk/g==}
peerDependencies: peerDependencies:
react: ^19.2.4 react: ^19.1.0
react-freeze@1.0.4: react-freeze@1.0.4:
resolution: {integrity: sha512-r4F0Sec0BLxWicc7HEyo2x3/2icUTrRmDjaaRyzzn+7aDyFZliszMDOgLVwSnQnYENOlL1o569Ze2HZefk8clA==} resolution: {integrity: sha512-r4F0Sec0BLxWicc7HEyo2x3/2icUTrRmDjaaRyzzn+7aDyFZliszMDOgLVwSnQnYENOlL1o569Ze2HZefk8clA==}
@ -2775,6 +2827,12 @@ packages:
react: '*' react: '*'
react-native: '*' react-native: '*'
react-native-web@0.21.2:
resolution: {integrity: sha512-SO2t9/17zM4iEnFvlu2DA9jqNbzNhoUP+AItkoCOyFmDMOhUnBBznBDCYN92fGdfAkfQlWzPoez6+zLxFNsZEg==}
peerDependencies:
react: ^18.0.0 || ^19.0.0
react-dom: ^18.0.0 || ^19.0.0
react-native-worklets@0.5.1: react-native-worklets@0.5.1:
resolution: {integrity: sha512-lJG6Uk9YuojjEX/tQrCbcbmpdLCSFxDK1rJlkDhgqkVi1KZzG7cdcBFQRqyNOOzR9Y0CXNuldmtWTGOyM0k0+w==} resolution: {integrity: sha512-lJG6Uk9YuojjEX/tQrCbcbmpdLCSFxDK1rJlkDhgqkVi1KZzG7cdcBFQRqyNOOzR9Y0CXNuldmtWTGOyM0k0+w==}
peerDependencies: peerDependencies:
@ -2889,9 +2947,6 @@ packages:
scheduler@0.26.0: scheduler@0.26.0:
resolution: {integrity: sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==} resolution: {integrity: sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==}
scheduler@0.27.0:
resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==}
semver@6.3.1: semver@6.3.1:
resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==}
hasBin: true hasBin: true
@ -2918,6 +2973,9 @@ packages:
resolution: {integrity: sha512-x0RTqQel6g5SY7Lg6ZreMmsOzncHFU7nhnRWkKgWuMTu5NN0DR5oruckMqRvacAN9d5w6ARnRBXl9xhDCgfMeA==} resolution: {integrity: sha512-x0RTqQel6g5SY7Lg6ZreMmsOzncHFU7nhnRWkKgWuMTu5NN0DR5oruckMqRvacAN9d5w6ARnRBXl9xhDCgfMeA==}
engines: {node: '>= 0.8.0'} engines: {node: '>= 0.8.0'}
setimmediate@1.0.5:
resolution: {integrity: sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==}
setprototypeof@1.2.0: setprototypeof@1.2.0:
resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==}
@ -3025,6 +3083,9 @@ packages:
structured-headers@0.4.1: structured-headers@0.4.1:
resolution: {integrity: sha512-0MP/Cxx5SzeeZ10p/bZI0S6MpgD+yxAhi1BOQ34jgnMXsCq3j1t6tQnZu+KdlL7dvJTLT3g9xN8tl10TqgFMcg==} resolution: {integrity: sha512-0MP/Cxx5SzeeZ10p/bZI0S6MpgD+yxAhi1BOQ34jgnMXsCq3j1t6tQnZu+KdlL7dvJTLT3g9xN8tl10TqgFMcg==}
styleq@0.1.3:
resolution: {integrity: sha512-3ZUifmCDCQanjeej1f6kyl/BeP/Vae5EYkQ9iJfUm/QwZvlgnZzyflqAsAWYURdtea8Vkvswu2GrC57h3qffcA==}
sucrase@3.35.1: sucrase@3.35.1:
resolution: {integrity: sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw==} resolution: {integrity: sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw==}
engines: {node: '>=16 || 14 >=14.17'} engines: {node: '>=16 || 14 >=14.17'}
@ -3105,6 +3166,9 @@ packages:
resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==}
engines: {node: '>=0.6'} engines: {node: '>=0.6'}
tr46@0.0.3:
resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==}
ts-interface-checker@0.1.13: ts-interface-checker@0.1.13:
resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==}
@ -3125,6 +3189,10 @@ packages:
engines: {node: '>=14.17'} engines: {node: '>=14.17'}
hasBin: true hasBin: true
ua-parser-js@1.0.41:
resolution: {integrity: sha512-LbBDqdIC5s8iROCUjMbW1f5dJQTEFB1+KO9ogbvlb3nm9n4YHa5p4KTvFPWvh2Hs8gZMBuiB1/8+pdfe/tDPug==}
hasBin: true
undici-types@7.18.2: undici-types@7.18.2:
resolution: {integrity: sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==} resolution: {integrity: sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==}
@ -3203,6 +3271,9 @@ packages:
wcwidth@1.0.1: wcwidth@1.0.1:
resolution: {integrity: sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==} resolution: {integrity: sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==}
webidl-conversions@3.0.1:
resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==}
webidl-conversions@5.0.0: webidl-conversions@5.0.0:
resolution: {integrity: sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==} resolution: {integrity: sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==}
engines: {node: '>=8'} engines: {node: '>=8'}
@ -3214,6 +3285,9 @@ packages:
resolution: {integrity: sha512-HoKuzZrUlgpz35YO27XgD28uh/WJH4B0+3ttFqRo//lmq+9T/mIOJ6kqmINI9HpUpz1imRC/nR/lxKpJiv0uig==} resolution: {integrity: sha512-HoKuzZrUlgpz35YO27XgD28uh/WJH4B0+3ttFqRo//lmq+9T/mIOJ6kqmINI9HpUpz1imRC/nR/lxKpJiv0uig==}
engines: {node: '>=10'} engines: {node: '>=10'}
whatwg-url@5.0.0:
resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==}
which@2.0.2: which@2.0.2:
resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==}
engines: {node: '>= 8'} engines: {node: '>= 8'}
@ -4339,19 +4413,19 @@ snapshots:
optionalDependencies: optionalDependencies:
'@types/react': 19.1.17 '@types/react': 19.1.17
'@radix-ui/react-primitive@2.1.4(@types/react@19.1.17)(react-dom@19.2.4(react@19.1.0))(react@19.1.0)': '@radix-ui/react-primitive@2.1.4(@types/react@19.1.17)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)':
dependencies: dependencies:
'@radix-ui/react-slot': 1.2.4(@types/react@19.1.17)(react@19.1.0) '@radix-ui/react-slot': 1.2.4(@types/react@19.1.17)(react@19.1.0)
react: 19.1.0 react: 19.1.0
react-dom: 19.2.4(react@19.1.0) react-dom: 19.1.0(react@19.1.0)
optionalDependencies: optionalDependencies:
'@types/react': 19.1.17 '@types/react': 19.1.17
'@radix-ui/react-separator@1.1.8(@types/react@19.1.17)(react-dom@19.2.4(react@19.1.0))(react@19.1.0)': '@radix-ui/react-separator@1.1.8(@types/react@19.1.17)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)':
dependencies: dependencies:
'@radix-ui/react-primitive': 2.1.4(@types/react@19.1.17)(react-dom@19.2.4(react@19.1.0))(react@19.1.0) '@radix-ui/react-primitive': 2.1.4(@types/react@19.1.17)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
react: 19.1.0 react: 19.1.0
react-dom: 19.2.4(react@19.1.0) react-dom: 19.1.0(react@19.1.0)
optionalDependencies: optionalDependencies:
'@types/react': 19.1.17 '@types/react': 19.1.17
@ -4560,6 +4634,8 @@ snapshots:
- supports-color - supports-color
optional: true optional: true
'@react-native/normalize-colors@0.74.89': {}
'@react-native/normalize-colors@0.81.5': {} '@react-native/normalize-colors@0.81.5': {}
'@react-native/virtualized-lists@0.81.5(@types/react@19.1.17)(react-native@0.81.5(@babel/core@7.29.0)(@react-native/metro-config@0.84.1(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)': '@react-native/virtualized-lists@0.81.5(@types/react@19.1.17)(react-native@0.81.5(@babel/core@7.29.0)(@react-native/metro-config@0.84.1(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)':
@ -4634,41 +4710,45 @@ snapshots:
dependencies: dependencies:
nanoid: 3.3.11 nanoid: 3.3.11
'@rn-primitives/portal@1.4.0(@types/react@19.1.17)(react-native@0.81.5(@babel/core@7.29.0)(@react-native/metro-config@0.84.1(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)(use-sync-external-store@1.6.0(react@19.1.0))': '@rn-primitives/portal@1.4.0(@types/react@19.1.17)(react-native-web@0.21.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.29.0)(@react-native/metro-config@0.84.1(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)(use-sync-external-store@1.6.0(react@19.1.0))':
dependencies: dependencies:
react: 19.1.0 react: 19.1.0
zustand: 5.0.12(@types/react@19.1.17)(react@19.1.0)(use-sync-external-store@1.6.0(react@19.1.0)) zustand: 5.0.12(@types/react@19.1.17)(react@19.1.0)(use-sync-external-store@1.6.0(react@19.1.0))
optionalDependencies: optionalDependencies:
react-native: 0.81.5(@babel/core@7.29.0)(@react-native/metro-config@0.84.1(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.0) react-native: 0.81.5(@babel/core@7.29.0)(@react-native/metro-config@0.84.1(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.0)
react-native-web: 0.21.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
transitivePeerDependencies: transitivePeerDependencies:
- '@types/react' - '@types/react'
- immer - immer
- use-sync-external-store - use-sync-external-store
'@rn-primitives/separator@1.4.0(@types/react@19.1.17)(react-dom@19.2.4(react@19.1.0))(react-native@0.81.5(@babel/core@7.29.0)(@react-native/metro-config@0.84.1(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)': '@rn-primitives/separator@1.4.0(@types/react@19.1.17)(react-dom@19.1.0(react@19.1.0))(react-native-web@0.21.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.29.0)(@react-native/metro-config@0.84.1(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)':
dependencies: dependencies:
'@radix-ui/react-separator': 1.1.8(@types/react@19.1.17)(react-dom@19.2.4(react@19.1.0))(react@19.1.0) '@radix-ui/react-separator': 1.1.8(@types/react@19.1.17)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
'@rn-primitives/slot': 1.4.0(react-native@0.81.5(@babel/core@7.29.0)(@react-native/metro-config@0.84.1(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) '@rn-primitives/slot': 1.4.0(react-native-web@0.21.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.29.0)(@react-native/metro-config@0.84.1(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)
'@rn-primitives/types': 1.4.0(react-native@0.81.5(@babel/core@7.29.0)(@react-native/metro-config@0.84.1(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) '@rn-primitives/types': 1.4.0(react-native-web@0.21.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.29.0)(@react-native/metro-config@0.84.1(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)
react: 19.1.0 react: 19.1.0
optionalDependencies: optionalDependencies:
react-native: 0.81.5(@babel/core@7.29.0)(@react-native/metro-config@0.84.1(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.0) react-native: 0.81.5(@babel/core@7.29.0)(@react-native/metro-config@0.84.1(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.0)
react-native-web: 0.21.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
transitivePeerDependencies: transitivePeerDependencies:
- '@types/react' - '@types/react'
- '@types/react-dom' - '@types/react-dom'
- react-dom - react-dom
'@rn-primitives/slot@1.4.0(react-native@0.81.5(@babel/core@7.29.0)(@react-native/metro-config@0.84.1(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)': '@rn-primitives/slot@1.4.0(react-native-web@0.21.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.29.0)(@react-native/metro-config@0.84.1(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)':
dependencies: dependencies:
react: 19.1.0 react: 19.1.0
optionalDependencies: optionalDependencies:
react-native: 0.81.5(@babel/core@7.29.0)(@react-native/metro-config@0.84.1(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.0) react-native: 0.81.5(@babel/core@7.29.0)(@react-native/metro-config@0.84.1(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.0)
react-native-web: 0.21.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
'@rn-primitives/types@1.4.0(react-native@0.81.5(@babel/core@7.29.0)(@react-native/metro-config@0.84.1(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)': '@rn-primitives/types@1.4.0(react-native-web@0.21.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.29.0)(@react-native/metro-config@0.84.1(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)':
dependencies: dependencies:
react: 19.1.0 react: 19.1.0
optionalDependencies: optionalDependencies:
react-native: 0.81.5(@babel/core@7.29.0)(@react-native/metro-config@0.84.1(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.0) react-native: 0.81.5(@babel/core@7.29.0)(@react-native/metro-config@0.84.1(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.0)
react-native-web: 0.21.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
'@sinclair/typebox@0.27.10': {} '@sinclair/typebox@0.27.10': {}
@ -5151,12 +5231,22 @@ snapshots:
dependencies: dependencies:
browserslist: 4.28.1 browserslist: 4.28.1
cross-fetch@3.2.0:
dependencies:
node-fetch: 2.7.0
transitivePeerDependencies:
- encoding
cross-spawn@7.0.6: cross-spawn@7.0.6:
dependencies: dependencies:
path-key: 3.1.1 path-key: 3.1.1
shebang-command: 2.0.0 shebang-command: 2.0.0
which: 2.0.2 which: 2.0.2
css-in-js-utils@3.1.0:
dependencies:
hyphenate-style-name: 1.1.0
css-select@5.2.2: css-select@5.2.2:
dependencies: dependencies:
boolbase: 1.0.0 boolbase: 1.0.0
@ -5280,12 +5370,14 @@ snapshots:
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
expo-camera@17.0.10(expo@54.0.33(@babel/core@7.29.0)(react-native@0.81.5(@babel/core@7.29.0)(@react-native/metro-config@0.84.1(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.29.0)(@react-native/metro-config@0.84.1(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.0))(react@19.1.0): expo-camera@17.0.10(expo@54.0.33(@babel/core@7.29.0)(react-native@0.81.5(@babel/core@7.29.0)(@react-native/metro-config@0.84.1(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native-web@0.21.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.29.0)(@react-native/metro-config@0.84.1(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.0))(react@19.1.0):
dependencies: dependencies:
expo: 54.0.33(@babel/core@7.29.0)(react-native@0.81.5(@babel/core@7.29.0)(@react-native/metro-config@0.84.1(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) expo: 54.0.33(@babel/core@7.29.0)(react-native@0.81.5(@babel/core@7.29.0)(@react-native/metro-config@0.84.1(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)
invariant: 2.2.4 invariant: 2.2.4
react: 19.1.0 react: 19.1.0
react-native: 0.81.5(@babel/core@7.29.0)(@react-native/metro-config@0.84.1(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.0) react-native: 0.81.5(@babel/core@7.29.0)(@react-native/metro-config@0.84.1(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.0)
optionalDependencies:
react-native-web: 0.21.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
expo-constants@18.0.13(expo@54.0.33(@babel/core@7.29.0)(react-native@0.81.5(@babel/core@7.29.0)(@react-native/metro-config@0.84.1(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.29.0)(@react-native/metro-config@0.84.1(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.0)): expo-constants@18.0.13(expo@54.0.33(@babel/core@7.29.0)(react-native@0.81.5(@babel/core@7.29.0)(@react-native/metro-config@0.84.1(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.29.0)(@react-native/metro-config@0.84.1(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.0)):
dependencies: dependencies:
@ -5312,11 +5404,13 @@ snapshots:
dependencies: dependencies:
expo: 54.0.33(@babel/core@7.29.0)(react-native@0.81.5(@babel/core@7.29.0)(@react-native/metro-config@0.84.1(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) expo: 54.0.33(@babel/core@7.29.0)(react-native@0.81.5(@babel/core@7.29.0)(@react-native/metro-config@0.84.1(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)
expo-image@3.0.11(expo@54.0.33(@babel/core@7.29.0)(react-native@0.81.5(@babel/core@7.29.0)(@react-native/metro-config@0.84.1(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.29.0)(@react-native/metro-config@0.84.1(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.0))(react@19.1.0): expo-image@3.0.11(expo@54.0.33(@babel/core@7.29.0)(react-native@0.81.5(@babel/core@7.29.0)(@react-native/metro-config@0.84.1(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native-web@0.21.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.29.0)(@react-native/metro-config@0.84.1(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.0))(react@19.1.0):
dependencies: dependencies:
expo: 54.0.33(@babel/core@7.29.0)(react-native@0.81.5(@babel/core@7.29.0)(@react-native/metro-config@0.84.1(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) expo: 54.0.33(@babel/core@7.29.0)(react-native@0.81.5(@babel/core@7.29.0)(@react-native/metro-config@0.84.1(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)
react: 19.1.0 react: 19.1.0
react-native: 0.81.5(@babel/core@7.29.0)(@react-native/metro-config@0.84.1(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.0) react-native: 0.81.5(@babel/core@7.29.0)(@react-native/metro-config@0.84.1(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.0)
optionalDependencies:
react-native-web: 0.21.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
expo-keep-awake@15.0.8(expo@54.0.33(@babel/core@7.29.0)(react-native@0.81.5(@babel/core@7.29.0)(@react-native/metro-config@0.84.1(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react@19.1.0): expo-keep-awake@15.0.8(expo@54.0.33(@babel/core@7.29.0)(react-native@0.81.5(@babel/core@7.29.0)(@react-native/metro-config@0.84.1(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react@19.1.0):
dependencies: dependencies:
@ -5412,6 +5506,20 @@ snapshots:
dependencies: dependencies:
bser: 2.1.1 bser: 2.1.1
fbjs-css-vars@1.0.2: {}
fbjs@3.0.5:
dependencies:
cross-fetch: 3.2.0
fbjs-css-vars: 1.0.2
loose-envify: 1.4.0
object-assign: 4.1.1
promise: 7.3.1
setimmediate: 1.0.5
ua-parser-js: 1.0.41
transitivePeerDependencies:
- encoding
fdir@6.5.0(picomatch@4.0.4): fdir@6.5.0(picomatch@4.0.4):
optionalDependencies: optionalDependencies:
picomatch: 4.0.4 picomatch: 4.0.4
@ -5536,6 +5644,8 @@ snapshots:
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
hyphenate-style-name@1.1.0: {}
i18next@26.0.1(typescript@5.9.3): i18next@26.0.1(typescript@5.9.3):
dependencies: dependencies:
'@babel/runtime': 7.29.2 '@babel/runtime': 7.29.2
@ -5561,6 +5671,10 @@ snapshots:
ini@1.3.8: {} ini@1.3.8: {}
inline-style-prefixer@7.0.1:
dependencies:
css-in-js-utils: 3.1.0
invariant@2.2.4: invariant@2.2.4:
dependencies: dependencies:
loose-envify: 1.4.0 loose-envify: 1.4.0
@ -5840,6 +5954,12 @@ snapshots:
dependencies: dependencies:
yallist: 3.1.1 yallist: 3.1.1
lucide-react-native@1.7.0(react-native-svg@15.12.1(react-native@0.81.5(@babel/core@7.29.0)(@react-native/metro-config@0.84.1(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.29.0)(@react-native/metro-config@0.84.1(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.0))(react@19.1.0):
dependencies:
react: 19.1.0
react-native: 0.81.5(@babel/core@7.29.0)(@react-native/metro-config@0.84.1(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.0)
react-native-svg: 15.12.1(react-native@0.81.5(@babel/core@7.29.0)(@react-native/metro-config@0.84.1(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)
makeerror@1.0.12: makeerror@1.0.12:
dependencies: dependencies:
tmpl: 1.0.5 tmpl: 1.0.5
@ -5850,6 +5970,8 @@ snapshots:
memoize-one@5.2.1: {} memoize-one@5.2.1: {}
memoize-one@6.0.0: {}
merge-options@3.0.4: merge-options@3.0.4:
dependencies: dependencies:
is-plain-obj: 2.1.0 is-plain-obj: 2.1.0
@ -6284,6 +6406,10 @@ snapshots:
nested-error-stacks@2.0.1: {} nested-error-stacks@2.0.1: {}
node-fetch@2.7.0:
dependencies:
whatwg-url: 5.0.0
node-forge@1.4.0: {} node-forge@1.4.0: {}
node-int64@0.4.0: {} node-int64@0.4.0: {}
@ -6457,6 +6583,10 @@ snapshots:
progress@2.0.3: {} progress@2.0.3: {}
promise@7.3.1:
dependencies:
asap: 2.0.6
promise@8.3.0: promise@8.3.0:
dependencies: dependencies:
asap: 2.0.6 asap: 2.0.6
@ -6500,16 +6630,16 @@ snapshots:
- bufferutil - bufferutil
- utf-8-validate - utf-8-validate
react-dom@19.2.4(react@19.1.0): react-dom@19.1.0(react@19.1.0):
dependencies: dependencies:
react: 19.1.0 react: 19.1.0
scheduler: 0.27.0 scheduler: 0.26.0
react-freeze@1.0.4(react@19.1.0): react-freeze@1.0.4(react@19.1.0):
dependencies: dependencies:
react: 19.1.0 react: 19.1.0
react-i18next@17.0.1(i18next@26.0.1(typescript@5.9.3))(react-dom@19.2.4(react@19.1.0))(react-native@0.81.5(@babel/core@7.29.0)(@react-native/metro-config@0.84.1(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)(typescript@5.9.3): react-i18next@17.0.1(i18next@26.0.1(typescript@5.9.3))(react-dom@19.1.0(react@19.1.0))(react-native@0.81.5(@babel/core@7.29.0)(@react-native/metro-config@0.84.1(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)(typescript@5.9.3):
dependencies: dependencies:
'@babel/runtime': 7.29.2 '@babel/runtime': 7.29.2
html-parse-stringify: 3.0.1 html-parse-stringify: 3.0.1
@ -6517,7 +6647,7 @@ snapshots:
react: 19.1.0 react: 19.1.0
use-sync-external-store: 1.6.0(react@19.1.0) use-sync-external-store: 1.6.0(react@19.1.0)
optionalDependencies: optionalDependencies:
react-dom: 19.2.4(react@19.1.0) react-dom: 19.1.0(react@19.1.0)
react-native: 0.81.5(@babel/core@7.29.0)(@react-native/metro-config@0.84.1(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.0) react-native: 0.81.5(@babel/core@7.29.0)(@react-native/metro-config@0.84.1(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.0)
typescript: 5.9.3 typescript: 5.9.3
@ -6579,6 +6709,21 @@ snapshots:
react-native: 0.81.5(@babel/core@7.29.0)(@react-native/metro-config@0.84.1(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.0) react-native: 0.81.5(@babel/core@7.29.0)(@react-native/metro-config@0.84.1(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.0)
warn-once: 0.1.1 warn-once: 0.1.1
react-native-web@0.21.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0):
dependencies:
'@babel/runtime': 7.29.2
'@react-native/normalize-colors': 0.74.89
fbjs: 3.0.5
inline-style-prefixer: 7.0.1
memoize-one: 6.0.0
nullthrows: 1.1.1
postcss-value-parser: 4.2.0
react: 19.1.0
react-dom: 19.1.0(react@19.1.0)
styleq: 0.1.3
transitivePeerDependencies:
- encoding
react-native-worklets@0.5.1(@babel/core@7.29.0)(react-native@0.81.5(@babel/core@7.29.0)(@react-native/metro-config@0.84.1(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.0))(react@19.1.0): react-native-worklets@0.5.1(@babel/core@7.29.0)(react-native@0.81.5(@babel/core@7.29.0)(@react-native/metro-config@0.84.1(@babel/core@7.29.0))(@types/react@19.1.17)(react@19.1.0))(react@19.1.0):
dependencies: dependencies:
'@babel/core': 7.29.0 '@babel/core': 7.29.0
@ -6729,8 +6874,6 @@ snapshots:
scheduler@0.26.0: {} scheduler@0.26.0: {}
scheduler@0.27.0: {}
semver@6.3.1: {} semver@6.3.1: {}
semver@7.7.2: {} semver@7.7.2: {}
@ -6766,6 +6909,8 @@ snapshots:
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
setimmediate@1.0.5: {}
setprototypeof@1.2.0: {} setprototypeof@1.2.0: {}
sf-symbols-typescript@2.2.0: {} sf-symbols-typescript@2.2.0: {}
@ -6847,6 +6992,8 @@ snapshots:
structured-headers@0.4.1: {} structured-headers@0.4.1: {}
styleq@0.1.3: {}
sucrase@3.35.1: sucrase@3.35.1:
dependencies: dependencies:
'@jridgewell/gen-mapping': 0.3.13 '@jridgewell/gen-mapping': 0.3.13
@ -6958,6 +7105,8 @@ snapshots:
toidentifier@1.0.1: {} toidentifier@1.0.1: {}
tr46@0.0.3: {}
ts-interface-checker@0.1.13: {} ts-interface-checker@0.1.13: {}
type-detect@4.0.8: {} type-detect@4.0.8: {}
@ -6968,6 +7117,8 @@ snapshots:
typescript@5.9.3: {} typescript@5.9.3: {}
ua-parser-js@1.0.41: {}
undici-types@7.18.2: {} undici-types@7.18.2: {}
undici@6.24.1: {} undici@6.24.1: {}
@ -7023,6 +7174,8 @@ snapshots:
dependencies: dependencies:
defaults: 1.0.4 defaults: 1.0.4
webidl-conversions@3.0.1: {}
webidl-conversions@5.0.0: {} webidl-conversions@5.0.0: {}
whatwg-fetch@3.6.20: {} whatwg-fetch@3.6.20: {}
@ -7033,6 +7186,11 @@ snapshots:
punycode: 2.3.1 punycode: 2.3.1
webidl-conversions: 5.0.0 webidl-conversions: 5.0.0
whatwg-url@5.0.0:
dependencies:
tr46: 0.0.3
webidl-conversions: 3.0.1
which@2.0.2: which@2.0.2:
dependencies: dependencies:
isexe: 2.0.0 isexe: 2.0.0

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 4.4 KiB

View file

@ -0,0 +1,57 @@
import { View, TouchableOpacity, TextInput } from "react-native";
import { useTranslation } from "react-i18next";
import { useNavigation } from "@react-navigation/native";
import type { NativeStackNavigationProp } from "@react-navigation/native-stack";
import { Ionicons } from "@expo/vector-icons";
import { colors } from "@/theme/colors";
import type { RootStackParamList } from "@/types/navigation";
type Nav = NativeStackNavigationProp<RootStackParamList>;
export default function SearchHeader() {
const { t } = useTranslation();
const navigation = useNavigation<Nav>();
return (
<View className="flex-row items-center justify-between px-5 pt-3 pb-4">
<View className="flex-1 flex-row items-center gap-2">
<View className="flex-1 flex-row items-center rounded-full bg-neutral-200 px-3 py-2">
<Ionicons
name="search-outline"
size={18}
color={colors.neutral[500]}
/>
<TextInput
className="ml-2 flex-1 text-[14px]"
placeholder={t("history.search")}
placeholderTextColor={colors.neutral[500]}
style={{ color: colors.neutral[900], paddingVertical: 0 }}
/>
</View>
<TouchableOpacity
className="h-9 w-9 items-center justify-center rounded-full bg-neutral-200"
activeOpacity={0.7}
onPress={() => navigation.navigate("Notifications")}
>
<Ionicons
name="notifications-outline"
size={20}
color={colors.neutral[800]}
/>
</TouchableOpacity>
<TouchableOpacity
className="h-9 w-9 items-center justify-center rounded-full bg-white border border-neutral-200"
activeOpacity={0.7}
onPress={() => navigation.navigate("Settings")}
>
<Ionicons
name="settings-outline"
size={20}
color={colors.neutral[900]}
/>
</TouchableOpacity>
</View>
</View>
);
}

View file

@ -1,32 +1,8 @@
import { useEffect } from "react"; import { View, TouchableOpacity } from "react-native";
import { View, ScrollView, TouchableOpacity, TextInput } from "react-native";
import { SafeAreaView } from "react-native-safe-area-context";
import { useNavigation } from "@react-navigation/native";
import type { BottomTabNavigationProp } from "@react-navigation/bottom-tabs";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { Ionicons } from "@expo/vector-icons";
import Animated, {
useSharedValue,
useAnimatedStyle,
withRepeat,
withSequence,
withTiming,
} from "react-native-reanimated";
import { Text } from "@/components/ui/text"; import { Text } from "@/components/ui/text";
import { ProgressRing } from "@/components/gamification/ProgressRing";
import { ScanCard } from "@/components/history/ScanCard";
import { useGameProgress } from "@/hooks/useGameProgress";
import { useHistory } from "@/hooks/useHistory";
import { colors } from "@/theme/colors"; import { colors } from "@/theme/colors";
import {
getLevelForXP,
getLevelNumber,
getXPProgress,
} from "@/utils/achievements";
import type { BottomTabParamList } from "@/types/navigation";
import StatCard from "@/components/home/gamificationstat";
import StatisticsSection from "@/components/home/statssection";
export default function SectionHeader({ export default function SectionHeader({
title, title,

View file

@ -9,7 +9,10 @@
"confirm": "Confirm", "confirm": "Confirm",
"loading": "Loading...", "loading": "Loading...",
"error": "Error", "error": "Error",
"retry": "Retry" "retry": "Retry",
"map": "Map",
"notifications": "Notifications",
"settings": "Settings"
}, },
"home": { "home": {
"greeting": "Hello, Winemaker!", "greeting": "Hello, Winemaker!",

View file

@ -9,7 +9,10 @@
"confirm": "Confirmer", "confirm": "Confirmer",
"loading": "Chargement...", "loading": "Chargement...",
"error": "Erreur", "error": "Erreur",
"retry": "Réessayer" "retry": "Réessayer",
"map": "Carte",
"notifications": "Notifications",
"settings": "Paramètres"
}, },
"home": { "home": {
"greeting": "Bonjour, Vigneron !", "greeting": "Bonjour, Vigneron !",

View file

@ -1,62 +1,51 @@
import React from 'react'; import React from "react";
import { View, Text, TouchableOpacity, Platform, LayoutAnimation, UIManager } from 'react-native'; import { View, Text, TouchableOpacity, Platform } from "react-native";
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs'; import { createBottomTabNavigator } from "@react-navigation/bottom-tabs";
import { Ionicons } from '@expo/vector-icons'; import { useSafeAreaInsets } from "react-native-safe-area-context";
import { useSafeAreaInsets } from 'react-native-safe-area-context'; import { useTranslation } from "react-i18next";
import { useTranslation } from 'react-i18next'; import * as Haptics from "expo-haptics";
import * as Haptics from 'expo-haptics'; import { House, ScanLine, MapPin } from "lucide-react-native";
// Imports de tes écrans import HomeScreen from "@/screens/HomeScreen";
import HomeScreen from '@/screens/HomeScreen'; import ScannerScreen from "@/screens/ScannerScreen";
import ScannerScreen from '@/screens/ScannerScreen'; import MapScreen from "@/screens/MapScreen";
import HistoryScreen from '@/screens/HistoryScreen'; import { colors } from "@/theme/colors";
import ProfileScreen from '@/screens/ProfileScreen';
// Activation de LayoutAnimation pour Android
if (Platform.OS === 'android' && UIManager.setLayoutAnimationEnabledExperimental) {
UIManager.setLayoutAnimationEnabledExperimental(true);
}
const Tab = createBottomTabNavigator(); const Tab = createBottomTabNavigator();
const TAB_ICONS: Record<string, any> = {
Home: House,
Map: MapPin,
};
function MyCustomTabBar({ state, descriptors, navigation }: any) { function MyCustomTabBar({ state, descriptors, navigation }: any) {
const insets = useSafeAreaInsets(); const insets = useSafeAreaInsets();
const { t } = useTranslation();
// Gestion de la marge basse pour éviter la superposition avec la barre système
const safeBottom = Platform.OS === 'android' ? Math.max(insets.bottom, 24) : insets.bottom;
return ( return (
<View <View
className="absolute bg-white flex-row items-center justify-between px-2"
style={{ style={{
bottom: safeBottom + 10, flexDirection: "row",
left: 20, backgroundColor: colors.surface,
right: 20, borderTopWidth: 1,
height: 70, borderTopColor: colors.neutral[300],
borderRadius: 35, paddingBottom: insets.bottom,
elevation: 12, paddingTop: 8,
shadowColor: '#000', alignItems: "flex-end",
shadowOffset: { width: 0, height: 10 },
shadowOpacity: 0.15,
shadowRadius: 20,
}} }}
> >
{state.routes.map((route: any, index: number) => { {state.routes.map((route: any, index: number) => {
const { options } = descriptors[route.key]; const { options } = descriptors[route.key];
const isFocused = state.index === index; const isFocused = state.index === index;
const label = options.tabBarLabel || route.name;
const isScanner = route.name === "Scanner";
const onPress = () => { const onPress = () => {
// 1. Retour Haptique (Vibration légère "Impact") if (Platform.OS !== "web") {
if (Platform.OS !== 'web') {
Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light); Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light);
} }
// 2. Animation de la transition (Pill expansion)
LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut);
const event = navigation.emit({ const event = navigation.emit({
type: 'tabPress', type: "tabPress",
target: route.key, target: route.key,
canPreventDefault: true, canPreventDefault: true,
}); });
@ -66,48 +55,80 @@ function MyCustomTabBar({ state, descriptors, navigation }: any) {
} }
}; };
// Choix de l'icône (Outline vs Solid) // FAB central pour Scanner
const getIcon = (name: string, focused: boolean) => { if (isScanner) {
switch (name) { return (
case 'Home': return focused ? 'home' : 'home-outline'; <TouchableOpacity
case 'History': return focused ? 'receipt' : 'receipt-outline'; key={route.key}
case 'Scanner': return focused ? 'scan' : 'scan-outline'; onPress={onPress}
case 'Profile': return focused ? 'person' : 'person-outline'; activeOpacity={0.8}
default: return 'help-outline'; accessibilityRole="button"
} accessibilityLabel={label}
}; style={{
flex: 1,
alignItems: "center",
justifyContent: "center",
}}
>
<View
style={{
width: 56,
height: 56,
borderRadius: 28,
backgroundColor: colors.primary[800],
alignItems: "center",
justifyContent: "center",
marginTop: -28,
shadowColor: colors.primary[900],
shadowOffset: { width: 0, height: 4 },
shadowOpacity: 0.3,
shadowRadius: 8,
elevation: 8,
}}
>
<ScanLine size={26} color="#FFFFFF" />
</View>
</TouchableOpacity>
);
}
const label = options.tabBarLabel || route.name; // Onglets classiques (Home, Map)
const Icon = TAB_ICONS[route.name];
const tintColor = isFocused ? colors.primary[700] : colors.neutral[400];
return ( return (
<TouchableOpacity <TouchableOpacity
key={index} key={route.key}
onPress={onPress} onPress={onPress}
activeOpacity={0.7} activeOpacity={0.7}
style={{ flex: isFocused ? 2 : 1 }} accessibilityRole="button"
className="items-center justify-center h-full" accessibilityState={isFocused ? { selected: true } : {}}
accessibilityLabel={label}
style={{
flex: 1,
alignItems: "center",
justifyContent: "center",
paddingVertical: 6,
}}
> >
<View {Icon && (
className={`flex-row items-center justify-center py-2.5 ${ <Icon
isFocused ? 'bg-gray-900 px-5' : 'bg-transparent px-0'
}`}
style={{ borderRadius: 999 }}
>
<Ionicons
name={getIcon(route.name, isFocused) as any}
size={22} size={22}
color={isFocused ? '#FFFFFF' : '#9CA3AF'} color={tintColor}
strokeWidth={isFocused ? 2.5 : 1.8}
/> />
)}
{isFocused && ( <Text
<Text numberOfLines={1}
numberOfLines={1} style={{
className="ml-2 text-white font-bold text-[13px]" fontSize: 11,
> marginTop: 4,
{label} color: tintColor,
</Text> fontWeight: isFocused ? "600" : "400",
)} }}
</View> >
{label}
</Text>
</TouchableOpacity> </TouchableOpacity>
); );
})} })}
@ -126,22 +147,17 @@ export default function BottomTabNavigator() {
<Tab.Screen <Tab.Screen
name="Home" name="Home"
component={HomeScreen} component={HomeScreen}
options={{ tabBarLabel: t('common.home') }} options={{ tabBarLabel: t("common.home") }}
/>
<Tab.Screen
name="History"
component={HistoryScreen}
options={{ tabBarLabel: t('common.history') }}
/> />
<Tab.Screen <Tab.Screen
name="Scanner" name="Scanner"
component={ScannerScreen} component={ScannerScreen}
options={{ tabBarLabel: 'Scan' }} options={{ tabBarLabel: t("common.scan") }}
/> />
<Tab.Screen <Tab.Screen
name="Profile" name="Map"
component={ProfileScreen} component={MapScreen}
options={{ tabBarLabel: t('common.profile') }} options={{ tabBarLabel: t("common.map") }}
/> />
</Tab.Navigator> </Tab.Navigator>
); );

View file

@ -3,6 +3,8 @@ import { NavigationContainer } from '@react-navigation/native';
import SplashScreen from '@/screens/SplashScreen'; import SplashScreen from '@/screens/SplashScreen';
import ResultScreen from '@/screens/ResultScreen'; import ResultScreen from '@/screens/ResultScreen';
import HistoryScreen from '@/screens/HistoryScreen';
import ProfileScreen from '@/screens/ProfileScreen';
import BottomTabNavigator from './BottomTabNavigator'; import BottomTabNavigator from './BottomTabNavigator';
import linking from './linking'; import linking from './linking';
import type { RootStackParamList } from '@/types/navigation'; import type { RootStackParamList } from '@/types/navigation';
@ -23,6 +25,16 @@ export default function RootNavigator() {
component={ResultScreen} component={ResultScreen}
options={{ animation: 'slide_from_bottom', presentation: 'modal' }} options={{ animation: 'slide_from_bottom', presentation: 'modal' }}
/> />
<Stack.Screen
name="Notifications"
component={HistoryScreen}
options={{ animation: 'slide_from_right' }}
/>
<Stack.Screen
name="Settings"
component={ProfileScreen}
options={{ animation: 'slide_from_right' }}
/>
</Stack.Navigator> </Stack.Navigator>
</NavigationContainer> </NavigationContainer>
); );

View file

@ -10,11 +10,12 @@ const linking: LinkingOptions<RootStackParamList> = {
screens: { screens: {
Home: 'home', Home: 'home',
Scanner: 'scan', Scanner: 'scan',
History: 'history', Map: 'map',
Profile: 'profile',
}, },
}, },
Result: 'result', Result: 'result',
Notifications: 'notifications',
Settings: 'settings',
}, },
}, },
}; };

View file

@ -2,7 +2,7 @@ import { useEffect } from "react";
import { View, ScrollView, TouchableOpacity, TextInput } from "react-native"; import { View, ScrollView, TouchableOpacity, TextInput } from "react-native";
import { SafeAreaView } from "react-native-safe-area-context"; import { SafeAreaView } from "react-native-safe-area-context";
import { useNavigation } from "@react-navigation/native"; import { useNavigation } from "@react-navigation/native";
import type { BottomTabNavigationProp } from "@react-navigation/bottom-tabs"; import type { NativeStackNavigationProp } from "@react-navigation/native-stack";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { Ionicons } from "@expo/vector-icons"; import { Ionicons } from "@expo/vector-icons";
import Animated, { import Animated, {
@ -24,13 +24,14 @@ import {
getLevelNumber, getLevelNumber,
getXPProgress, getXPProgress,
} from "@/utils/achievements"; } from "@/utils/achievements";
import type { BottomTabParamList } from "@/types/navigation"; import type { RootStackParamList } from "@/types/navigation";
import StatCard from "@/components/home/gamificationstat"; import StatCard from "@/components/home/gamificationstat";
import StatisticsSection from "@/components/home/statssection"; import StatisticsSection from "@/components/home/statssection";
import SearchHeader from "@/components/home/SearchHeader";
import SectionHeader from "@/components/home/components/homeheader"; import SectionHeader from "@/components/home/components/homeheader";
import MaterialIcons from "@expo/vector-icons/MaterialIcons"; import MaterialIcons from "@expo/vector-icons/MaterialIcons";
type HomeNav = BottomTabNavigationProp<BottomTabParamList, "Home">; type HomeNav = NativeStackNavigationProp<RootStackParamList>;
interface GameProgress { interface GameProgress {
totalScans: number; totalScans: number;
@ -116,37 +117,10 @@ export default function HomeScreen() {
className="flex-1" className="flex-1"
showsVerticalScrollIndicator={false} showsVerticalScrollIndicator={false}
contentContainerStyle={{ contentContainerStyle={{
paddingBottom: 130, // La hauteur de ta barre (70) + le margin bas (~34) + de l'espace pour respirer (26) paddingBottom: 24,
}} }}
> >
{/* Header — title left, icons right */} <SearchHeader />
<View className="flex-row items-center justify-between px-5 pt-3 pb-4">
<View className="flex-1 flex-row items-center gap-2">
<View className="flex-1 flex-row items-center rounded-full bg-neutral-200 px-3 py-2">
<Ionicons
name="search-outline"
size={18}
color={colors.neutral[500]}
/>
<TextInput
className="ml-2 flex-1 text-[14px]"
placeholder={t("history.search")}
placeholderTextColor={colors.neutral[500]}
style={{ color: colors.neutral[900], paddingVertical: 0 }}
/>
</View>
<TouchableOpacity
className="h-9 w-9 items-center justify-center rounded-full bg-neutral-200"
activeOpacity={0.7}
>
<Ionicons
name="add-outline"
size={22}
color={colors.neutral[800]}
/>
</TouchableOpacity>
</View>
</View>
<StatisticsSection progress={userProgress} /> <StatisticsSection progress={userProgress} />
@ -204,7 +178,7 @@ export default function HomeScreen() {
<View className="mx-5 mb-6 gap-2"> <View className="mx-5 mb-6 gap-2">
<SectionHeader <SectionHeader
title={t("home.lastScan")} title={t("home.lastScan")}
onViewAll={() => navigation.navigate("History")} onViewAll={() => navigation.navigate("Notifications")}
/> />
<ScanCard record={lastScan} /> <ScanCard record={lastScan} />
</View> </View>

View file

@ -0,0 +1,30 @@
import { View } from "react-native";
import { SafeAreaView } from "react-native-safe-area-context";
import { useTranslation } from "react-i18next";
import { Ionicons } from "@expo/vector-icons";
import { Text } from "@/components/ui/text";
import { colors } from "@/theme/colors";
export default function MapScreen() {
const { t } = useTranslation();
return (
<SafeAreaView className="flex-1 bg-[#FAFAFA]" edges={["top"]}>
<View className="flex-1 items-center justify-center px-8">
<View
className="mb-6 h-20 w-20 items-center justify-center rounded-full"
style={{ backgroundColor: colors.primary[100] }}
>
<Ionicons name="map-outline" size={36} color={colors.primary[700]} />
</View>
<Text className="mb-2 text-xl font-semibold" style={{ color: colors.neutral[900] }}>
{t("common.map")}
</Text>
<Text className="text-center text-sm" style={{ color: colors.neutral[500] }}>
Coming soon
</Text>
</View>
</SafeAreaView>
);
}

View file

@ -1,5 +1,5 @@
import { useEffect } from 'react'; import { useEffect } from 'react';
import { View, Text, StyleSheet } from 'react-native'; import { View, Text, Image, StyleSheet } from 'react-native';
import { useNavigation } from '@react-navigation/native'; import { useNavigation } from '@react-navigation/native';
import type { NativeStackNavigationProp } from '@react-navigation/native-stack'; import type { NativeStackNavigationProp } from '@react-navigation/native-stack';
import { colors } from '@/theme/colors'; import { colors } from '@/theme/colors';
@ -21,9 +21,13 @@ export default function SplashScreen() {
return ( return (
<View style={styles.container}> <View style={styles.container}>
<Text style={styles.leafEmoji}>🍃</Text> <Image
<Text style={styles.logo}>VinEye</Text> source={require('@/assets/images/icon.png')}
<Text style={styles.subtitle}>Détection de vignes par IA</Text> style={styles.logoImage}
resizeMode="contain"
/>
{/* <Text style={styles.logo}>VinEye</Text>
<Text style={styles.subtitle}>Détection de vignes par IA</Text> */}
</View> </View>
); );
} }
@ -31,12 +35,15 @@ export default function SplashScreen() {
const styles = StyleSheet.create({ const styles = StyleSheet.create({
container: { container: {
flex: 1, flex: 1,
backgroundColor: colors.primary[900], backgroundColor: colors.surface,
alignItems: 'center', alignItems: 'center',
justifyContent: 'center', justifyContent: 'center',
gap: 24,
},
logoImage: {
width: 198,
height: 198,
}, },
leafEmoji: { fontSize: 80 },
logo: { logo: {
fontSize: typography.fontSizes['4xl'], fontSize: typography.fontSizes['4xl'],
fontWeight: typography.fontWeights.extrabold, fontWeight: typography.fontWeights.extrabold,

View file

@ -4,11 +4,12 @@ export type RootStackParamList = {
Splash: undefined; Splash: undefined;
Main: undefined; Main: undefined;
Result: { detection: Detection }; Result: { detection: Detection };
Notifications: undefined;
Settings: undefined;
}; };
export type BottomTabParamList = { export type BottomTabParamList = {
Home: undefined; Home: undefined;
Scanner: undefined; Scanner: undefined;
History: undefined; Map: undefined;
Profile: undefined;
}; };