projet debut
| @@ -1,12 +1,31 @@ | ||||
| import 'package:flutter/material.dart'; | ||||
|  | ||||
| void main() { | ||||
|   runApp( | ||||
|     Container( | ||||
|       color: Colors.red, | ||||
|       alignment: Alignment.center, | ||||
|       margin: const EdgeInsets.all(100), | ||||
|       child: const Text("Hello world", textDirection: TextDirection.ltr), | ||||
| class CardWithImage extends StatelessWidget { | ||||
|   const CardWithImage({super.key}); | ||||
|   @override | ||||
|   Widget build(BuildContext context) { | ||||
|     return Scaffold( | ||||
|       appBar: AppBar(title: const Text('Card + Image de fond')), | ||||
|       body: Padding( | ||||
|         padding: const EdgeInsets.all(10), | ||||
|         child: Card( | ||||
|           elevation: 5, | ||||
|           clipBehavior: Clip.antiAlias, | ||||
|           child: SizedBox( | ||||
|             height: 150, | ||||
|             child: Stack( | ||||
|               fit: StackFit.expand, // l'enfant occupe toute la carte | ||||
|               children: [ | ||||
|                 // Image locale déclarée dans pubspec.yaml | ||||
|                 Image.asset( | ||||
|                   'assets/images/paris.jpg', | ||||
|                   fit: BoxFit.cover, // couvre toute la surface, quitte à rogner | ||||
|                 ), | ||||
|               ], | ||||
|             ), | ||||
|           ), | ||||
|         ), | ||||
|       ), | ||||
|     ); | ||||
|   } | ||||
| } | ||||
							
								
								
									
										
											BIN
										
									
								
								my_travel/assets/images/activities/chaumont.jpg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 7.7 KiB | 
							
								
								
									
										
											BIN
										
									
								
								my_travel/assets/images/activities/dame.jpg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 11 KiB | 
							
								
								
									
										
											BIN
										
									
								
								my_travel/assets/images/activities/defense.jpg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 11 KiB | 
							
								
								
									
										
											BIN
										
									
								
								my_travel/assets/images/activities/louvre.jpg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 5.8 KiB | 
							
								
								
									
										
											BIN
										
									
								
								my_travel/assets/images/lyon.jpg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 8.0 KiB | 
							
								
								
									
										
											BIN
										
									
								
								my_travel/assets/images/nice.jpg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 90 KiB | 
							
								
								
									
										
											BIN
										
									
								
								my_travel/assets/images/paris.jpg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 44 KiB | 
							
								
								
									
										29
									
								
								my_travel/lib/data/data.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,29 @@ | ||||
| // lib/data/data.dart | ||||
| import '../models/activity.model.dart'; | ||||
|  | ||||
| List<Activity> activities = [ | ||||
|   Activity( | ||||
|     image: 'assets/images/activities/louvre.jpg', | ||||
|     name: 'Le Louvre', | ||||
|     id: 'a1', | ||||
|     city: 'Paris', | ||||
|   ), | ||||
|   Activity( | ||||
|     image: 'assets/images/activities/chaumont.jpg', | ||||
|     name: 'Les buttes Chaumont', | ||||
|     id: 'a2', | ||||
|     city: 'Paris', | ||||
|   ), | ||||
|   Activity( | ||||
|     image: 'assets/images/activities/dame.jpg', | ||||
|     name: 'Notre Dame', | ||||
|     id: 'a3', | ||||
|     city: 'Paris', | ||||
|   ), | ||||
|   Activity( | ||||
|     image: 'assets/images/activities/defense.jpg', | ||||
|     name: 'La Défense', | ||||
|     id: 'a4', | ||||
|     city: 'Paris', | ||||
|   ), | ||||
| ]; | ||||
| @@ -1,22 +1,15 @@ | ||||
| import 'package:flutter/material.dart'; | ||||
| import 'views/city/city.dart'; | ||||
|  | ||||
| void main() => runApp(const DrEvaristenTrip()); | ||||
|  | ||||
| class DrEvaristenTrip extends StatelessWidget { | ||||
|  | ||||
|   const DrEvaristenTrip({super.key}); | ||||
|   @override | ||||
|   Widget build(BuildContext context) { | ||||
|     return MaterialApp( | ||||
|       debugShowCheckedModeBanner: false, | ||||
|       home: Scaffold( | ||||
|         appBar: AppBar( | ||||
|           leading: const Icon(Icons.home), | ||||
|           title: const Text('DrEvaristen Trip'), | ||||
|           actions: const <Widget>[Icon(Icons.more_vert)], | ||||
|         ), | ||||
|       body: const Text('DrEvaristen'), | ||||
|       ), | ||||
|       home: City(), // affichage direct pour développement | ||||
|     ); | ||||
|   } | ||||
| } | ||||
							
								
								
									
										13
									
								
								my_travel/lib/models/activity.model.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,13 @@ | ||||
| // lib/models/activity.model.dart | ||||
| class Activity { | ||||
|   String name; | ||||
|   String image; | ||||
|   String? id; | ||||
|   String city; | ||||
|   Activity({ | ||||
|     required this.name, | ||||
|     required this.city, | ||||
|     this.id, | ||||
|     required this.image, | ||||
|   }); | ||||
| } | ||||
							
								
								
									
										37
									
								
								my_travel/lib/views/city/city.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,37 @@ | ||||
| import 'package:flutter/material.dart'; | ||||
| import '../../data/data.dart' as data; | ||||
| import '../../models/activity.model.dart'; | ||||
| import '../widgets/activity_card.dart'; | ||||
|  | ||||
| class City extends StatefulWidget { | ||||
|   final List<Activity> activities = data.activities; | ||||
|   City({super.key}); | ||||
|   @override | ||||
|   State<City> createState() => _CityState(); | ||||
| } | ||||
|  | ||||
| class _CityState extends State<City> { | ||||
|   @override | ||||
|   Widget build(BuildContext context) { | ||||
|     return Scaffold( | ||||
|       appBar: AppBar( | ||||
|         leading: const Icon(Icons.chevron_left), | ||||
|         title: const Text('Paris'), | ||||
|         actions: const [Icon(Icons.more_vert)], | ||||
|       ), | ||||
|  | ||||
|       // ==================== GridView.extent (taille max par item) - VERSION ACTIVE ✅ ==================== | ||||
|       body: Container( | ||||
|         padding: const EdgeInsets.all(10), | ||||
|         child: GridView.extent( | ||||
|           maxCrossAxisExtent: 150, // largeur max d'un item | ||||
|           mainAxisSpacing: 2, | ||||
|           crossAxisSpacing: 5, | ||||
|           children: widget.activities | ||||
|               .map((a) => ActivityCard(activity: a)) | ||||
|               .toList(), | ||||
|         ), | ||||
|       ), | ||||
|     ); | ||||
|   } | ||||
| } | ||||
							
								
								
									
										53
									
								
								my_travel/lib/views/home/home.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,53 @@ | ||||
| import 'package:flutter/material.dart'; | ||||
| import '../widgets/city_card.dart'; | ||||
|  | ||||
| class Home extends StatefulWidget { | ||||
|   const Home({super.key}); | ||||
|  | ||||
|   @override | ||||
|   State<Home> createState() => _HomeState(); | ||||
| } | ||||
|  | ||||
| class _HomeState extends State<Home> { | ||||
|   // Liste "source de vérité" affichée dans l'UI | ||||
|   final List<Map<String, dynamic>> cities = [ | ||||
|     {'name': 'Paris', 'image': 'assets/images/paris.jpg', 'checked': false}, | ||||
|     {'name': 'Lyon', 'image': 'assets/images/lyon.jpg', 'checked': false}, | ||||
|     {'name': 'Nice', 'image': 'assets/images/nice.jpg', 'checked': false}, | ||||
|   ]; | ||||
|  | ||||
|   // Fonction pour basculer l'état favori d'une ville | ||||
|   void switchChecked(Map<String, dynamic> city) { | ||||
|     setState(() { | ||||
|       city['checked'] = !(city['checked'] ?? false); | ||||
|     }); | ||||
|   } | ||||
|  | ||||
|   @override | ||||
|   Widget build(BuildContext context) { | ||||
|     return Scaffold( | ||||
|       appBar: AppBar( | ||||
|         leading: const Icon(Icons.home), | ||||
|         title: const Text('DrEvaristen Trip'), | ||||
|         actions: const [Icon(Icons.more_vert)], | ||||
|       ), | ||||
|       body: Container( | ||||
|         padding: const EdgeInsets.all(10), | ||||
|         child: Column( | ||||
|           crossAxisAlignment: CrossAxisAlignment.stretch, | ||||
|           // On transforme chaque map en CityCard | ||||
|           children: [ | ||||
|             for (final city in cities) | ||||
|               CityCard( | ||||
|                 name: city['name'], | ||||
|                 image: city['image'], | ||||
|                 checked: city['checked'] ?? false, | ||||
|                 updateChecked: () => | ||||
|                     switchChecked(city), // capture la bonne ville | ||||
|               ), | ||||
|           ], | ||||
|         ), | ||||
|       ), | ||||
|     ); | ||||
|   } | ||||
| } | ||||
							
								
								
									
										23
									
								
								my_travel/lib/views/widgets/activity_card.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,23 @@ | ||||
| import 'package:flutter/material.dart'; | ||||
| import '../../models/activity.model.dart'; | ||||
|  | ||||
| class ActivityCard extends StatelessWidget { | ||||
|   final Activity activity; | ||||
|   const ActivityCard({super.key, required this.activity}); | ||||
|  | ||||
|   @override | ||||
|   Widget build(BuildContext context) { | ||||
|     return ListTile( | ||||
|       leading: CircleAvatar(backgroundImage: AssetImage(activity.image)), | ||||
|       title: Text(activity.name), | ||||
|       subtitle: Text(activity.city), | ||||
|       trailing: Checkbox( | ||||
|         value: true, | ||||
|         tristate: true, | ||||
|         onChanged: (e) {}, // nécessite un état pour évoluer | ||||
|         activeColor: Colors.black, | ||||
|         checkColor: Colors.red, | ||||
|       ), | ||||
|     ); | ||||
|   } | ||||
| } | ||||
							
								
								
									
										67
									
								
								my_travel/lib/views/widgets/city_card.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,67 @@ | ||||
| import 'package:flutter/material.dart'; | ||||
|  | ||||
| class CityCard extends StatelessWidget { | ||||
|   final String name; | ||||
|   final String image; | ||||
|   final bool checked; // devient requis | ||||
|   final VoidCallback updateChecked; | ||||
|   const CityCard({ | ||||
|     super.key, | ||||
|     required this.name, | ||||
|     required this.image, | ||||
|     required this.checked, | ||||
|     required this.updateChecked, | ||||
|   }); | ||||
|   @override | ||||
|   Widget build(BuildContext context) { | ||||
|     return Card( | ||||
|       elevation: 5, | ||||
|       clipBehavior: Clip.antiAlias, | ||||
|       child: SizedBox( | ||||
|         height: 150, | ||||
|         child: Stack( | ||||
|           fit: StackFit.expand, | ||||
|           children: [ | ||||
|             Ink.image( | ||||
|               image: AssetImage(image), | ||||
|               fit: BoxFit.cover, | ||||
|               child: InkWell(onTap: updateChecked), // notifie le parent | ||||
|             ), | ||||
|             Padding( | ||||
|               padding: const EdgeInsets.all(10), | ||||
|               child: Column( | ||||
|                 children: [ | ||||
|                   // Icône favori : pleine si checked, sinon contour | ||||
|                   Expanded( | ||||
|                     child: Row( | ||||
|                       mainAxisAlignment: MainAxisAlignment.end, | ||||
|                       crossAxisAlignment: CrossAxisAlignment.start, | ||||
|                       children: [ | ||||
|                         Icon( | ||||
|                           checked ? Icons.star : Icons.star_border, | ||||
|                           size: 30, | ||||
|                           color: Colors.white, | ||||
|                         ), | ||||
|                       ], | ||||
|                     ), | ||||
|                   ), | ||||
|                   Row( | ||||
|                     children: [ | ||||
|                       Text( | ||||
|                         name, | ||||
|                         style: const TextStyle( | ||||
|                           fontSize: 30, | ||||
|                           color: Colors.white, | ||||
|                         ), | ||||
|                       ), | ||||
|                     ], | ||||
|                   ), | ||||
|                 ], | ||||
|               ), | ||||
|             ), | ||||
|           ], | ||||
|         ), | ||||
|       ), | ||||
|     ); | ||||
|   } | ||||
| } | ||||
| @@ -58,7 +58,9 @@ flutter: | ||||
|   uses-material-design: true | ||||
|  | ||||
|   # To add assets to your application, add an assets section, like this: | ||||
|   # assets: | ||||
|   assets: | ||||
|     - assets/images/ | ||||
|     - assets/images/activities/ | ||||
|   #   - images/a_dot_burr.jpeg | ||||
|   #   - images/a_dot_ham.jpeg | ||||
|  | ||||
|   | ||||