diff --git a/.idea/.gitignore b/.idea/.gitignore
new file mode 100644
index 0000000..8f00030
--- /dev/null
+++ b/.idea/.gitignore
@@ -0,0 +1,5 @@
+# Default ignored files
+/shelf/
+/workspace.xml
+# GitHub Copilot persisted chat sessions
+/copilot/chatSessions
diff --git a/.idea/3il-student.iml b/.idea/3il-student.iml
new file mode 100644
index 0000000..88725d4
--- /dev/null
+++ b/.idea/3il-student.iml
@@ -0,0 +1,483 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/discord.xml b/.idea/discord.xml
new file mode 100644
index 0000000..d8e9561
--- /dev/null
+++ b/.idea/discord.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Dart_Packages.xml b/.idea/libraries/Dart_Packages.xml
new file mode 100644
index 0000000..b0594fc
--- /dev/null
+++ b/.idea/libraries/Dart_Packages.xml
@@ -0,0 +1,276 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/Dart_SDK.xml b/.idea/libraries/Dart_SDK.xml
new file mode 100644
index 0000000..79bdae7
--- /dev/null
+++ b/.idea/libraries/Dart_SDK.xml
@@ -0,0 +1,29 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
new file mode 100644
index 0000000..6e86672
--- /dev/null
+++ b/.idea/misc.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
new file mode 100644
index 0000000..6ee7f41
--- /dev/null
+++ b/.idea/modules.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..35eb1dd
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.vscode/launch.json b/.vscode/launch.json
new file mode 100644
index 0000000..01ea055
--- /dev/null
+++ b/.vscode/launch.json
@@ -0,0 +1,28 @@
+{
+ // Utilisez IntelliSense pour en savoir plus sur les attributs possibles.
+ // Pointez pour afficher la description des attributs existants.
+ // Pour plus d'informations, visitez : https://go.microsoft.com/fwlink/?linkid=830387
+ "version": "0.2.0",
+ "configurations": [
+ {
+ "name": "app_student",
+ "cwd": "frontend\\app_student",
+ "request": "launch",
+ "type": "dart"
+ },
+ {
+ "name": "app_student (profile mode)",
+ "cwd": "frontend\\app_student",
+ "request": "launch",
+ "type": "dart",
+ "flutterMode": "profile"
+ },
+ {
+ "name": "app_student (release mode)",
+ "cwd": "frontend\\app_student",
+ "request": "launch",
+ "type": "dart",
+ "flutterMode": "release"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/backend/composer.json b/backend/composer.json
index 8410887..cd9945d 100644
--- a/backend/composer.json
+++ b/backend/composer.json
@@ -21,6 +21,7 @@
"symfony/yaml": "6.4.*"
},
"require-dev": {
+ "symfony/debug-bundle": "6.4.*",
"symfony/maker-bundle": "^1.53"
},
"config": {
diff --git a/backend/composer.lock b/backend/composer.lock
index 6678a68..216579f 100644
--- a/backend/composer.lock
+++ b/backend/composer.lock
@@ -4,7 +4,9 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
- "content-hash": "e478085c90ffbf3ef8d4b96ac02a834c",
+
+ "content-hash": "30f9eda7517c76d9b97fe895a2ce5b36",
+
"packages": [
{
"name": "masterminds/html5",
@@ -3023,6 +3025,80 @@
},
"time": "2024-02-21T19:24:10+00:00"
},
+ {
+ "name": "symfony/debug-bundle",
+ "version": "v6.4.3",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/debug-bundle.git",
+ "reference": "425c7760a4e6fdc6cb643c791d32277037c971df"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/debug-bundle/zipball/425c7760a4e6fdc6cb643c791d32277037c971df",
+ "reference": "425c7760a4e6fdc6cb643c791d32277037c971df",
+ "shasum": ""
+ },
+ "require": {
+ "ext-xml": "*",
+ "php": ">=8.1",
+ "symfony/dependency-injection": "^5.4|^6.0|^7.0",
+ "symfony/http-kernel": "^5.4|^6.0|^7.0",
+ "symfony/twig-bridge": "^5.4|^6.0|^7.0",
+ "symfony/var-dumper": "^5.4|^6.0|^7.0"
+ },
+ "conflict": {
+ "symfony/config": "<5.4",
+ "symfony/dependency-injection": "<5.4"
+ },
+ "require-dev": {
+ "symfony/config": "^5.4|^6.0|^7.0",
+ "symfony/web-profiler-bundle": "^5.4|^6.0|^7.0"
+ },
+ "type": "symfony-bundle",
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Bundle\\DebugBundle\\": ""
+ },
+ "exclude-from-classmap": [
+ "/Tests/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Provides a tight integration of the Symfony VarDumper component and the ServerLogCommand from MonologBridge into the Symfony full-stack framework",
+ "homepage": "https://symfony.com",
+ "support": {
+ "source": "https://github.com/symfony/debug-bundle/tree/v6.4.3"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2024-01-23T14:51:35+00:00"
+ },
{
"name": "symfony/maker-bundle",
"version": "v1.56.0",
@@ -3175,6 +3251,265 @@
}
],
"time": "2024-02-20T12:31:00+00:00"
+ },
+ {
+ "name": "symfony/translation-contracts",
+ "version": "v3.4.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/translation-contracts.git",
+ "reference": "06450585bf65e978026bda220cdebca3f867fde7"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/06450585bf65e978026bda220cdebca3f867fde7",
+ "reference": "06450585bf65e978026bda220cdebca3f867fde7",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.1"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "3.4-dev"
+ },
+ "thanks": {
+ "name": "symfony/contracts",
+ "url": "https://github.com/symfony/contracts"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Contracts\\Translation\\": ""
+ },
+ "exclude-from-classmap": [
+ "/Test/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Nicolas Grekas",
+ "email": "p@tchwork.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Generic abstractions related to translation",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "abstractions",
+ "contracts",
+ "decoupling",
+ "interfaces",
+ "interoperability",
+ "standards"
+ ],
+ "support": {
+ "source": "https://github.com/symfony/translation-contracts/tree/v3.4.1"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2023-12-26T14:02:43+00:00"
+ },
+ {
+ "name": "symfony/twig-bridge",
+ "version": "v6.4.4",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/twig-bridge.git",
+ "reference": "256f330026d1c97187b61aa5c29e529499877f13"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/twig-bridge/zipball/256f330026d1c97187b61aa5c29e529499877f13",
+ "reference": "256f330026d1c97187b61aa5c29e529499877f13",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.1",
+ "symfony/deprecation-contracts": "^2.5|^3",
+ "symfony/translation-contracts": "^2.5|^3",
+ "twig/twig": "^2.13|^3.0.4"
+ },
+ "conflict": {
+ "phpdocumentor/reflection-docblock": "<3.2.2",
+ "phpdocumentor/type-resolver": "<1.4.0",
+ "symfony/console": "<5.4",
+ "symfony/form": "<6.3",
+ "symfony/http-foundation": "<5.4",
+ "symfony/http-kernel": "<6.4",
+ "symfony/mime": "<6.2",
+ "symfony/serializer": "<6.4",
+ "symfony/translation": "<5.4",
+ "symfony/workflow": "<5.4"
+ },
+ "require-dev": {
+ "egulias/email-validator": "^2.1.10|^3|^4",
+ "league/html-to-markdown": "^5.0",
+ "phpdocumentor/reflection-docblock": "^3.0|^4.0|^5.0",
+ "symfony/asset": "^5.4|^6.0|^7.0",
+ "symfony/asset-mapper": "^6.3|^7.0",
+ "symfony/console": "^5.4|^6.0|^7.0",
+ "symfony/dependency-injection": "^5.4|^6.0|^7.0",
+ "symfony/expression-language": "^5.4|^6.0|^7.0",
+ "symfony/finder": "^5.4|^6.0|^7.0",
+ "symfony/form": "^6.4|^7.0",
+ "symfony/html-sanitizer": "^6.1|^7.0",
+ "symfony/http-foundation": "^5.4|^6.0|^7.0",
+ "symfony/http-kernel": "^6.4|^7.0",
+ "symfony/intl": "^5.4|^6.0|^7.0",
+ "symfony/mime": "^6.2|^7.0",
+ "symfony/polyfill-intl-icu": "~1.0",
+ "symfony/property-info": "^5.4|^6.0|^7.0",
+ "symfony/routing": "^5.4|^6.0|^7.0",
+ "symfony/security-acl": "^2.8|^3.0",
+ "symfony/security-core": "^5.4|^6.0|^7.0",
+ "symfony/security-csrf": "^5.4|^6.0|^7.0",
+ "symfony/security-http": "^5.4|^6.0|^7.0",
+ "symfony/serializer": "^6.4.3|^7.0.3",
+ "symfony/stopwatch": "^5.4|^6.0|^7.0",
+ "symfony/translation": "^6.1|^7.0",
+ "symfony/web-link": "^5.4|^6.0|^7.0",
+ "symfony/workflow": "^5.4|^6.0|^7.0",
+ "symfony/yaml": "^5.4|^6.0|^7.0",
+ "twig/cssinliner-extra": "^2.12|^3",
+ "twig/inky-extra": "^2.12|^3",
+ "twig/markdown-extra": "^2.12|^3"
+ },
+ "type": "symfony-bridge",
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Bridge\\Twig\\": ""
+ },
+ "exclude-from-classmap": [
+ "/Tests/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Provides integration for Twig with various Symfony components",
+ "homepage": "https://symfony.com",
+ "support": {
+ "source": "https://github.com/symfony/twig-bridge/tree/v6.4.4"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2024-02-15T11:26:02+00:00"
+ },
+ {
+ "name": "twig/twig",
+ "version": "v3.8.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/twigphp/Twig.git",
+ "reference": "9d15f0ac07f44dc4217883ec6ae02fd555c6f71d"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/twigphp/Twig/zipball/9d15f0ac07f44dc4217883ec6ae02fd555c6f71d",
+ "reference": "9d15f0ac07f44dc4217883ec6ae02fd555c6f71d",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.2.5",
+ "symfony/polyfill-ctype": "^1.8",
+ "symfony/polyfill-mbstring": "^1.3",
+ "symfony/polyfill-php80": "^1.22"
+ },
+ "require-dev": {
+ "psr/container": "^1.0|^2.0",
+ "symfony/phpunit-bridge": "^5.4.9|^6.3|^7.0"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Twig\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com",
+ "homepage": "http://fabien.potencier.org",
+ "role": "Lead Developer"
+ },
+ {
+ "name": "Twig Team",
+ "role": "Contributors"
+ },
+ {
+ "name": "Armin Ronacher",
+ "email": "armin.ronacher@active-4.com",
+ "role": "Project Founder"
+ }
+ ],
+ "description": "Twig, the flexible, fast, and secure template language for PHP",
+ "homepage": "https://twig.symfony.com",
+ "keywords": [
+ "templating"
+ ],
+ "support": {
+ "issues": "https://github.com/twigphp/Twig/issues",
+ "source": "https://github.com/twigphp/Twig/tree/v3.8.0"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/twig/twig",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2023-11-21T18:54:41+00:00"
}
],
"aliases": [],
diff --git a/backend/config/bundles.php b/backend/config/bundles.php
index ffeb861..2e25f6e 100644
--- a/backend/config/bundles.php
+++ b/backend/config/bundles.php
@@ -3,4 +3,5 @@
return [
Symfony\Bundle\FrameworkBundle\FrameworkBundle::class => ['all' => true],
Symfony\Bundle\MakerBundle\MakerBundle::class => ['dev' => true],
+ Symfony\Bundle\DebugBundle\DebugBundle::class => ['dev' => true],
];
diff --git a/backend/config/packages/debug.yaml b/backend/config/packages/debug.yaml
new file mode 100644
index 0000000..ad874af
--- /dev/null
+++ b/backend/config/packages/debug.yaml
@@ -0,0 +1,5 @@
+when@dev:
+ debug:
+ # Forwards VarDumper Data clones to a centralized server allowing to inspect dumps on CLI or in your browser.
+ # See the "server:dump" command to start a new server.
+ dump_destination: "tcp://%env(VAR_DUMPER_SERVER)%"
diff --git a/backend/symfony.lock b/backend/symfony.lock
index 71d8362..72966a0 100644
--- a/backend/symfony.lock
+++ b/backend/symfony.lock
@@ -23,6 +23,18 @@
"./bin/console"
]
},
+ "symfony/debug-bundle": {
+ "version": "6.4",
+ "recipe": {
+ "repo": "github.com/symfony/recipes",
+ "branch": "main",
+ "version": "5.3",
+ "ref": "5aa8aa48234c8eb6dbdd7b3cd5d791485d2cec4b"
+ },
+ "files": [
+ "./config/packages/debug.yaml"
+ ]
+ },
"symfony/flex": {
"version": "2.4",
"recipe": {
diff --git a/frontend/app_student/.run/main_dev.run.xml b/frontend/app_student/.run/main_dev.run.xml
new file mode 100644
index 0000000..b98f49e
--- /dev/null
+++ b/frontend/app_student/.run/main_dev.run.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frontend/app_student/.run/main_prod.run.xml b/frontend/app_student/.run/main_prod.run.xml
new file mode 100644
index 0000000..7a31433
--- /dev/null
+++ b/frontend/app_student/.run/main_prod.run.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frontend/app_student/lib/api/api_service.dart b/frontend/app_student/lib/api/api_service.dart
new file mode 100644
index 0000000..531d406
--- /dev/null
+++ b/frontend/app_student/lib/api/api_service.dart
@@ -0,0 +1,24 @@
+import 'dart:convert';
+import 'package:http/http.dart' as http;
+
+class ApiService {
+ final String apiUrl;
+
+ ApiService({required this.apiUrl});
+
+ Future> getData(
+ String endpoint, T Function(Map) fromJson) async {
+ try {
+ final response = await http.get(Uri.parse('$apiUrl$endpoint'));
+
+ if (response.statusCode == 200) {
+ List jsonResponse = json.decode(response.body);
+ return jsonResponse.map((item) => fromJson(item)).toList();
+ } else {
+ throw Exception('Failed to load data');
+ }
+ } catch (e) {
+ throw Exception('Failed to load data: $e');
+ }
+ }
+}
diff --git a/frontend/app_student/lib/api/classes/entities/class.dart b/frontend/app_student/lib/api/classes/entities/class.dart
new file mode 100644
index 0000000..4f3e2b1
--- /dev/null
+++ b/frontend/app_student/lib/api/classes/entities/class.dart
@@ -0,0 +1,13 @@
+class Class {
+ final String file;
+ final String name;
+
+ Class({required this.file, required this.name});
+
+ factory Class.fromJson(Map json) {
+ return Class(
+ file: json['file'],
+ name: json['name'],
+ );
+ }
+}
diff --git a/frontend/app_student/lib/api/classes/repositories/class_repository.dart b/frontend/app_student/lib/api/classes/repositories/class_repository.dart
new file mode 100644
index 0000000..d37d6cf
--- /dev/null
+++ b/frontend/app_student/lib/api/classes/repositories/class_repository.dart
@@ -0,0 +1,12 @@
+import 'package:app_student/api/classes/entities/class.dart';
+import 'package:app_student/api/api_service.dart';
+
+class ClassRepository {
+ final ApiService apiService;
+
+ ClassRepository({required this.apiService});
+
+ Future> getClasses() {
+ return apiService.getData('/api/classes', (item) => Class.fromJson(item));
+ }
+}
diff --git a/frontend/app_student/lib/api/courses/entities/course.dart b/frontend/app_student/lib/api/courses/entities/course.dart
new file mode 100644
index 0000000..93655dc
--- /dev/null
+++ b/frontend/app_student/lib/api/courses/entities/course.dart
@@ -0,0 +1,31 @@
+class Course {
+ final String creneau;
+ final String activite;
+ final String id;
+ final String couleur;
+ final Map horaire;
+ final String salle;
+
+ Course({
+ required this.creneau,
+ required this.activite,
+ required this.id,
+ required this.couleur,
+ required this.horaire,
+ required this.salle,
+ });
+
+ factory Course.fromJson(Map json) {
+ return Course(
+ creneau: json['creneau'] ?? 'null',
+ activite: json['activite'] ?? 'null',
+ id: json['id'] ?? 'null',
+ couleur: json['couleur'] ?? 'null',
+ horaire: {
+ 'start': json['horaire']['start'] ?? 'null',
+ 'end': json['horaire']['end'] ?? 'null',
+ },
+ salle: json['salle'] ?? 'null',
+ );
+ }
+}
diff --git a/frontend/app_student/lib/api/day_schedule/entities/day_schedule.dart b/frontend/app_student/lib/api/day_schedule/entities/day_schedule.dart
new file mode 100644
index 0000000..77c70a2
--- /dev/null
+++ b/frontend/app_student/lib/api/day_schedule/entities/day_schedule.dart
@@ -0,0 +1,25 @@
+import '../../courses/entities/course.dart';
+
+class DaySchedule {
+ final String date;
+ final String jour;
+ final List cours;
+
+ DaySchedule({
+ required this.date,
+ required this.jour,
+ required this.cours,
+ });
+
+ factory DaySchedule.fromJson(Map json) {
+ var coursFromJson = json['cours'] as List;
+ List coursList =
+ coursFromJson.map((i) => Course.fromJson(i)).toList();
+
+ return DaySchedule(
+ date: json['date'],
+ jour: json['jour'],
+ cours: coursList,
+ );
+ }
+}
diff --git a/frontend/app_student/lib/api/day_schedule/repositories/day_schedule.dart b/frontend/app_student/lib/api/day_schedule/repositories/day_schedule.dart
new file mode 100644
index 0000000..c0fa80a
--- /dev/null
+++ b/frontend/app_student/lib/api/day_schedule/repositories/day_schedule.dart
@@ -0,0 +1,14 @@
+import 'package:app_student/api/api_service.dart';
+import '../entities/day_schedule.dart';
+
+class DayScheduleRepository {
+ final String className;
+ final ApiService apiService;
+
+ DayScheduleRepository({required this.className, required this.apiService});
+
+ Future> getDaySchedules($className) {
+ return apiService.getData('/api/timetable?class_param=$className',
+ (item) => DaySchedule.fromJson(item));
+ }
+}
diff --git a/frontend/app_student/lib/classes/bloc/class_bloc.dart b/frontend/app_student/lib/classes/bloc/class_bloc.dart
new file mode 100644
index 0000000..8fdcab1
--- /dev/null
+++ b/frontend/app_student/lib/classes/bloc/class_bloc.dart
@@ -0,0 +1,26 @@
+import 'dart:async';
+
+import 'package:app_student/api/classes/entities/class.dart';
+import 'package:app_student/api/classes/repositories/class_repository.dart';
+
+
+
+class ClassBloc {
+ final ClassRepository classRepository;
+ final _classController = StreamController>();
+
+ Stream> get classStream => _classController.stream;
+
+ ClassBloc({required this.classRepository}) {
+ fetchClasses();
+ }
+
+ fetchClasses() async {
+ final classes = await classRepository.getClasses();
+ _classController.sink.add(classes);
+ }
+
+ dispose() {
+ _classController.close();
+ }
+}
diff --git a/frontend/app_student/lib/classes/views/class.dart b/frontend/app_student/lib/classes/views/class.dart
new file mode 100644
index 0000000..465b331
--- /dev/null
+++ b/frontend/app_student/lib/classes/views/class.dart
@@ -0,0 +1,60 @@
+import 'package:app_student/api/classes/entities/class.dart';
+import 'package:flutter/material.dart';
+import 'package:app_student/classes/bloc/class_bloc.dart';
+
+
+class ClassListPage extends StatefulWidget {
+ final ClassBloc classBloc;
+
+ const ClassListPage({required this.classBloc, super.key});
+
+ @override
+ ClassListPageState createState() => ClassListPageState();
+}
+
+class ClassListPageState extends State {
+ late ClassBloc _classBloc;
+
+ @override
+ void initState() {
+ super.initState();
+ _classBloc = widget.classBloc;
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ return Scaffold(
+ appBar: AppBar(
+ title: const Text('Class List'),
+ ),
+ body: StreamBuilder>(
+ stream: _classBloc.classStream,
+ builder: (BuildContext context, AsyncSnapshot> snapshot) {
+ if (snapshot.hasError) {
+ return Center(child: Text('Error: ${snapshot.error}'));
+ }
+
+ if (!snapshot.hasData) {
+ return const Center(child: CircularProgressIndicator());
+ }
+
+ return ListView.builder(
+ itemCount: snapshot.data!.length,
+ itemBuilder: (context, index) {
+ return ListTile(
+ title: Text(snapshot.data![index].name),
+ subtitle: Text(snapshot.data![index].file),
+ );
+ },
+ );
+ },
+ ),
+ );
+ }
+
+ @override
+ void dispose() {
+ _classBloc.dispose();
+ super.dispose();
+ }
+}
diff --git a/frontend/app_student/lib/config/config.dart b/frontend/app_student/lib/config/config.dart
new file mode 100644
index 0000000..ef552f2
--- /dev/null
+++ b/frontend/app_student/lib/config/config.dart
@@ -0,0 +1,3 @@
+abstract class Config {
+ String get apiUrl;
+}
diff --git a/frontend/app_student/lib/config/dev_config.dart b/frontend/app_student/lib/config/dev_config.dart
new file mode 100644
index 0000000..af2b236
--- /dev/null
+++ b/frontend/app_student/lib/config/dev_config.dart
@@ -0,0 +1,6 @@
+import 'config.dart';
+
+class DevConfig extends Config {
+ @override
+ String get apiUrl => 'https://api-dev.lukasvalois.com';
+}
diff --git a/frontend/app_student/lib/config/prod_config.dart b/frontend/app_student/lib/config/prod_config.dart
new file mode 100644
index 0000000..ae7a73c
--- /dev/null
+++ b/frontend/app_student/lib/config/prod_config.dart
@@ -0,0 +1,8 @@
+import 'config.dart';
+
+class ProdConfig extends Config {
+ @override
+ // TODO: Implement the new production API URL
+ String get apiUrl => 'https://api-dev.lukasvalois.com';
+
+}
diff --git a/frontend/app_student/lib/day_schedules/bloc/day_schedule_bloc.dart b/frontend/app_student/lib/day_schedules/bloc/day_schedule_bloc.dart
new file mode 100644
index 0000000..40eb95d
--- /dev/null
+++ b/frontend/app_student/lib/day_schedules/bloc/day_schedule_bloc.dart
@@ -0,0 +1,25 @@
+import 'dart:async';
+import 'package:app_student/api/day_schedule/entities/day_schedule.dart';
+import 'package:app_student/api/day_schedule/repositories/day_schedule.dart';
+
+class DayScheduleBloc {
+ final DayScheduleRepository dayScheduleRepository;
+ final _dayScheduleController = StreamController>();
+
+ Stream> get dayScheduleStream =>
+ _dayScheduleController.stream;
+
+ DayScheduleBloc({required this.dayScheduleRepository}) {
+ fetchDaySchedules('B3 GROUPE 3 DLW-FA');
+ // TODO : get the class name from the shared preferences
+ }
+
+ fetchDaySchedules(String className) async {
+ final daySchedules = await dayScheduleRepository.getDaySchedules(className);
+ _dayScheduleController.sink.add(daySchedules);
+ }
+
+ dispose() {
+ _dayScheduleController.close();
+ }
+}
diff --git a/frontend/app_student/lib/day_schedules/views/day_schedule.dart b/frontend/app_student/lib/day_schedules/views/day_schedule.dart
new file mode 100644
index 0000000..a522a09
--- /dev/null
+++ b/frontend/app_student/lib/day_schedules/views/day_schedule.dart
@@ -0,0 +1,36 @@
+import 'package:app_student/day_schedules/bloc/day_schedule_bloc.dart';
+import 'package:flutter/material.dart';
+import 'package:app_student/api/day_schedule/entities/day_schedule.dart';
+
+class DayScheduleView extends StatelessWidget {
+ final DayScheduleBloc dayScheduleBloc;
+
+ const DayScheduleView({super.key, required this.dayScheduleBloc});
+
+ @override
+ Widget build(BuildContext context) {
+ return StreamBuilder>(
+ stream: dayScheduleBloc.dayScheduleStream,
+ builder: (context, snapshot) {
+ if (snapshot.hasData) {
+ return ListView.builder(
+ itemCount: snapshot.data!.length,
+ itemBuilder: (context, index) {
+ final daySchedule = snapshot.data![index];
+ return Card(
+ child: ListTile(
+ title: Text(daySchedule.date),
+ subtitle: Text('Jour: ${daySchedule.jour}'),
+ ),
+ );
+ },
+ );
+ } else if (snapshot.hasError) {
+ return Text('Erreur: ${snapshot.error}');
+ }
+
+ return const Text('Erreur: Les données ne sont pas encore disponibles');
+ },
+ );
+ }
+}
diff --git a/frontend/app_student/lib/main.dart b/frontend/app_student/lib/main.dart
deleted file mode 100644
index 8e94089..0000000
--- a/frontend/app_student/lib/main.dart
+++ /dev/null
@@ -1,125 +0,0 @@
-import 'package:flutter/material.dart';
-
-void main() {
- runApp(const MyApp());
-}
-
-class MyApp extends StatelessWidget {
- const MyApp({super.key});
-
- // This widget is the root of your application.
- @override
- Widget build(BuildContext context) {
- return MaterialApp(
- title: 'Flutter Demo',
- theme: ThemeData(
- // This is the theme of your application.
- //
- // TRY THIS: Try running your application with "flutter run". You'll see
- // the application has a purple toolbar. Then, without quitting the app,
- // try changing the seedColor in the colorScheme below to Colors.green
- // and then invoke "hot reload" (save your changes or press the "hot
- // reload" button in a Flutter-supported IDE, or press "r" if you used
- // the command line to start the app).
- //
- // Notice that the counter didn't reset back to zero; the application
- // state is not lost during the reload. To reset the state, use hot
- // restart instead.
- //
- // This works for code too, not just values: Most code changes can be
- // tested with just a hot reload.
- colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
- useMaterial3: true,
- ),
- home: const MyHomePage(title: 'Flutter Demo Home Page'),
- );
- }
-}
-
-class MyHomePage extends StatefulWidget {
- const MyHomePage({super.key, required this.title});
-
- // This widget is the home page of your application. It is stateful, meaning
- // that it has a State object (defined below) that contains fields that affect
- // how it looks.
-
- // This class is the configuration for the state. It holds the values (in this
- // case the title) provided by the parent (in this case the App widget) and
- // used by the build method of the State. Fields in a Widget subclass are
- // always marked "final".
-
- final String title;
-
- @override
- State createState() => _MyHomePageState();
-}
-
-class _MyHomePageState extends State {
- int _counter = 0;
-
- void _incrementCounter() {
- setState(() {
- // This call to setState tells the Flutter framework that something has
- // changed in this State, which causes it to rerun the build method below
- // so that the display can reflect the updated values. If we changed
- // _counter without calling setState(), then the build method would not be
- // called again, and so nothing would appear to happen.
- _counter++;
- });
- }
-
- @override
- Widget build(BuildContext context) {
- // This method is rerun every time setState is called, for instance as done
- // by the _incrementCounter method above.
- //
- // The Flutter framework has been optimized to make rerunning build methods
- // fast, so that you can just rebuild anything that needs updating rather
- // than having to individually change instances of widgets.
- return Scaffold(
- appBar: AppBar(
- // TRY THIS: Try changing the color here to a specific color (to
- // Colors.amber, perhaps?) and trigger a hot reload to see the AppBar
- // change color while the other colors stay the same.
- backgroundColor: Theme.of(context).colorScheme.inversePrimary,
- // 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(widget.title),
- ),
- body: Center(
- // Center is a layout widget. It takes a single child and positions it
- // in the middle of the parent.
- child: Column(
- // Column is also a layout widget. It takes a list of children and
- // arranges them vertically. By default, it sizes itself to fit its
- // children horizontally, and tries to be as tall as its parent.
- //
- // Column has various properties to control how it sizes itself and
- // how it positions its children. Here we use mainAxisAlignment to
- // center the children vertically; the main axis here is the vertical
- // axis because Columns are vertical (the cross axis would be
- // horizontal).
- //
- // TRY THIS: Invoke "debug painting" (choose the "Toggle Debug Paint"
- // action in the IDE, or press "p" in the console), to see the
- // wireframe for each widget.
- mainAxisAlignment: MainAxisAlignment.center,
- children: [
- const Text(
- 'You have pushed the button this many times:',
- ),
- Text(
- '$_counter',
- style: Theme.of(context).textTheme.headlineMedium,
- ),
- ],
- ),
- ),
- floatingActionButton: FloatingActionButton(
- onPressed: _incrementCounter,
- tooltip: 'Increment',
- child: const Icon(Icons.add),
- ), // This trailing comma makes auto-formatting nicer for build methods.
- );
- }
-}
diff --git a/frontend/app_student/lib/main_dev.dart b/frontend/app_student/lib/main_dev.dart
new file mode 100644
index 0000000..0ba4f9a
--- /dev/null
+++ b/frontend/app_student/lib/main_dev.dart
@@ -0,0 +1,39 @@
+import 'package:app_student/api/api_service.dart';
+import 'package:app_student/api/classes/repositories/class_repository.dart';
+import 'package:app_student/classes/views/class.dart';
+import 'package:app_student/config/dev_config.dart';
+import 'package:flutter/material.dart';
+import 'package:provider/provider.dart';
+import 'classes/bloc/class_bloc.dart';
+import 'config/config.dart';
+
+void main() {
+ runApp(
+ Provider(
+ create: (_) => DevConfig(),
+ child: const MyApp(),
+ ),
+ );
+}
+
+class MyApp extends StatelessWidget {
+ const MyApp({super.key});
+
+ @override
+ Widget build(BuildContext context) {
+ final config = Provider.of(context);
+ final ApiService apiService = ApiService(apiUrl: config.apiUrl);
+ final classBloc =
+ ClassBloc(classRepository: ClassRepository(apiService: apiService));
+
+ return MaterialApp(
+ title: 'Class List',
+ theme: ThemeData(
+ primarySwatch: Colors.blue,
+ ),
+ home: ClassListPage(
+ classBloc: classBloc,
+ ),
+ );
+ }
+}
diff --git a/frontend/app_student/lib/main_prod.dart b/frontend/app_student/lib/main_prod.dart
new file mode 100644
index 0000000..c0adc91
--- /dev/null
+++ b/frontend/app_student/lib/main_prod.dart
@@ -0,0 +1,42 @@
+import 'package:app_student/api/api_service.dart';
+import 'package:app_student/api/day_schedule/repositories/day_schedule.dart';
+import 'package:app_student/config/prod_config.dart';
+import 'package:app_student/day_schedules/bloc/day_schedule_bloc.dart';
+import 'package:app_student/day_schedules/views/day_schedule.dart';
+import 'package:flutter/material.dart';
+import 'package:provider/provider.dart';
+import 'config/config.dart';
+
+void main() {
+ runApp(
+ Provider(
+ create: (_) => ProdConfig(),
+ child: const MyApp(),
+ ),
+ );
+}
+
+class MyApp extends StatelessWidget {
+ const MyApp({super.key});
+
+ @override
+ Widget build(BuildContext context) {
+ final config = Provider.of(context);
+ final ApiService apiService = ApiService(apiUrl: config.apiUrl);
+
+ final dayScheduleBloc = DayScheduleBloc(
+ dayScheduleRepository: DayScheduleRepository(
+ apiService: apiService, className: 'B3%20Groupe%203%20DLW-FA'));
+
+
+ return MaterialApp(
+ title: 'Class List',
+ theme: ThemeData(
+ primarySwatch: Colors.blue,
+ ),
+ home: DayScheduleView(
+ dayScheduleBloc: dayScheduleBloc,
+ ),
+ );
+ }
+}
diff --git a/frontend/app_student/pubspec.lock b/frontend/app_student/pubspec.lock
index f5b0af9..b5fb585 100644
--- a/frontend/app_student/pubspec.lock
+++ b/frontend/app_student/pubspec.lock
@@ -75,6 +75,22 @@ packages:
description: flutter
source: sdk
version: "0.0.0"
+ http:
+ dependency: "direct main"
+ description:
+ name: http
+ sha256: "761a297c042deedc1ffbb156d6e2af13886bb305c2a343a4d972504cd67dd938"
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.2.1"
+ http_parser:
+ dependency: transitive
+ description:
+ name: http_parser
+ sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b"
+ url: "https://pub.dev"
+ source: hosted
+ version: "4.0.2"
leak_tracker:
dependency: transitive
description:
@@ -131,6 +147,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.11.0"
+ nested:
+ dependency: transitive
+ description:
+ name: nested
+ sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20"
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.0.0"
path:
dependency: transitive
description:
@@ -139,6 +163,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.9.0"
+ provider:
+ dependency: "direct main"
+ description:
+ name: provider
+ sha256: c8a055ee5ce3fd98d6fc872478b03823ffdb448699c6ebdbbc71d59b596fd48c
+ url: "https://pub.dev"
+ source: hosted
+ version: "6.1.2"
sky_engine:
dependency: transitive
description: flutter
@@ -192,6 +224,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "0.6.1"
+ typed_data:
+ dependency: transitive
+ description:
+ name: typed_data
+ sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.3.2"
vector_math:
dependency: transitive
description:
@@ -208,5 +248,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "13.0.0"
+ web:
+ dependency: transitive
+ description:
+ name: web
+ sha256: "97da13628db363c635202ad97068d47c5b8aa555808e7a9411963c533b449b27"
+ url: "https://pub.dev"
+ source: hosted
+ version: "0.5.1"
sdks:
dart: ">=3.3.0 <4.0.0"
+ flutter: ">=1.16.0"
diff --git a/frontend/app_student/pubspec.yaml b/frontend/app_student/pubspec.yaml
index 2a36cc0..9d54152 100644
--- a/frontend/app_student/pubspec.yaml
+++ b/frontend/app_student/pubspec.yaml
@@ -35,6 +35,8 @@ dependencies:
# The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: ^1.0.6
+ http: ^1.2.1
+ provider: ^6.1.2
dev_dependencies:
flutter_test:
diff --git a/frontend/app_student/test/widget_test.dart b/frontend/app_student/test/widget_test.dart
index da445b1..ef5fd51 100644
--- a/frontend/app_student/test/widget_test.dart
+++ b/frontend/app_student/test/widget_test.dart
@@ -8,7 +8,7 @@
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
-import 'package:app_student/main.dart';
+import 'package:app_student/main_dev.dart';
void main() {
testWidgets('Counter increments smoke test', (WidgetTester tester) async {