From 4df3b2a2865bd02b8494bd67a72e380b4202f515 Mon Sep 17 00:00:00 2001 From: Valentin CZERYBA Date: Sun, 23 Jun 2024 17:23:26 +0200 Subject: [PATCH 1/9] list functionnal test --- covas_mobile/lib/ListItemMenu.dart | 95 ++++++++++++++++++++++++++++++ covas_mobile/lib/classes/post.dart | 17 ++++++ covas_mobile/lib/main.dart | 11 ++-- 3 files changed, 116 insertions(+), 7 deletions(-) create mode 100644 covas_mobile/lib/ListItemMenu.dart create mode 100644 covas_mobile/lib/classes/post.dart diff --git a/covas_mobile/lib/ListItemMenu.dart b/covas_mobile/lib/ListItemMenu.dart new file mode 100644 index 0000000..ac1e420 --- /dev/null +++ b/covas_mobile/lib/ListItemMenu.dart @@ -0,0 +1,95 @@ +import 'dart:convert'; +import 'package:http/http.dart' as http; +import 'package:flutter/material.dart'; +import 'classes/post.dart'; + +// app starting point +void main() { + runApp(const MyApp()); +} + +class MyApp extends StatelessWidget { + const MyApp({super.key}); + + @override + Widget build(BuildContext context) { + return MaterialApp( + home: const ListItemMenu(), + debugShowCheckedModeBanner: false, + ); + } +} + +// homepage class +class ListItemMenu extends StatefulWidget { + const ListItemMenu({super.key}); + + @override + State createState() => _MyHomePageState(); +} + +// homepage state +class _MyHomePageState extends State { + // variable to call and store future list of posts + Future> postsFuture = getPosts(); + + // function to fetch data from api and return future list of posts + static Future> getPosts() async { + var url = Uri.parse("https://jsonplaceholder.typicode.com/albums/1/photos"); + final response = + await http.get(url, headers: {"Content-Type": "application/json"}); + final List body = json.decode(response.body); + return body.map((e) => Post.fromJson(e)).toList(); + } + + // build function + @override + Widget build(BuildContext context) { + return Scaffold( + body: Center( + // FutureBuilder + child: FutureBuilder>( + future: postsFuture, + builder: (context, snapshot) { + if (snapshot.connectionState == ConnectionState.waiting) { + // until data is fetched, show loader + return const CircularProgressIndicator(); + } else if (snapshot.hasData) { + // once data is fetched, display it on screen (call buildPosts()) + final posts = snapshot.data!; + return buildPosts(posts); + } else { + // if no data, show simple Text + return const Text("No data available"); + } + }, + ), + ), + ); + } + + // function to display fetched data on screen + Widget buildPosts(List posts) { + // ListView Builder to show data in a list + return ListView.builder( + itemCount: posts.length, + itemBuilder: (context, index) { + final post = posts[index]; + return Container( + color: Colors.grey.shade300, + margin: EdgeInsets.symmetric(vertical: 5, horizontal: 10), + padding: EdgeInsets.symmetric(vertical: 5, horizontal: 5), + height: 100, + width: double.maxFinite, + child: Row( + children: [ + Expanded(flex: 1, child: Image.network(post.url!)), + SizedBox(width: 10), + Expanded(flex: 3, child: Text(post.title!)), + ], + ), + ); + }, + ); + } +} diff --git a/covas_mobile/lib/classes/post.dart b/covas_mobile/lib/classes/post.dart new file mode 100644 index 0000000..69c1727 --- /dev/null +++ b/covas_mobile/lib/classes/post.dart @@ -0,0 +1,17 @@ +class Post { + int? albumId; + int? id; + String? title; + String? url; + String? thumbnailUrl; + + Post({this.albumId, this.id, this.title, this.url, this.thumbnailUrl}); + + Post.fromJson(Map json) { + albumId = json['albumId']; + id = json['id']; + title = json['title']; + url = json['url']; + thumbnailUrl = json['thumbnailUrl']; + } +} diff --git a/covas_mobile/lib/main.dart b/covas_mobile/lib/main.dart index 63d637f..0f7e5f8 100644 --- a/covas_mobile/lib/main.dart +++ b/covas_mobile/lib/main.dart @@ -5,7 +5,8 @@ import 'package:http/http.dart' as http; import 'dart:convert'; import 'dart:io'; -import 'MyHomePage.dart'; +//import 'MyHomePage.dart'; +import 'ListItemMenu.dart'; import 'classes/alert.dart'; @@ -74,9 +75,7 @@ class _LoginDemoState extends State with ShowErrorDialog { } } Navigator.push( - context, - MaterialPageRoute( - builder: (_) => MyHomePage(title: 'Flutter Demo'))); + context, MaterialPageRoute(builder: (_) => ListItemMenu())); } else { var text = ""; switch (response.statusCode) { @@ -136,9 +135,7 @@ class _LoginDemoState extends State with ShowErrorDialog { headers: {HttpHeaders.cookieHeader: 'access_token: ${access_token}'}); if (responseToken.statusCode == 200) { Navigator.push( - context, - MaterialPageRoute( - builder: (_) => MyHomePage(title: 'Flutter Demo'))); + context, MaterialPageRoute(builder: (_) => ListItemMenu())); } else { prefs.remove("access_token"); } From bbb1a096971a0f9a7a4869a43a66ba71d2e394c3 Mon Sep 17 00:00:00 2001 From: Valentin CZERYBA Date: Sun, 23 Jun 2024 20:57:54 +0200 Subject: [PATCH 2/9] add share preference item list --- covas_mobile/lib/ListItemMenu.dart | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/covas_mobile/lib/ListItemMenu.dart b/covas_mobile/lib/ListItemMenu.dart index ac1e420..aab66fe 100644 --- a/covas_mobile/lib/ListItemMenu.dart +++ b/covas_mobile/lib/ListItemMenu.dart @@ -2,6 +2,7 @@ import 'dart:convert'; import 'package:http/http.dart' as http; import 'package:flutter/material.dart'; import 'classes/post.dart'; +import 'package:shared_preferences/shared_preferences.dart'; // app starting point void main() { @@ -35,11 +36,18 @@ class _MyHomePageState extends State { // function to fetch data from api and return future list of posts static Future> getPosts() async { - var url = Uri.parse("https://jsonplaceholder.typicode.com/albums/1/photos"); - final response = - await http.get(url, headers: {"Content-Type": "application/json"}); - final List body = json.decode(response.body); - return body.map((e) => Post.fromJson(e)).toList(); + SharedPreferences prefs = await SharedPreferences.getInstance(); + var accessToken = prefs.getString("access_token") ?? ""; + final List body = []; + if (accessToken.isNotEmpty) { + var url = + Uri.parse("https://jsonplaceholder.typicode.com/albums/1/photos"); + final response = + await http.get(url, headers: {"Content-Type": "application/json"}); + final List body = json.decode(response.body); + return body.map((e) => Post.fromJson(e)).toList(); + } + return body; } // build function @@ -84,7 +92,6 @@ class _MyHomePageState extends State { child: Row( children: [ Expanded(flex: 1, child: Image.network(post.url!)), - SizedBox(width: 10), Expanded(flex: 3, child: Text(post.title!)), ], ), From 2120e24a79535f014c3720769e52bacb2e58f917 Mon Sep 17 00:00:00 2001 From: Valentin CZERYBA Date: Sun, 23 Jun 2024 21:02:56 +0200 Subject: [PATCH 3/9] rollback sizedbox --- covas_mobile/lib/ListItemMenu.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/covas_mobile/lib/ListItemMenu.dart b/covas_mobile/lib/ListItemMenu.dart index aab66fe..4946182 100644 --- a/covas_mobile/lib/ListItemMenu.dart +++ b/covas_mobile/lib/ListItemMenu.dart @@ -92,6 +92,7 @@ class _MyHomePageState extends State { child: Row( children: [ Expanded(flex: 1, child: Image.network(post.url!)), + SizedBox(width: 10), Expanded(flex: 3, child: Text(post.title!)), ], ), From cf29b1d364a201229045c7ed5d7acd34f619702c Mon Sep 17 00:00:00 2001 From: Valentin CZERYBA Date: Mon, 24 Jun 2024 23:57:43 +0200 Subject: [PATCH 4/9] handle events api --- covas_mobile/lib/ListItemMenu.dart | 41 +++++++++++++++++----------- covas_mobile/lib/classes/events.dart | 13 +++++++++ 2 files changed, 38 insertions(+), 16 deletions(-) create mode 100644 covas_mobile/lib/classes/events.dart diff --git a/covas_mobile/lib/ListItemMenu.dart b/covas_mobile/lib/ListItemMenu.dart index 4946182..ee83305 100644 --- a/covas_mobile/lib/ListItemMenu.dart +++ b/covas_mobile/lib/ListItemMenu.dart @@ -1,9 +1,12 @@ import 'dart:convert'; +import 'dart:io'; import 'package:http/http.dart' as http; import 'package:flutter/material.dart'; -import 'classes/post.dart'; +import 'classes/events.dart'; import 'package:shared_preferences/shared_preferences.dart'; +import 'variable/globals.dart' as globals; + // app starting point void main() { runApp(const MyApp()); @@ -32,20 +35,21 @@ class ListItemMenu extends StatefulWidget { // homepage state class _MyHomePageState extends State { // variable to call and store future list of posts - Future> postsFuture = getPosts(); + Future> postsFuture = getPosts(); // function to fetch data from api and return future list of posts - static Future> getPosts() async { + static Future> getPosts() async { SharedPreferences prefs = await SharedPreferences.getInstance(); var accessToken = prefs.getString("access_token") ?? ""; - final List body = []; + final List body = []; if (accessToken.isNotEmpty) { - var url = - Uri.parse("https://jsonplaceholder.typicode.com/albums/1/photos"); - final response = - await http.get(url, headers: {"Content-Type": "application/json"}); - final List body = json.decode(response.body); - return body.map((e) => Post.fromJson(e)).toList(); + var url = Uri.parse("http://${globals.api}/events"); + final response = await http.get(url, headers: { + "Content-Type": "application/json", + HttpHeaders.cookieHeader: "access_token=${accessToken}" + }); + final List body = json.decode(utf8.decode(response.bodyBytes)); + return body.map((e) => Events.fromJson(e)).toList(); } return body; } @@ -56,7 +60,7 @@ class _MyHomePageState extends State { return Scaffold( body: Center( // FutureBuilder - child: FutureBuilder>( + child: FutureBuilder>( future: postsFuture, builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.waiting) { @@ -77,7 +81,7 @@ class _MyHomePageState extends State { } // function to display fetched data on screen - Widget buildPosts(List posts) { + Widget buildPosts(List posts) { // ListView Builder to show data in a list return ListView.builder( itemCount: posts.length, @@ -85,15 +89,20 @@ class _MyHomePageState extends State { final post = posts[index]; return Container( color: Colors.grey.shade300, - margin: EdgeInsets.symmetric(vertical: 5, horizontal: 10), + margin: EdgeInsets.symmetric(vertical: 5, horizontal: 5), padding: EdgeInsets.symmetric(vertical: 5, horizontal: 5), height: 100, width: double.maxFinite, child: Row( children: [ - Expanded(flex: 1, child: Image.network(post.url!)), - SizedBox(width: 10), - Expanded(flex: 3, child: Text(post.title!)), + Text( + '${post.name!}\n\n', + style: Theme.of(context).textTheme.titleMedium, + ), + Text( + '${post.place!}', + style: Theme.of(context).textTheme.titleSmall, + ), ], ), ); diff --git a/covas_mobile/lib/classes/events.dart b/covas_mobile/lib/classes/events.dart new file mode 100644 index 0000000..f40e1b9 --- /dev/null +++ b/covas_mobile/lib/classes/events.dart @@ -0,0 +1,13 @@ +class Events { + String? id; + String? name; + String? place; + + Events({this.place, this.id, this.name}); + + Events.fromJson(Map json) { + id = json['id']; + name = json['name']; + place = json['place']; + } +} From 10b8448917659f932b19c924947bf6c3679fd764 Mon Sep 17 00:00:00 2001 From: Valentin CZERYBA Date: Wed, 26 Jun 2024 21:46:51 +0200 Subject: [PATCH 5/9] listTile ok --- covas_mobile/lib/ListItemMenu.dart | 21 ++------------------- 1 file changed, 2 insertions(+), 19 deletions(-) diff --git a/covas_mobile/lib/ListItemMenu.dart b/covas_mobile/lib/ListItemMenu.dart index ee83305..7f371ac 100644 --- a/covas_mobile/lib/ListItemMenu.dart +++ b/covas_mobile/lib/ListItemMenu.dart @@ -87,25 +87,8 @@ class _MyHomePageState extends State { itemCount: posts.length, itemBuilder: (context, index) { final post = posts[index]; - return Container( - color: Colors.grey.shade300, - margin: EdgeInsets.symmetric(vertical: 5, horizontal: 5), - padding: EdgeInsets.symmetric(vertical: 5, horizontal: 5), - height: 100, - width: double.maxFinite, - child: Row( - children: [ - Text( - '${post.name!}\n\n', - style: Theme.of(context).textTheme.titleMedium, - ), - Text( - '${post.place!}', - style: Theme.of(context).textTheme.titleSmall, - ), - ], - ), - ); + return ListTile( + title: Text('${post.name!}'), subtitle: Text('${post.place!}')); }, ); } From 0c47c943f9d6033b658c40b424f6aaabf6ae8fd8 Mon Sep 17 00:00:00 2001 From: Valentin CZERYBA Date: Wed, 26 Jun 2024 22:08:00 +0200 Subject: [PATCH 6/9] add separator --- covas_mobile/lib/ListItemMenu.dart | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/covas_mobile/lib/ListItemMenu.dart b/covas_mobile/lib/ListItemMenu.dart index 7f371ac..0ab0041 100644 --- a/covas_mobile/lib/ListItemMenu.dart +++ b/covas_mobile/lib/ListItemMenu.dart @@ -83,13 +83,16 @@ class _MyHomePageState extends State { // function to display fetched data on screen Widget buildPosts(List posts) { // ListView Builder to show data in a list - return ListView.builder( + return ListView.separated( itemCount: posts.length, itemBuilder: (context, index) { final post = posts[index]; return ListTile( title: Text('${post.name!}'), subtitle: Text('${post.place!}')); }, + separatorBuilder: (context, index) { + return Divider(); + }, ); } } From 4804c8bc01b5e71a0c3d08accd50c8ad973f51a3 Mon Sep 17 00:00:00 2001 From: Valentin CZERYBA Date: Wed, 26 Jun 2024 22:32:27 +0200 Subject: [PATCH 7/9] title app --- covas_mobile/lib/ListItemMenu.dart | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/covas_mobile/lib/ListItemMenu.dart b/covas_mobile/lib/ListItemMenu.dart index 0ab0041..2ceded1 100644 --- a/covas_mobile/lib/ListItemMenu.dart +++ b/covas_mobile/lib/ListItemMenu.dart @@ -83,16 +83,22 @@ class _MyHomePageState extends State { // function to display fetched data on screen Widget buildPosts(List posts) { // ListView Builder to show data in a list - return ListView.separated( - itemCount: posts.length, - itemBuilder: (context, index) { - final post = posts[index]; - return ListTile( - title: Text('${post.name!}'), subtitle: Text('${post.place!}')); - }, - separatorBuilder: (context, index) { - return Divider(); - }, - ); + return Scaffold( + appBar: AppBar( + // Here we take the value from the MyHomePage object that was created by + // the App.build method, and use it to set our appbar title. + title: Text("Item list menu"), + ), + body: ListView.separated( + itemCount: posts.length, + itemBuilder: (context, index) { + final post = posts[index]; + return ListTile( + title: Text('${post.name!}'), subtitle: Text('${post.place!}')); + }, + separatorBuilder: (context, index) { + return Divider(); + }, + )); } } From 581512a6da81557a93775c3d3aceaf301fcdcdc0 Mon Sep 17 00:00:00 2001 From: Valentin CZERYBA Date: Wed, 26 Jun 2024 23:10:16 +0200 Subject: [PATCH 8/9] add colors menu --- covas_mobile/lib/ListItemMenu.dart | 41 ++++++++++++++++++------------ covas_mobile/lib/main.dart | 2 ++ 2 files changed, 27 insertions(+), 16 deletions(-) diff --git a/covas_mobile/lib/ListItemMenu.dart b/covas_mobile/lib/ListItemMenu.dart index 2ceded1..834c92c 100644 --- a/covas_mobile/lib/ListItemMenu.dart +++ b/covas_mobile/lib/ListItemMenu.dart @@ -84,21 +84,30 @@ class _MyHomePageState extends State { Widget buildPosts(List posts) { // ListView Builder to show data in a list return Scaffold( - appBar: AppBar( - // Here we take the value from the MyHomePage object that was created by - // the App.build method, and use it to set our appbar title. - title: Text("Item list menu"), - ), - body: ListView.separated( - itemCount: posts.length, - itemBuilder: (context, index) { - final post = posts[index]; - return ListTile( - title: Text('${post.name!}'), subtitle: Text('${post.place!}')); - }, - separatorBuilder: (context, index) { - return Divider(); - }, - )); + appBar: AppBar( + // Here we take the value from the MyHomePage object that was created by + // the App.build method, and use it to set our appbar title. + title: Text("Item list menu"), + backgroundColor: Colors.blue, + foregroundColor: Colors.white, + ), + body: ListView.separated( + itemCount: posts.length, + itemBuilder: (context, index) { + final post = posts[index]; + return ListTile( + title: Text('${post.name!}'), subtitle: Text('${post.place!}')); + }, + separatorBuilder: (context, index) { + return Divider(); + }, + ), + floatingActionButton: FloatingActionButton( + onPressed: () {}, + backgroundColor: Colors.blue, + tooltip: 'Recherche', + child: const Icon(Icons.search, color: Colors.white), + ), + ); } } diff --git a/covas_mobile/lib/main.dart b/covas_mobile/lib/main.dart index 0f7e5f8..817a956 100644 --- a/covas_mobile/lib/main.dart +++ b/covas_mobile/lib/main.dart @@ -154,6 +154,8 @@ class _LoginDemoState extends State with ShowErrorDialog { backgroundColor: Colors.white, appBar: AppBar( title: Text("Login Page"), + backgroundColor: Colors.blue, + foregroundColor: Colors.white, ), body: SingleChildScrollView( child: Column( From aaf13023276fec3ae33155b9a14e6d1572cc9282 Mon Sep 17 00:00:00 2001 From: Valentin CZERYBA Date: Thu, 27 Jun 2024 00:01:07 +0200 Subject: [PATCH 9/9] date format --- covas_mobile/lib/ListItemMenu.dart | 11 +++++++++-- covas_mobile/lib/classes/events.dart | 4 +++- covas_mobile/lib/classes/post.dart | 17 ----------------- covas_mobile/pubspec.lock | 8 ++++++++ covas_mobile/pubspec.yaml | 1 + 5 files changed, 21 insertions(+), 20 deletions(-) delete mode 100644 covas_mobile/lib/classes/post.dart diff --git a/covas_mobile/lib/ListItemMenu.dart b/covas_mobile/lib/ListItemMenu.dart index 834c92c..eea0e64 100644 --- a/covas_mobile/lib/ListItemMenu.dart +++ b/covas_mobile/lib/ListItemMenu.dart @@ -4,12 +4,14 @@ import 'package:http/http.dart' as http; import 'package:flutter/material.dart'; import 'classes/events.dart'; import 'package:shared_preferences/shared_preferences.dart'; +import 'package:intl/intl.dart'; +import 'package:intl/date_symbol_data_local.dart'; import 'variable/globals.dart' as globals; // app starting point void main() { - runApp(const MyApp()); + initializeDateFormatting("fr_FR", null).then((_) => (const MyApp())); } class MyApp extends StatelessWidget { @@ -95,8 +97,13 @@ class _MyHomePageState extends State { itemCount: posts.length, itemBuilder: (context, index) { final post = posts[index]; + final startDate = DateTime.parse(post.startDate!); + final date = DateFormat.yMd().format(startDate); + final time = DateFormat.Hm().format(startDate); + return ListTile( - title: Text('${post.name!}'), subtitle: Text('${post.place!}')); + title: Text('${post.name!}'), + subtitle: Text('${post.place!}\n${date} ${time}')); }, separatorBuilder: (context, index) { return Divider(); diff --git a/covas_mobile/lib/classes/events.dart b/covas_mobile/lib/classes/events.dart index f40e1b9..c1cb070 100644 --- a/covas_mobile/lib/classes/events.dart +++ b/covas_mobile/lib/classes/events.dart @@ -2,12 +2,14 @@ class Events { String? id; String? name; String? place; + String? startDate; - Events({this.place, this.id, this.name}); + Events({this.place, this.id, this.name, this.startDate}); Events.fromJson(Map json) { id = json['id']; name = json['name']; place = json['place']; + startDate = json["start_date"]; } } diff --git a/covas_mobile/lib/classes/post.dart b/covas_mobile/lib/classes/post.dart deleted file mode 100644 index 69c1727..0000000 --- a/covas_mobile/lib/classes/post.dart +++ /dev/null @@ -1,17 +0,0 @@ -class Post { - int? albumId; - int? id; - String? title; - String? url; - String? thumbnailUrl; - - Post({this.albumId, this.id, this.title, this.url, this.thumbnailUrl}); - - Post.fromJson(Map json) { - albumId = json['albumId']; - id = json['id']; - title = json['title']; - url = json['url']; - thumbnailUrl = json['thumbnailUrl']; - } -} diff --git a/covas_mobile/pubspec.lock b/covas_mobile/pubspec.lock index 2cbf4e6..b873bf1 100644 --- a/covas_mobile/pubspec.lock +++ b/covas_mobile/pubspec.lock @@ -112,6 +112,14 @@ packages: url: "https://pub.dev" source: hosted version: "4.0.2" + intl: + dependency: "direct main" + description: + name: intl + sha256: d6f56758b7d3014a48af9701c085700aac781a92a87a62b1333b46d8879661cf + url: "https://pub.dev" + source: hosted + version: "0.19.0" leak_tracker: dependency: transitive description: diff --git a/covas_mobile/pubspec.yaml b/covas_mobile/pubspec.yaml index c1cb06c..1356f4a 100644 --- a/covas_mobile/pubspec.yaml +++ b/covas_mobile/pubspec.yaml @@ -36,6 +36,7 @@ dependencies: cupertino_icons: ^1.0.2 http: ^1.2.1 shared_preferences: ^2.2.3 + intl: ^0.19.0 dev_dependencies: flutter_test: