Application mobile Android développée avec .NET MAUI (C#) permettant aux commerciaux GSB de gérer leur stock personnel d'échantillons de compléments alimentaires.
Technologie : .NET MAUI 10.0 avec SQLite pour la persistance locale
Base de données : SQLite (sqlite-net-pcl)
Pattern MVVM : CommunityToolkit.Mvvm
Plateforme cible : Android 5.0+ (API 21)
AndroidGSB/
├── Models/
│ ├── Echantillon.cs # Modèle produit avec propriétés observables
│ └── MajStock.cs # Modèle mouvement de stock
│
├── Data/
│ ├── DatabaseService.cs # Service d'accès aux données SQLite
│ ├── DatabaseConstants.cs # Constantes de configuration BD
│ └── ServiceHelper.cs # Utilitaire d'injection de dépendances
│
├── ViewModels/
│ ├── BaseViewModel.cs # Base MVVM avec pattern RelayCommand
│ ├── MainViewModel.cs # Page d'accueil - navigation
│ ├── AjoutEchantillonViewModel.cs # Saisie nouveau produit
│ ├── ListeEchantillonsViewModel.cs # Affichage liste produits
│ ├── MajEchantillonViewModel.cs # Ajout/suppression stock
│ └── ListeMouvementsViewModel.cs # Historique mouvements
│
├── Views/
│ ├── MainPage.xaml / .cs # Accueil avec 5 boutons de navigation
│ ├── AjoutEchantillonPage.xaml / .cs # Saisie produit
│ ├── ListeEchantillonsPage.xaml / .cs # Liste scrollable
│ ├── MajEchantillonPage.xaml / .cs # Maj stock
│ └── ListeMouvementsPage.xaml / .cs # Historique avec filtres
│
├── Converters/
│ └── MouvementColorConverter.cs # Colorisation mouvements
│
├── Resources/
│ └── Styles/
│ └── Colors.xaml # Palette GSB sombre
│
├── App.xaml / App.xaml.cs # Configuration app
├── AppShell.xaml / AppShell.xaml.cs # Routes de navigation
├── MainPage.xaml / MainPage.xaml.cs # Page d'accueil
├── MauiProgram.cs # Configuration DI et init BD
└── AndroidGSB.csproj # Configuration projet
- Id (clé primaire, auto-incrémentée)
- CodeProduit (notNull) - ex: "A0001"
- LibelleProduit (notNull)
- Description
- Conseils
- Dosage
- Composition
- Complement
- Stock (float)
- StockMini (float) - seuil d'alerte
Table : Echantillons
- Cle (clé primaire, auto-incrémentée)
- CodeProduit
- Quantite (float)
- Mouvement ("ajout" | "suppression")
- Date (DateTime)
Table : MajStock
Singleton gérant toutes les opérations CRUD :
Méthodes Echantillon:
GetEchantillonsAsync()- Récupère tous les produitsGetEchantillonByCodeAsync(code)- Recherche par codeInsererEchantillonAsync(echantillon)- CréerUpdateEchantillonAsync(echantillon)- Mettre à jourSupprimerEchantillonAsync(code)- Supprimer
Gestion Stock:
AjouterStockAsync(code, quantite)- Incrémente stock + historiqueSupprimerStockAsync(code, quantite)- Décrémente stock + historique
Mouvements:
GetMouvementsAsync()- Tous les mouvementsGetAjoutsAsync()- Filtre ajoutsGetSuppressionsAsync()- Filtre suppressions
Initialisation:
InitAsync()- Crée les tables et insère données de test
Tous héritent de BaseViewModel qui expose :
IsBusy(bool) - Indicateur d'activitéIsNotBusy(bool) - Propriété calculéeTitle(string)
Commandes RelayCommand :
NavigateToAjouterCommandNavigateToListeCommandNavigateToMajCommandNavigateToMouvementsCommandQuitterCommand
Propriétés observables :
CodeProduitLibelleProduitStockSaisiMessageResultat
Commandes :
AjouterEchantillonCommand- Validation et insertionQuitterCommand
Echantillons(ObservableCollection)ChargerEchantillonsCommandQuitterCommand
Propriétés :
CodeProduitQuantiteSaisieMessageResultat
Commandes :
AjouterStockCommandSupprimerStockCommandQuitterCommand
Propriétés :
Mouvements(ObservableCollection)FiltreActif(string)
Commandes :
ChargerMouvementsCommandFiltrerAjoutsCommandFiltrerSuppressionsCommandAfficherTousCommandQuitterCommand
Support de QueryProperty pour le filtre via URL
PrimaryColor = #1a1a2e (bleu nuit)
SecondaryColor = #16213e (bleu profond)
AccentColor = #0f3460 (bleu moyen)
HighlightColor = #e94560 (rose/rouge GSB)
TextPrimary = #ffffff
TextSecondary = #a8b2d8
SuccessColor = #4caf50 (vert)
DangerColor = #f44336 (rouge)
- Boutons arrondis (CornerRadius=8)
- Fond sombre (#1a1a2e)
- CollectionView pour listes scrollables
- ActivityIndicator pour opérations async
<PackageReference Include="sqlite-net-pcl" Version="1.9.172"/>
<PackageReference Include="SQLitePCLRaw.provider.dynamic_cdecl" Version="2.1.6"/>
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.2.2"/>
<PackageReference Include="CommunityToolkit.Maui" Version="7.0.1"/>5 boutons de navigation :
- Ajouter un nouvel échantillon
- Liste des échantillons
- Maj d'un échantillon
- Liste des ajouts
- Liste des suppressions
- Saisie : Code, Libellé, Stock initial
- Validation : champs non vides, unicité du code, format numérique
- Message de confirmation avec les données saisies
- CollectionView avec affichage Code, Libellé, Stock, StockMini
- Fond gris foncé (#16213e)
- Rechargement au OnAppearing()
- Recherche par code
- Deux boutons : Ajouter / Supprimer quantité
- Validation : stock ne peut pas être négatif
- Enregistrement automatique dans MajStock
- 3 boutons filtre : Tous / Ajouts / Suppressions
- Affichage : Code, Quantité, Mouvement (coloré), Date
- Tri par date décroissante
- Support QueryProperty pour pré-charger un filtre
Routes enregistrées dans AppShell.xaml.cs :
Routing.RegisterRoute(nameof(AjoutEchantillonPage), typeof(AjoutEchantillonPage));
Routing.RegisterRoute(nameof(ListeEchantillonsPage), typeof(ListeEchantillonsPage));
Routing.RegisterRoute(nameof(MajEchantillonPage), typeof(MajEchantillonPage));
Routing.RegisterRoute(nameof(ListeMouvementsPage), typeof(ListeMouvementsPage));Appels de navigation :
await Shell.Current.GoToAsync("AjoutEchantillonPage");
await Shell.Current.GoToAsync("ListeMouvementsPage?filtre=ajouts");- Enregistrement du DatabaseService comme singleton
- Enregistrement de toutes les Pages et ViewModels en transient
- Appel à InitAsync() pour créer les tables et données de test
- Configuration CommunityToolkit.Maui
- FlyoutBehavior="Disabled" (pas de menu latéral)
- ShellContent point vers MainPage
Automatiquement insérées au démarrage si la table est vide :
A0001 - Acai Bio - Stock: 10, Mini: 3
A0002 - Aloe Vera - Stock: 5, Mini: 2
B0001 - Baobab Poudre - Stock: 7, Mini: 2
B0002 - Bacopa Monnieri - Stock: 6, Mini: 2
M0001 - Moringa Bio - Stock: 12, Mini: 4
dotnet build -c Release -f net10.0-androiddotnet publish -c Release -f net10.0-android -p:AndroidPackageFormat=apkdotnet publish -c Release -f net10.0-android -p:AndroidPackageFormat=aab- APK :
bin/Release/net10.0-android/com.companyname.androidgsb.apk - AAB :
bin/Release/net10.0-android/com.companyname.androidgsb.aab
- Permissions Android : L'accès aux fichiers est géré automatiquement par FileSystem.AppDataDirectory
- BD SQLite : Stockée dans
/data/data/com.companyname.androidgsb/files/gsb_stock.db3 - Async/Await : Toutes les opérations BD sont asynchrones
- Gestion erreurs : Try/catch avec messages utilisateur appropriés
- Validation métier :
- Code unique pour chaque produit
- Stock ne peut pas être négatif
- Quantités doivent être positives
Tous les Debug.WriteLine() sortent dans la fenêtre de débogage de Rider
Utiliser "DB Browser for SQLite" ou le plugin "Database Navigator" de Rider
Configuration des Run dans Rider : Run > Edit Configurations > Sélectionner AVD
- Modèles de données (Echantillon, MajStock)
- Service de base de données avec CRUD complet
- ViewModels avec RelayCommands
- Pages XAML avec data binding
- Navigation Shell
- Validation métier
- Données de test
- Design thème GSB sombre
- Support async/await
- Gestion erreurs
- Historique mouvements avec filtres
- Convertisseur de couleurs personnalisé
Version : 1.0
Date : Mars 2026
Auteur : GitHub Copilot
Cible : SIO 2ème année SLAM - BLOC2 GSB