diff --git a/TP1/container/lib/main.dart b/TP1/container/lib/main.dart index 5b87520..91a4ce0 100644 --- a/TP1/container/lib/main.dart +++ b/TP1/container/lib/main.dart @@ -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 + ), + ], + ), + ), + ), + ), + ); + } } \ No newline at end of file diff --git a/my_travel/assets/images/activities/chaumont.jpg b/my_travel/assets/images/activities/chaumont.jpg new file mode 100644 index 0000000..e62751d Binary files /dev/null and b/my_travel/assets/images/activities/chaumont.jpg differ diff --git a/my_travel/assets/images/activities/dame.jpg b/my_travel/assets/images/activities/dame.jpg new file mode 100644 index 0000000..c759199 Binary files /dev/null and b/my_travel/assets/images/activities/dame.jpg differ diff --git a/my_travel/assets/images/activities/defense.jpg b/my_travel/assets/images/activities/defense.jpg new file mode 100644 index 0000000..4274f26 Binary files /dev/null and b/my_travel/assets/images/activities/defense.jpg differ diff --git a/my_travel/assets/images/activities/louvre.jpg b/my_travel/assets/images/activities/louvre.jpg new file mode 100644 index 0000000..9a16cdb Binary files /dev/null and b/my_travel/assets/images/activities/louvre.jpg differ diff --git a/my_travel/assets/images/lyon.jpg b/my_travel/assets/images/lyon.jpg new file mode 100644 index 0000000..1bc7c9b Binary files /dev/null and b/my_travel/assets/images/lyon.jpg differ diff --git a/my_travel/assets/images/nice.jpg b/my_travel/assets/images/nice.jpg new file mode 100644 index 0000000..544e61d Binary files /dev/null and b/my_travel/assets/images/nice.jpg differ diff --git a/my_travel/assets/images/paris.jpg b/my_travel/assets/images/paris.jpg new file mode 100644 index 0000000..203b277 Binary files /dev/null and b/my_travel/assets/images/paris.jpg differ diff --git a/my_travel/lib/data/data.dart b/my_travel/lib/data/data.dart new file mode 100644 index 0000000..1579001 --- /dev/null +++ b/my_travel/lib/data/data.dart @@ -0,0 +1,29 @@ +// lib/data/data.dart +import '../models/activity.model.dart'; + +List 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', + ), +]; diff --git a/my_travel/lib/main.dart b/my_travel/lib/main.dart index c935dbc..1492f66 100644 --- a/my_travel/lib/main.dart +++ b/my_travel/lib/main.dart @@ -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 [Icon(Icons.more_vert)], - ), - body: const Text('DrEvaristen'), - ), + home: City(), // affichage direct pour développement ); } -} \ No newline at end of file +} diff --git a/my_travel/lib/models/activity.model.dart b/my_travel/lib/models/activity.model.dart new file mode 100644 index 0000000..379e538 --- /dev/null +++ b/my_travel/lib/models/activity.model.dart @@ -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, + }); +} diff --git a/my_travel/lib/views/city/city.dart b/my_travel/lib/views/city/city.dart new file mode 100644 index 0000000..28d43ef --- /dev/null +++ b/my_travel/lib/views/city/city.dart @@ -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 activities = data.activities; + City({super.key}); + @override + State createState() => _CityState(); +} + +class _CityState extends State { + @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(), + ), + ), + ); + } +} diff --git a/my_travel/lib/views/home/home.dart b/my_travel/lib/views/home/home.dart new file mode 100644 index 0000000..15229fa --- /dev/null +++ b/my_travel/lib/views/home/home.dart @@ -0,0 +1,53 @@ +import 'package:flutter/material.dart'; +import '../widgets/city_card.dart'; + +class Home extends StatefulWidget { + const Home({super.key}); + + @override + State createState() => _HomeState(); +} + +class _HomeState extends State { + // Liste "source de vérité" affichée dans l'UI + final List> 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 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 + ), + ], + ), + ), + ); + } +} diff --git a/my_travel/lib/views/widgets/activity_card.dart b/my_travel/lib/views/widgets/activity_card.dart new file mode 100644 index 0000000..ac841c2 --- /dev/null +++ b/my_travel/lib/views/widgets/activity_card.dart @@ -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, + ), + ); + } +} diff --git a/my_travel/lib/views/widgets/city_card.dart b/my_travel/lib/views/widgets/city_card.dart new file mode 100644 index 0000000..511ec82 --- /dev/null +++ b/my_travel/lib/views/widgets/city_card.dart @@ -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, + ), + ), + ], + ), + ], + ), + ), + ], + ), + ), + ); + } +} diff --git a/my_travel/pubspec.yaml b/my_travel/pubspec.yaml index 074128d..072637f 100644 --- a/my_travel/pubspec.yaml +++ b/my_travel/pubspec.yaml @@ -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