diff --git a/.env.example b/.env.example
new file mode 100644
index 0000000..7d1b4e7
--- /dev/null
+++ b/.env.example
@@ -0,0 +1,5 @@
+API_URL_ANDROID=http://10.0.2.2:8000
+API_URL_IOS=http://localhost:8000
+API_URL_PHYSICAL=
+URL_MEDIAS=
+API_TIMEOUT=10
\ No newline at end of file
diff --git a/.flutter-plugins-dependencies 2 b/.flutter-plugins-dependencies 2
new file mode 100644
index 0000000..e7f8482
--- /dev/null
+++ b/.flutter-plugins-dependencies 2
@@ -0,0 +1 @@
+{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"audioplayers_darwin","path":"/Users/elhatriayoub/.pub-cache/hosted/pub.dev/audioplayers_darwin-6.2.0/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"path_provider_foundation","path":"/Users/elhatriayoub/.pub-cache/hosted/pub.dev/path_provider_foundation-2.4.1/","shared_darwin_source":true,"native_build":true,"dependencies":[],"dev_dependency":false},{"name":"sqflite_darwin","path":"/Users/elhatriayoub/.pub-cache/hosted/pub.dev/sqflite_darwin-2.4.1+1/","shared_darwin_source":true,"native_build":true,"dependencies":[],"dev_dependency":false},{"name":"video_player_avfoundation","path":"/Users/elhatriayoub/.pub-cache/hosted/pub.dev/video_player_avfoundation-2.7.0/","shared_darwin_source":true,"native_build":true,"dependencies":[],"dev_dependency":false}],"android":[{"name":"audioplayers_android","path":"/Users/elhatriayoub/.pub-cache/hosted/pub.dev/audioplayers_android-5.2.0/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"path_provider_android","path":"/Users/elhatriayoub/.pub-cache/hosted/pub.dev/path_provider_android-2.2.16/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"sqflite_android","path":"/Users/elhatriayoub/.pub-cache/hosted/pub.dev/sqflite_android-2.4.0/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"video_player_android","path":"/Users/elhatriayoub/.pub-cache/hosted/pub.dev/video_player_android-2.8.2/","native_build":true,"dependencies":[],"dev_dependency":false}],"macos":[{"name":"audioplayers_darwin","path":"/Users/elhatriayoub/.pub-cache/hosted/pub.dev/audioplayers_darwin-6.2.0/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"path_provider_foundation","path":"/Users/elhatriayoub/.pub-cache/hosted/pub.dev/path_provider_foundation-2.4.1/","shared_darwin_source":true,"native_build":true,"dependencies":[],"dev_dependency":false},{"name":"sqflite_darwin","path":"/Users/elhatriayoub/.pub-cache/hosted/pub.dev/sqflite_darwin-2.4.1+1/","shared_darwin_source":true,"native_build":true,"dependencies":[],"dev_dependency":false},{"name":"video_player_avfoundation","path":"/Users/elhatriayoub/.pub-cache/hosted/pub.dev/video_player_avfoundation-2.7.0/","shared_darwin_source":true,"native_build":true,"dependencies":[],"dev_dependency":false}],"linux":[{"name":"audioplayers_linux","path":"/Users/elhatriayoub/.pub-cache/hosted/pub.dev/audioplayers_linux-4.2.0/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"path_provider_linux","path":"/Users/elhatriayoub/.pub-cache/hosted/pub.dev/path_provider_linux-2.2.1/","native_build":false,"dependencies":[],"dev_dependency":false}],"windows":[{"name":"audioplayers_windows","path":"/Users/elhatriayoub/.pub-cache/hosted/pub.dev/audioplayers_windows-4.2.0/","native_build":true,"dependencies":[],"dev_dependency":false},{"name":"path_provider_windows","path":"/Users/elhatriayoub/.pub-cache/hosted/pub.dev/path_provider_windows-2.3.0/","native_build":false,"dependencies":[],"dev_dependency":false}],"web":[{"name":"audioplayers_web","path":"/Users/elhatriayoub/.pub-cache/hosted/pub.dev/audioplayers_web-5.1.0/","dependencies":[],"dev_dependency":false},{"name":"video_player_web","path":"/Users/elhatriayoub/.pub-cache/hosted/pub.dev/video_player_web-2.3.4/","dependencies":[],"dev_dependency":false}]},"dependencyGraph":[{"name":"audioplayers","dependencies":["audioplayers_android","audioplayers_darwin","audioplayers_linux","audioplayers_web","audioplayers_windows","path_provider"]},{"name":"audioplayers_android","dependencies":[]},{"name":"audioplayers_darwin","dependencies":[]},{"name":"audioplayers_linux","dependencies":[]},{"name":"audioplayers_web","dependencies":[]},{"name":"audioplayers_windows","dependencies":[]},{"name":"path_provider","dependencies":["path_provider_android","path_provider_foundation","path_provider_linux","path_provider_windows"]},{"name":"path_provider_android","dependencies":[]},{"name":"path_provider_foundation","dependencies":[]},{"name":"path_provider_linux","dependencies":[]},{"name":"path_provider_windows","dependencies":[]},{"name":"sqflite","dependencies":["sqflite_android","sqflite_darwin"]},{"name":"sqflite_android","dependencies":[]},{"name":"sqflite_darwin","dependencies":[]},{"name":"video_player","dependencies":["video_player_android","video_player_avfoundation","video_player_web"]},{"name":"video_player_android","dependencies":[]},{"name":"video_player_avfoundation","dependencies":[]},{"name":"video_player_web","dependencies":[]}],"date_created":"2026-02-15 15:34:16.509165","version":"3.35.5","swift_package_manager_enabled":{"ios":false,"macos":false}}
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
index 924e127..7df6ec9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,9 +5,11 @@
*.swp
.DS_Store
.atom/
+.build/
.buildlog/
.history
.svn/
+.swiftpm/
migrate_working_dir/
# IntelliJ related
@@ -42,4 +44,6 @@ app.*.map.json
/android/app/profile
/android/app/release
-build
\ No newline at end of file
+
+build
+.env
\ No newline at end of file
diff --git a/android/app/build.gradle b/android/app/build.gradle
index 107258c..bba7235 100644
--- a/android/app/build.gradle
+++ b/android/app/build.gradle
@@ -6,9 +6,9 @@ plugins {
}
android {
- namespace = "com.example.seriouse_game"
- compileSdk = 35 //flutter.compileSdkVersion
- ndkVersion = "25.1.8937393" //flutter.ndkVersion
+ namespace = "com.example.factoscope"
+ compileSdk = 36 //flutter.compileSdkVersion
+ ndkVersion = "26.1.10909125" //flutter.ndkVersion
compileOptions {
sourceCompatibility = JavaVersion.VERSION_1_8
@@ -21,7 +21,7 @@ android {
defaultConfig {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
- applicationId = "com.example.seriouse_game"
+ applicationId = "com.example.factoscope"
// You can update the following values to match your application needs.
// For more information, see: https://flutter.dev/to/review-gradle-config.
minSdk = flutter.minSdkVersion
diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml
index b326570..fb4074e 100644
--- a/android/app/src/main/AndroidManifest.xml
+++ b/android/app/src/main/AndroidManifest.xml
@@ -1,8 +1,9 @@
+ android:icon="@mipmap/ic_launcher"
+ android:roundIcon="@mipmap/ic_launcher_round">
+ android:name="io.flutter.embedding.android.NormalTheme"
+ android:resource="@style/NormalTheme"
+ />
-
-
+
+
-
-
+
+
-
+
\ No newline at end of file
diff --git a/android/app/src/main/kotlin/com/example/projet_collective/MainActivity.kt b/android/app/src/main/kotlin/com/example/projet_collective/MainActivity.kt
index 2528f66..390f4fd 100644
--- a/android/app/src/main/kotlin/com/example/projet_collective/MainActivity.kt
+++ b/android/app/src/main/kotlin/com/example/projet_collective/MainActivity.kt
@@ -1,4 +1,4 @@
-package com.example.seriouse_game
+package com.example.factoscope
import io.flutter.embedding.android.FlutterActivity
diff --git a/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
new file mode 100644
index 0000000..c9ad5f9
--- /dev/null
+++ b/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
new file mode 100644
index 0000000..c9ad5f9
--- /dev/null
+++ b/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
deleted file mode 100644
index db77bb4..0000000
Binary files a/android/app/src/main/res/mipmap-hdpi/ic_launcher.png and /dev/null differ
diff --git a/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png b/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png
new file mode 100644
index 0000000..f5ae6d2
Binary files /dev/null and b/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png differ
diff --git a/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
deleted file mode 100644
index 17987b7..0000000
Binary files a/android/app/src/main/res/mipmap-mdpi/ic_launcher.png and /dev/null differ
diff --git a/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png b/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png
new file mode 100644
index 0000000..f5ae6d2
Binary files /dev/null and b/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png differ
diff --git a/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
deleted file mode 100644
index 09d4391..0000000
Binary files a/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png and /dev/null differ
diff --git a/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png b/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png
new file mode 100644
index 0000000..f5ae6d2
Binary files /dev/null and b/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png differ
diff --git a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
deleted file mode 100644
index d5f1c8d..0000000
Binary files a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png and /dev/null differ
diff --git a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png
new file mode 100644
index 0000000..f5ae6d2
Binary files /dev/null and b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png differ
diff --git a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
deleted file mode 100644
index 4d6372e..0000000
Binary files a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png and /dev/null differ
diff --git a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png
new file mode 100644
index 0000000..f5ae6d2
Binary files /dev/null and b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png differ
diff --git a/android/app/src/main/res/values/styles.xml b/android/app/src/main/res/values/styles.xml
index cb1ef88..cb9786d 100644
--- a/android/app/src/main/res/values/styles.xml
+++ b/android/app/src/main/res/values/styles.xml
@@ -1,6 +1,7 @@
-
+
-
+
+ #F0AE00
+
\ No newline at end of file
diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties
index 7bb2df6..3c85cfe 100644
--- a/android/gradle/wrapper/gradle-wrapper.properties
+++ b/android/gradle/wrapper/gradle-wrapper.properties
@@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-all.zip
diff --git a/android/settings.gradle b/android/settings.gradle
index a42444d..4f52071 100644
--- a/android/settings.gradle
+++ b/android/settings.gradle
@@ -18,8 +18,8 @@ pluginManagement {
plugins {
id "dev.flutter.flutter-plugin-loader" version "1.0.0"
- id "com.android.application" version "8.2.1" apply false
- id "org.jetbrains.kotlin.android" version "1.8.22" apply false
+ id "com.android.application" version "8.6.0" apply false
+ id "org.jetbrains.kotlin.android" version "2.1.0" apply false
}
include ":app"
diff --git a/assets/icon/icon_android.png b/assets/icon/icon_android.png
new file mode 100644
index 0000000..252dfb1
Binary files /dev/null and b/assets/icon/icon_android.png differ
diff --git a/ios/Flutter/Generated 2.xcconfig b/ios/Flutter/Generated 2.xcconfig
new file mode 100644
index 0000000..4744a3b
--- /dev/null
+++ b/ios/Flutter/Generated 2.xcconfig
@@ -0,0 +1,14 @@
+// This is a generated file; do not edit or check into version control.
+FLUTTER_ROOT=/opt/homebrew/share/flutter
+FLUTTER_APPLICATION_PATH=/Users/elhatriayoub/Desktop/PCOl
+COCOAPODS_PARALLEL_CODE_SIGN=true
+FLUTTER_TARGET=lib/main.dart
+FLUTTER_BUILD_DIR=build
+FLUTTER_BUILD_NAME=1.0.0
+FLUTTER_BUILD_NUMBER=1
+EXCLUDED_ARCHS[sdk=iphonesimulator*]=i386
+EXCLUDED_ARCHS[sdk=iphoneos*]=armv7
+DART_OBFUSCATION=false
+TRACK_WIDGET_CREATION=true
+TREE_SHAKE_ICONS=false
+PACKAGE_CONFIG=.dart_tool/package_config.json
diff --git a/ios/Flutter/flutter_export_environment 2.sh b/ios/Flutter/flutter_export_environment 2.sh
new file mode 100755
index 0000000..5299fd4
--- /dev/null
+++ b/ios/Flutter/flutter_export_environment 2.sh
@@ -0,0 +1,13 @@
+#!/bin/sh
+# This is a generated file; do not edit or check into version control.
+export "FLUTTER_ROOT=/opt/homebrew/share/flutter"
+export "FLUTTER_APPLICATION_PATH=/Users/elhatriayoub/Desktop/PCOl"
+export "COCOAPODS_PARALLEL_CODE_SIGN=true"
+export "FLUTTER_TARGET=lib/main.dart"
+export "FLUTTER_BUILD_DIR=build"
+export "FLUTTER_BUILD_NAME=1.0.0"
+export "FLUTTER_BUILD_NUMBER=1"
+export "DART_OBFUSCATION=false"
+export "TRACK_WIDGET_CREATION=true"
+export "TREE_SHAKE_ICONS=false"
+export "PACKAGE_CONFIG=.dart_tool/package_config.json"
diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist
index c491f5e..e5c700d 100644
--- a/ios/Runner/Info.plist
+++ b/ios/Runner/Info.plist
@@ -13,7 +13,7 @@
CFBundleInfoDictionaryVersion
6.0
CFBundleName
- seriouse_game
+ factoscope
CFBundlePackageType
APPL
CFBundleShortVersionString
diff --git a/lib/DataBase/database_helper.dart b/lib/DataBase/database_helper.dart
deleted file mode 100644
index df5a889..0000000
--- a/lib/DataBase/database_helper.dart
+++ /dev/null
@@ -1,196 +0,0 @@
-import 'package:sqflite/sqflite.dart';
-import 'package:path/path.dart';
-
-class DatabaseHelper {
- static final DatabaseHelper instance = DatabaseHelper._init();
- static Database? _database;
-
- DatabaseHelper._init();
-
- // Méthode pour obtenir la base de données
- Future get database async {
- if (_database != null) return _database!;
- _database = await _initDB('app.db');
- return _database!;
- }
-
- // Initialisation de la base de données
- Future _initDB(String filePath) async {
- final dbPath = await getDatabasesPath();
- final path = join(dbPath, filePath);
- //resetDatabase();
- return await openDatabase(
- path,
- version: 1,
- onOpen: (db) async {
- // Appeler _createDB pour recréer les tables si nécessaire
- await _createDB(db, 1);
- },
- );
- }
-
- // Crée les tables dans la base de données
- Future _createDB(Database db, int version) async {
- await db.execute('''
- CREATE TABLE IF NOT EXISTS module (
- id INTEGER PRIMARY KEY AUTOINCREMENT,
- urlImg TEXT NOT NULL,
- titre TEXT NOT NULL,
- description TEXT NOT NULL
- );
- ''');
-
- await db.execute('''
- CREATE TABLE IF NOT EXISTS cours (
- id INTEGER PRIMARY KEY AUTOINCREMENT,
- titre TEXT NOT NULL,
- contenu TEXT NOT NULL,
- id_module INTEGER,
- FOREIGN KEY (id_module) REFERENCES module (id)
- );
- ''');
-
- await db.execute('''
- CREATE TABLE IF NOT EXISTS page (
- id INTEGER PRIMARY KEY AUTOINCREMENT,
- description TEXT ,
- ordre INTEGER NOT NULL,
- urlAudio TEST DEFAULT "",
- est_vue INTEGER DEFAULT 0,
- id_cours INTEGER NOT NULL,
- FOREIGN KEY (id_cours) REFERENCES cours (id) ON DELETE CASCADE ON UPDATE CASCADE
- );
- ''');
-
- await db.execute('''
- CREATE TABLE IF NOT EXISTS MiniJeu (
- id INTEGER PRIMARY KEY AUTOINCREMENT,
- id_cours INTEGER NOT NULL,
- nom TEXT NOT NULL,
- description TEXT,
- progression INTEGER NOT NULL,
- FOREIGN KEY (id_cours) REFERENCES cours (id)
- );
-''');
-
- await db.execute('''
- CREATE TABLE IF NOT EXISTS MotsCroises (
- id INTEGER PRIMARY KEY AUTOINCREMENT,
- id_minijeu INTEGER NOT NULL,
- taille_grille TEXT NOT NULL,
- description TEXT,
- FOREIGN KEY (id_minijeu) REFERENCES MiniJeu (id) ON DELETE CASCADE
-
- );
- ''');
-
- await db.execute('''
- CREATE TABLE IF NOT EXISTS Mot (
- id INTEGER PRIMARY KEY AUTOINCREMENT,
- id_motscroises INTEGER NOT NULL,
- mot TEXT NOT NULL,
- indice TEXT NOT NULL,
- direction TEXT NOT NULL,
- position_depart_x INTEGER NOT NULL,
- position_depart_y INTEGER NOT NULL,
- FOREIGN KEY (id_motscroises) REFERENCES MotsCroises (id) ON DELETE CASCADE
- );
- ''');
-
- await db.execute('''
- CREATE TABLE IF NOT EXISTS MediaCours (
- id INTEGER PRIMARY KEY AUTOINCREMENT,
- id_page INTEGER NOT NULL,
- ordre INTEGER NOT NULL,
- url TEXT NOT NULL,
- type TEXT NOT NULL,
- caption TEXT,
- FOREIGN KEY (id_page) REFERENCES page (id) ON DELETE CASCADE
- );
-''');
- await db.execute('''
- CREATE TABLE IF NOT EXISTS ObjectifCours (
- id INTEGER PRIMARY KEY AUTOINCREMENT,
- id_cours INTEGER NOT NULL,
- description TEXT NOT NULL,
- FOREIGN KEY (id_cours) REFERENCES cours (id) ON DELETE CASCADE
- );
-''');
-
- await db.execute('''
-CREATE TABLE Question(
- idQuestion INTEGER,
- PRIMARY KEY(idQuestion)
-);''');
-
- await db.execute('''CREATE TABLE QuestionImg(
- idQuestion INTEGER,
- urlImage TEXT NOT NULL,
- caption TEXT NOT NULL,
- PRIMARY KEY(idQuestion),
- FOREIGN KEY(idQuestion) REFERENCES Question(idQuestion)
-);''');
-
- await db.execute('''CREATE TABLE QuestionText(
- idQuestion INTEGER,
- txt TEXT NOT NULL,
- PRIMARY KEY(idQuestion),
- FOREIGN KEY(idQuestion) REFERENCES Question(idQuestion)
-);''');
-
- await db.execute('''CREATE TABLE QCM(
- idQCM INTEGER,
- numSolution INTEGER NOT NULL,
- idCours INTEGER NOT NULL,
- idQuestion INTEGER NOT NULL,
- PRIMARY KEY(idQCM),
- UNIQUE(idQuestion),
- FOREIGN KEY(idCours) REFERENCES cours(id),
- FOREIGN KEY(idQuestion) REFERENCES Question(idQuestion)
-);''');
-
- await db.execute('''CREATE TABLE Reponse(
- idReponse INTEGER,
- idQCM INTEGER NOT NULL,
- PRIMARY KEY(idReponse),
- FOREIGN KEY(idQCM) REFERENCES QCM(idQCM)
-);''');
-
- await db.execute('''CREATE TABLE ReponseImg(
- idReponse INTEGER,
- urlImage TEXT NOT NULL,
- caption TEXT NOT NULL,
- PRIMARY KEY(idReponse),
- FOREIGN KEY(idReponse) REFERENCES Reponse(idReponse)
-);''');
-
- await db.execute('''CREATE TABLE ReponseText(
- idReponse INTEGER,
- txt TEXT NOT NULL,
- PRIMARY KEY(idReponse),
- FOREIGN KEY(idReponse) REFERENCES Reponse(idReponse)
-);''');
-
-
- }
-
- // Supprime la base de données et recrée les tables
- Future resetDatabase() async {
- final dbPath = await getDatabasesPath();
- final path = join(dbPath, 'app.db');
-
- // Supprime la base de données existante
- await deleteDatabase(path);
-
- // Rouvre la base de données pour recréer les tables
- _database = await _initDB('app.db');
- }
-
- // Méthode pour fermer la base de données
- Future close() async {
- final db = _database;
- if (db != null) {
- await db.close();
- }
- }
-}
diff --git a/lib/config/Couleurs et typos.md b/lib/assets/Couleurs et typos.md
similarity index 100%
rename from lib/config/Couleurs et typos.md
rename to lib/assets/Couleurs et typos.md
diff --git a/lib/assets/cfi.jpg b/lib/assets/cfi.jpg
new file mode 100644
index 0000000..86ae4d8
Binary files /dev/null and b/lib/assets/cfi.jpg differ
diff --git a/lib/assets/epjt.png b/lib/assets/epjt.png
new file mode 100644
index 0000000..eb32512
Binary files /dev/null and b/lib/assets/epjt.png differ
diff --git a/lib/data/AppData/CharteFactoscope/facto-education.png b/lib/assets/facto-education.png
similarity index 100%
rename from lib/data/AppData/CharteFactoscope/facto-education.png
rename to lib/assets/facto-education.png
diff --git a/lib/data/AppData/CharteFactoscope/facto-environnement.png b/lib/assets/facto-environnement.png
similarity index 100%
rename from lib/data/AppData/CharteFactoscope/facto-environnement.png
rename to lib/assets/facto-environnement.png
diff --git a/lib/data/AppData/CharteFactoscope/facto-institutions.png b/lib/assets/facto-institutions.png
similarity index 100%
rename from lib/data/AppData/CharteFactoscope/facto-institutions.png
rename to lib/assets/facto-institutions.png
diff --git a/lib/data/AppData/facto-logo.png b/lib/assets/facto-logo.png
similarity index 100%
rename from lib/data/AppData/facto-logo.png
rename to lib/assets/facto-logo.png
diff --git a/lib/data/AppData/CharteFactoscope/facto-politique.png b/lib/assets/facto-politique.png
similarity index 100%
rename from lib/data/AppData/CharteFactoscope/facto-politique.png
rename to lib/assets/facto-politique.png
diff --git a/lib/data/AppData/CharteFactoscope/facto-sante.png b/lib/assets/facto-sante.png
similarity index 100%
rename from lib/data/AppData/CharteFactoscope/facto-sante.png
rename to lib/assets/facto-sante.png
diff --git a/lib/data/AppData/CharteFactoscope/facto-securite.png b/lib/assets/facto-securite.png
similarity index 100%
rename from lib/data/AppData/CharteFactoscope/facto-securite.png
rename to lib/assets/facto-securite.png
diff --git a/lib/data/AppData/CharteFactoscope/facto-societe.png b/lib/assets/facto-societe.png
similarity index 100%
rename from lib/data/AppData/CharteFactoscope/facto-societe.png
rename to lib/assets/facto-societe.png
diff --git a/lib/data/AppData/goals.png b/lib/assets/goals.png
similarity index 100%
rename from lib/data/AppData/goals.png
rename to lib/assets/goals.png
diff --git a/lib/data/AppData/CharteFactoscope/logo-factoscope.png b/lib/assets/logo-factoscope.png
similarity index 100%
rename from lib/data/AppData/CharteFactoscope/logo-factoscope.png
rename to lib/assets/logo-factoscope.png
diff --git a/lib/data/AppData/CharteFactoscope/logo-factoscope_seul.png b/lib/assets/logo-factoscope_seul.png
similarity index 100%
rename from lib/data/AppData/CharteFactoscope/logo-factoscope_seul.png
rename to lib/assets/logo-factoscope_seul.png
diff --git a/lib/assets/logo-factoscope_seul_2.png b/lib/assets/logo-factoscope_seul_2.png
new file mode 100644
index 0000000..b7d1ab3
Binary files /dev/null and b/lib/assets/logo-factoscope_seul_2.png differ
diff --git a/lib/assets/nothing2hide.jpg b/lib/assets/nothing2hide.jpg
new file mode 100644
index 0000000..b741dec
Binary files /dev/null and b/lib/assets/nothing2hide.jpg differ
diff --git a/lib/config.dart b/lib/config.dart
new file mode 100644
index 0000000..19fe283
--- /dev/null
+++ b/lib/config.dart
@@ -0,0 +1,25 @@
+import 'dart:io';
+import 'package:flutter_dotenv/flutter_dotenv.dart';
+
+class AppConfig {
+ static String get apiBaseUrlAndroidEmulator =>
+ dotenv.env['API_URL_ANDROID'] ?? 'http://10.0.2.2:8000';
+
+ static String get apiBaseUrlIosSimulator =>
+ dotenv.env['API_URL_IOS'] ?? 'http://localhost:8000';
+
+ static String get apiBaseUrlPhysicalDevice =>
+ dotenv.env['API_URL_PHYSICAL'] ?? 'http://192.168.1.X:8000';
+
+ static String get urlMedias =>
+ dotenv.env['URL_MEDIAS'] ?? '';
+
+ static int get apiTimeout =>
+ int.tryParse(dotenv.env['API_TIMEOUT'] ?? '"10') ?? 10;
+
+ static String get effectiveApiUrl {
+ if (Platform.isAndroid) return apiBaseUrlAndroidEmulator;
+ if (Platform.isIOS) return apiBaseUrlIosSimulator;
+ return apiBaseUrlAndroidEmulator;
+ }
+}
\ No newline at end of file
diff --git a/lib/data/AppData/CharteFactoscope/Couleurs et typos.md b/lib/data/AppData/CharteFactoscope/Couleurs et typos.md
deleted file mode 100644
index 2903655..0000000
--- a/lib/data/AppData/CharteFactoscope/Couleurs et typos.md
+++ /dev/null
@@ -1,27 +0,0 @@
-## Couleurs
-
-#### jaune
-
-#fcb330
-
-#### bleu
-
-#292460
-
-#### écriture
-
-#666
-
-## Typos
-
-#### titres
-
-
-
-#### highlights
-
-
-
-#### texte
-
-
\ No newline at end of file
diff --git a/lib/data/AppData/CharteFactoscope/logo-factoscope_seul_2.png b/lib/data/AppData/CharteFactoscope/logo-factoscope_seul_2.png
deleted file mode 100644
index 0b2ce7c..0000000
Binary files a/lib/data/AppData/CharteFactoscope/logo-factoscope_seul_2.png and /dev/null differ
diff --git a/lib/data/AppData/Module1/metadata.json b/lib/data/AppData/Module1/metadata.json
new file mode 100644
index 0000000..9b676f0
--- /dev/null
+++ b/lib/data/AppData/Module1/metadata.json
@@ -0,0 +1,5 @@
+{
+ "titre": "Module 1",
+ "urlImg": "assets/facto-societe.png",
+ "description": "Chaque citoyen a un rôle à jouer en matière de lutte contre la désinformation… À condition qu’il maîtrise les codes de son environnement informationnel : les sources à sa disposition, les fondements du travail journalistique, les rouages des réseaux sociaux numériques, les risques désinformationnels, etc. A nous tous de nous emparer de ces connaissances pour exercer pleinement et librement nos droits et devoirs de citoyens !"
+}
\ No newline at end of file
diff --git a/lib/data/AppData/Module2/metadata.json b/lib/data/AppData/Module2/metadata.json
new file mode 100644
index 0000000..eee9b09
--- /dev/null
+++ b/lib/data/AppData/Module2/metadata.json
@@ -0,0 +1,5 @@
+{
+ "titre": "Module 2",
+ "urlImg": "assets/facto-societe.png",
+ "description": "Chaque citoyen a un rôle à jouer en matière de lutte contre la désinformation… À condition qu’il maîtrise les codes de son environnement informationnel : les sources à sa disposition, les fondements du travail journalistique, les rouages des réseaux sociaux numériques, les risques désinformationnels, etc. A nous tous de nous emparer de ces connaissances pour exercer pleinement et librement nos droits et devoirs de citoyens !"
+}
\ No newline at end of file
diff --git a/lib/data/AppData/Module3/metadata.json b/lib/data/AppData/Module3/metadata.json
new file mode 100644
index 0000000..c16ce7c
--- /dev/null
+++ b/lib/data/AppData/Module3/metadata.json
@@ -0,0 +1,5 @@
+{
+ "titre": "Module 3",
+ "urlImg": "assets/facto-societe.png",
+ "description": "Chaque citoyen a un rôle à jouer en matière de lutte contre la désinformation… À condition qu’il maîtrise les codes de son environnement informationnel : les sources à sa disposition, les fondements du travail journalistique, les rouages des réseaux sociaux numériques, les risques désinformationnels, etc. A nous tous de nous emparer de ces connaissances pour exercer pleinement et librement nos droits et devoirs de citoyens !"
+}
\ No newline at end of file
diff --git a/lib/data/AppData/facto-societe.png b/lib/data/AppData/facto-societe.png
deleted file mode 100644
index 7aca33f..0000000
Binary files a/lib/data/AppData/facto-societe.png and /dev/null differ
diff --git a/lib/data/AppData/music.mp3 b/lib/data/AppData/music.mp3
deleted file mode 100644
index 9201688..0000000
Binary files a/lib/data/AppData/music.mp3 and /dev/null differ
diff --git a/lib/data/AppData/ok.txt b/lib/data/AppData/ok.txt
deleted file mode 100644
index 1bd8ee3..0000000
--- a/lib/data/AppData/ok.txt
+++ /dev/null
@@ -1 +0,0 @@
-etzteoajhtejrtyeatyear_t
\ No newline at end of file
diff --git a/lib/data/AppData/test.mp4 b/lib/data/AppData/test.mp4
deleted file mode 100644
index a4bf26b..0000000
Binary files a/lib/data/AppData/test.mp4 and /dev/null differ
diff --git a/lib/data/ArchiveBestPattern2QCM/question.txt b/lib/data/ArchiveBestPattern2QCM/question.txt
deleted file mode 100644
index e61ca26..0000000
--- a/lib/data/ArchiveBestPattern2QCM/question.txt
+++ /dev/null
@@ -1 +0,0 @@
-Qu'elle est la couleur du ciel ?
\ No newline at end of file
diff --git a/lib/data/ArchiveBestPattern2QCM/reponse1.txt b/lib/data/ArchiveBestPattern2QCM/reponse1.txt
deleted file mode 100644
index 2013e49..0000000
--- a/lib/data/ArchiveBestPattern2QCM/reponse1.txt
+++ /dev/null
@@ -1 +0,0 @@
-vert
\ No newline at end of file
diff --git a/lib/data/ArchiveBestPattern2QCM/reponse2.txt b/lib/data/ArchiveBestPattern2QCM/reponse2.txt
deleted file mode 100644
index aec3c84..0000000
--- a/lib/data/ArchiveBestPattern2QCM/reponse2.txt
+++ /dev/null
@@ -1 +0,0 @@
-bleu
\ No newline at end of file
diff --git a/lib/data/ArchiveBestPattern2QCM/reponse3.txt b/lib/data/ArchiveBestPattern2QCM/reponse3.txt
deleted file mode 100644
index 5923218..0000000
--- a/lib/data/ArchiveBestPattern2QCM/reponse3.txt
+++ /dev/null
@@ -1 +0,0 @@
-jaune
\ No newline at end of file
diff --git a/lib/data/ArchiveBestPattern2QCM/reponse4.txt b/lib/data/ArchiveBestPattern2QCM/reponse4.txt
deleted file mode 100644
index e672b18..0000000
--- a/lib/data/ArchiveBestPattern2QCM/reponse4.txt
+++ /dev/null
@@ -1 +0,0 @@
-je ne sais pas !
\ No newline at end of file
diff --git a/lib/data/ArchiveBestPattern2QCM/solution.txt b/lib/data/ArchiveBestPattern2QCM/solution.txt
deleted file mode 100644
index d8263ee..0000000
--- a/lib/data/ArchiveBestPattern2QCM/solution.txt
+++ /dev/null
@@ -1 +0,0 @@
-2
\ No newline at end of file
diff --git a/lib/data_initializer.dart b/lib/data_initializer.dart
index 5ea703f..c35fdc4 100644
--- a/lib/data_initializer.dart
+++ b/lib/data_initializer.dart
@@ -1,591 +1,325 @@
+import 'package:flutter/services.dart';
+import 'package:factoscope/models/module.dart';
+import 'package:factoscope/models/cours.dart';
+import 'package:factoscope/repositories/cours_repository.dart';
+import 'package:factoscope/repositories/module_repository.dart';
+import 'package:factoscope/repositories/page_repository.dart';
+import 'package:factoscope/ui/module_selectionne.dart';
+import 'package:factoscope/ui/cours_selectionne.dart';
+import 'package:factoscope/database_helper.dart';
import 'package:flutter/foundation.dart';
-import 'package:seriouse_game/models/module.dart';
-import 'package:seriouse_game/repositories/coursRepository.dart';
-
-import 'package:seriouse_game/repositories/moduleRepository.dart';
-import 'package:seriouse_game/repositories/minijeuRepository.dart';
-import 'package:seriouse_game/repositories/mediaCoursRepository.dart';
-import 'package:seriouse_game/repositories/objectifCoursRepository.dart';
-import 'package:seriouse_game/repositories/pageRepository.dart';
-
-import 'package:seriouse_game/repositories/QCM/QCMRepository.dart';
-import 'package:seriouse_game/repositories/QCM/QuestionRepository.dart';
-import 'package:seriouse_game/repositories/QCM/ReponseRepository.dart';
-import 'package:seriouse_game/ui/ModuleSelectionne.dart';
-
-import 'DataBase/database_helper.dart';
-import 'models/cours.dart';
-import 'models/mediaCours.dart';
-import 'models/objectifCours.dart';
-import 'models/page.dart';
-
-import 'models/QCM/qcm.dart';
-import 'models/QCM/question.dart';
-import 'models/QCM/reponse.dart';
-
-import 'package:seriouse_game/ui/CoursSelectionne.dart';
+import 'dart:convert';
final moduleRepository = ModuleRepository();
- final coursRepository = CoursRepository();
- final miniJeuRepository = MiniJeuRepository();
- final mediaCoursRepository = MediaCoursRepository();
- final pageRepository = PageRepository();
- final objectifCoursRepository = ObjectifCoursRepository();
-
- final questionRepo = QuestionRepository();
- final reponseRepo = ReponseRepository();
- final qcmRepo = QCMRepository();
+final coursRepository = CoursRepository();
+final pageRepository = PageRepository();
Future insertModule1() async {
- // Création du Module
- final module = Module(
- titre: 'Thématique 1',
- urlImg: 'lib/data/AppData/facto-societe.png',
- description: 'Chaque citoyen a un rôle à jouer en matière de lutte contre la désinformation… À condition qu’il maîtrise les codes de son environnement informationnel : les sources à sa disposition, les fondements du travail journalistique, les rouages des réseaux sociaux numériques, les risques désinformationnels, etc. A nous tous de nous emparer de ces connaissances pour exercer pleinement et librement nos droits et devoirs de citoyens !');
- final moduleId = await moduleRepository.create(module);
-
- // Création du Cours
- Cours cours = Cours(
- idModule: moduleId,
- titre: 'Les sources d’informations',
- contenu: 'Comprendre et évaluer les sources d’information.');
- final coursId = await coursRepository.create(cours);
-
- // Ajout des Objectifs du Cours
- final objectif1 = ObjectifCours(
- idCours: coursId,
- description: 'Comprendre les différents types de sources d’information',
- );
- final objectif2 = ObjectifCours(
- idCours: coursId,
- description: 'Savoir évaluer la crédibilité d’une source',
- );
- final objectif3 = ObjectifCours(
- idCours: coursId,
- description: 'Identifier les signes de désinformation',
- );
-
- await objectifCoursRepository.create(objectif1);
- await objectifCoursRepository.create(objectif2);
- await objectifCoursRepository.create(objectif3);
-
- // Page 1 : Introduction aux sources d'information
- Page page1 = Page(idCours: coursId, ordre: 1, description: "Qu'est-ce qu'une source d'information ?");
- int pageId1 = await pageRepository.create(page1);
-
- await mediaCoursRepository.create(MediaCours(
- idPage: pageId1,
- ordre: 1,
- url: 'lib/data/AppData/Module1/Cours1/source_information_definition.txt',
- type: 'text'));
-
- await mediaCoursRepository.create(MediaCours(
- idPage: pageId1,
- ordre: 2,
- url: 'lib/data/AppData/Module1/Cours1/journaliste_interview.jpg',
- type: 'image',
- caption: 'Journaliste réalisant une interview'));
-
- // Page 2 : Les différentes sources
- Page page2 = Page(idCours: coursId, ordre: 2, description: "Types de sources d'information");
- int pageId2 = await pageRepository.create(page2);
-
- await mediaCoursRepository.create(MediaCours(
- idPage: pageId2,
- ordre: 1,
- url: 'lib/data/AppData/Module1/Cours1/types_sources.txt',
- type: 'text'));
-
- await mediaCoursRepository.create(MediaCours(
- idPage: pageId2,
- ordre: 2,
- url: 'lib/data/AppData/Module1/Cours1/source_primaire_secondaire.png',
- type: 'image',
- caption: 'Illustration des sources primaires et secondaires'));
-
- // Page 3 : Évaluer la crédibilité d'une source
- Page page3 = Page(idCours: coursId, ordre: 3, description: "Comment vérifier la fiabilité d'une source ?");
- int pageId3 = await pageRepository.create(page3);
-
- await mediaCoursRepository.create(MediaCours(
- idPage: pageId3,
- ordre: 1,
- url: 'lib/data/AppData/Module1/Cours1/evaluer_sources.txt',
- type: 'text'));
-
- await mediaCoursRepository.create(MediaCours(
- idPage: pageId3,
- ordre: 2,
- url: 'lib/data/AppData/Module1/Cours1/fake_news_verification.png',
- type: 'image',
- caption: 'Techniques de vérification des fake news'));
-
- /// Données de test pour les QCM
- List testQCMs = [
- QCM(
- id: 1,
- numSolution: 2,
- idCours: 1,
- idQuestion: 1,
- question:
- Question(
- id: 1,
- text: "Quel est le principal indicateur de la fiabilité d’une source d’information ?",
- type: "text",
- ),
-
- reponses: [
- Reponse(id: 1, idQCM: 1, text: "Sa popularité sur les réseaux sociaux", type: "text"),
- Reponse(id: 2, idQCM: 1, text: "La vérifiabilité des informations par d’autres sources fiables", type: "text"),
- Reponse(id: 3, idQCM: 1, text: "Le nombre de commentaires sous l’article", type: "text"),
- Reponse(id: 4, idQCM: 1, text: "Le design du site web", type: "text"),
- ],
- ),
- QCM(
- id: 2,
- numSolution: 2,
- idCours: 1,
- idQuestion: 2,
- question:
- Question(
- id: 2,
- text: "Quelle est la meilleure manière de vérifier une information trouvée en ligne ?",
- type: "text",
- ),
-
- reponses: [
- Reponse(id: 5, idQCM: 2, text: "La partager immédiatement avec ses amis", type: "text"),
- Reponse(id: 6, idQCM: 2, text: "Consulter plusieurs sources fiables et vérifier la cohérence de l’information", type: "text"),
- Reponse(id: 7, idQCM: 2, text: "Faire confiance à la première source trouvée", type: "text"),
- Reponse(id: 8, idQCM: 2, text: "Vérifier si l’information est amusante avant de la croire", type: "text"),
- ],
- ),
- QCM(
- id: 3,
- numSolution: 2,
- idCours: 1,
- idQuestion: 3,
- question:
- Question(
- id: 3,
- text: "Quel est un signe révélateur d’une fausse information ?",
- type: "text",
- ),
-
- reponses: [
- Reponse(id: 9, idQCM: 3, text: "Elle provient d’un média reconnu et sérieux", type: "text"),
- Reponse(id: 10, idQCM: 3, text: "Elle utilise un ton sensationnaliste et manque de sources vérifiables", type: "text"),
- Reponse(id: 11, idQCM: 3, text: "Elle cite plusieurs experts et références", type: "text"),
- Reponse(id: 12, idQCM: 3, text: "Elle est reprise par plusieurs médias de confiance", type: "text"),
- ],
- ),
- ];
-
- // Insertion des qcm dans la bdd
- for (var qcm in testQCMs) {
- await qcmRepo.insert(qcm);
- await questionRepo.insert(qcm.question!);
-
- for (var reponse in qcm.reponses!) {
- await reponseRepo.insert(reponse);
- }
- }
-
-
-
-
-
-
- //ajout d'un autre cours
-
- cours = Cours(
- idModule: moduleId,
- titre: 'Genres journalistiques',
- contenu: 'Découvrir les genres journalistiques.');
-
- final coursId2 = await coursRepository.create(cours);
-
- // Ajout des Objectifs du Cours
- final objectif4 = ObjectifCours(
- idCours: coursId2,
- description: 'Les genres d\'information',
- );
- final objectif5 = ObjectifCours(
- idCours: coursId2,
- description: 'Les genres d\'opinion',
- );
-
-
- await objectifCoursRepository.create(objectif4);
- await objectifCoursRepository.create(objectif5);
-
- // Page 4 : Les differents genres d'information
- Page page4 = Page(idCours: coursId2, ordre: 1, description: "Qu'elle sont les genres d'information ?",urlAudio: 'lib/data/AppData/Module1/Cours1/genre_d_information.mp3');
- int pageId4 = await pageRepository.create(page4);
-
- await mediaCoursRepository.create(MediaCours(
- idPage: pageId4,
- ordre: 1,
- url: 'lib/data/AppData/Module1/Cours1/genre_d_information.txt',
- type: 'text'));
-
- await mediaCoursRepository.create(MediaCours(
- idPage: pageId4,
- ordre: 2,
- url: 'lib/data/AppData/Module1/Cours1/genre_d_information.jpg',
- type: 'image',
- caption: 'Les genres d\'information'));
-
- await mediaCoursRepository.create(MediaCours(
- idPage: pageId4,
- ordre : 3,
- url : 'lib/data/AppData/Module1/Cours1/genre_d_information2.txt',
- type: 'text',
- ));
-
- // Page 5 : Les différents genres d'opinion
- Page page5 = Page(idCours: coursId2, ordre: 2, description: "Les genres d'opinion");
- int pageId5 = await pageRepository.create(page5);
-
- await mediaCoursRepository.create(MediaCours(
- idPage: pageId5,
- ordre: 1,
- url: 'lib/data/AppData/Module1/Cours1/genre_opinion.mp4',
- type: 'video'));
-
-
-
+ final String response =
+ await rootBundle.loadString('lib/data/AppData/Module1/metadata.json');
+ final moduleData = await json.decode(response);
-
-
- // Ajout des autres cours
-
-
- cours = Cours(
- idModule: moduleId,
- titre: 'Réseaux sociaux',
- contenu: '');
- await coursRepository.create(cours);
-
- cours = Cours(
- idModule: moduleId,
- titre: 'Désinformation/Mésinformation',
- contenu: '');
- await coursRepository.create(cours);
-}
-
-Future insertModule2() async {
- // Création du Module
final module = Module(
- titre: 'Thématique 2',
- urlImg: 'lib/data/AppData/facto-societe.png',
- description: 'Grâce aux technologies modernes, tout le monde est aujourd’hui en mesure de diffuser des informations et de produire des contenus. Mais tout le monde n’a pas appris les codes, règles et enjeux d’une information responsable à destination du grand public. Que vous ayez 1 à 1 million de followers, ce module est fait pour vous !');
- final moduleId = await moduleRepository.create(module);
-
- // Création des Cours
- Cours cours = Cours(
- idModule: moduleId,
- titre: 'Ethique professionnelle et personnelle',
- contenu: '');
+ titre: moduleData['titre'],
+ urlImg: moduleData['urlImg'] ?? 'assets/facto-societe.png',
+ description: moduleData['description']);
+ await moduleRepository.create(module);
+
+ // Cours cours = Cours(
+ // idModule: moduleId,
+ // titre: 'Les sources d\'informations',
+ // contenu: 'Comprendre et évaluer les sources d\'information.',
+ // description: 'Description des sources d\'informations.');
// final coursId = await coursRepository.create(cours);
+ //
+ // // Page 1 : Introduction aux sources d'information
+ // Page page1 = Page(
+ // idCours: coursId,
+ // description: "Qu'est-ce qu'une source d'information ?",
+ // medias: [
+ // MediaItem(
+ // ordre: 1,
+ // url: 'lib/data/AppData/Module1/Cours1/source_information_definition.txt',
+ // type: 'text',
+ // ),
+ // MediaItem(
+ // ordre: 2,
+ // url: 'lib/data/AppData/Module1/Cours1/journaliste_interview.jpg',
+ // type: 'image',
+ // caption: 'Journaliste réalisant une interview',
+ // ),
+ // ],
+ // );
+ // await pageRepository.create(page1);
+ //
+ // // Page 2 : Les différentes sources
+ // Page page2 = Page(
+ // idCours: coursId,
+ // description: "Types de sources d'information",
+ // medias: [
+ // MediaItem(
+ // ordre: 1,
+ // url: 'lib/data/AppData/Module1/Cours1/types_sources.txt',
+ // type: 'text',
+ // ),
+ // MediaItem(
+ // ordre: 2,
+ // url: 'lib/data/AppData/Module1/Cours1/source_primaire_secondaire.png',
+ // type: 'image',
+ // caption: 'Illustration des sources primaires et secondaires',
+ // ),
+ // ],
+ // );
+ // await pageRepository.create(page2);
+ //
+ // // Page 3 : Évaluer la crédibilité d'une source
+ // Page page3 = Page(
+ // idCours: coursId,
+ // description: "Comment vérifier la fiabilité d'une source ?",
+ // medias: [
+ // MediaItem(
+ // ordre: 1,
+ // url: 'lib/data/AppData/Module1/Cours1/evaluer_sources.txt',
+ // type: 'text',
+ // ),
+ // MediaItem(
+ // ordre: 2,
+ // url: 'lib/data/AppData/Module1/Cours1/fake_news_verification.png',
+ // type: 'image',
+ // caption: 'Techniques de vérification des fake news',
+ // ),
+ // ],
+ // );
+ // await pageRepository.create(page3);
+ //
+ // await _insertQCMForCours1(coursId);
+ // await _insertClozeCours1(coursId);
+ //
+ // Cours cours2 = Cours(
+ // idModule: moduleId,
+ // titre: 'COURS 2',
+ // contenu: 'Comprendre le cours 2',
+ // description: 'Description du cours 2 oui oui oui.');
+ // final coursId2 = await coursRepository.create(cours2);
+ //
+ // Page page11 = Page(
+ // idCours: coursId2,
+ // description: "Description 1",
+ // medias: [
+ // MediaItem(
+ // ordre: 1,
+ // url: 'lib/data/AppData/Module1/Cours2/genre_d_information.txt',
+ // type: 'text',
+ // ),
+ // MediaItem(
+ // ordre: 2,
+ // url: 'lib/data/AppData/Module1/Cours2/genre_d_information.jpg',
+ // type: 'image',
+ // caption: 'Journaliste réalisant une interview',
+ // ),
+ // ],
+ // );
+ // await pageRepository.create(page11);
+ //
+ // Page page22 = Page(
+ // idCours: coursId2,
+ // description: "Description 2",
+ // medias: [
+ // MediaItem(
+ // ordre: 1,
+ // url: 'lib/data/AppData/Module1/Cours2/genre_d_information.txt',
+ // type: 'text',
+ // ),
+ // MediaItem(
+ // ordre: 2,
+ // url: 'lib/data/AppData/Module1/Cours2/genre_d_information.mp3',
+ // type: 'audio',
+ // caption: 'Illustration des sources primaires et secondaires',
+ // ),
+ // ],
+ // );
+ // await pageRepository.create(page22);
+ //
+ // Page page33 = Page(
+ // idCours: coursId2,
+ // description: "Comment vérifier la fiabilité d'une source ?",
+ // medias: [
+ // MediaItem(
+ // ordre: 1,
+ // url: 'lib/data/AppData/Module1/Cours2/genre_d_information.txt',
+ // type: 'text',
+ // ),
+ // MediaItem(
+ // ordre: 2,
+ // url: 'lib/data/AppData/Module1/Cours2/genre_opinion.mp4',
+ // type: 'video',
+ // caption: 'Techniques de vérification des fake news',
+ // ),
+ // ],
+ // );
+ // await pageRepository.create(page33);
+}
- cours = Cours(
- idModule: moduleId,
- titre: 'Journalisme et production de contenus',
- contenu: '');
- await coursRepository.create(cours);
+// Future _insertClozeCours1(int coursId) async {
+// final repo = ClozeRepository();
+//
+// await repo.insert(
+// ClozeQuestion(
+// phrase: "Le principal indicateur de la fiabilité d'une source d'information est la __________ des informations par d'autres sources fiables.",
+// rep1: "popularité sur les réseaux sociaux",
+// rep2: "vérifiabilité",
+// rep3: "nombre de commentaires sous l\'article",
+// rep4: "design du site web",
+// soluce: 2,
+// idCours: coursId),
+// );
+//
+// await repo.insert(
+// ClozeQuestion(
+// phrase: "La meilleure manière de vérifier une information trouvée en ligne est de __________ plusieurs sources fiables et vérifier la cohérence de l'information.",
+// rep1: "la partager immédiatement avec ses amis",
+// rep2: "consulter",
+// rep3: "faire confiance à la première source trouvée",
+// rep4: "vérifier si l\'information est amusante avant de la croire",
+// soluce: 2,
+// idCours: coursId),
+// );
+//
+// await repo.insert(
+// ClozeQuestion(
+// phrase: "Un signe révélateur d'une fausse information est qu'elle __________ un ton sensationnaliste et manque de sources vérifiables.",
+// rep1: "provient d\'un média reconnu et sérieux",
+// rep2: "utilise",
+// rep3: "cite plusieurs experts et références",
+// rep4: "est reprise par plusieurs médias de confiance",
+// soluce: 2,
+// idCours: coursId),
+// );
+// }
+//
+// Future _insertQCMForCours1(int coursId) async {
+// final db = await DatabaseHelper.instance.database;
+//
+// // QCM 1
+// await db.insert('qcm', {
+// 'question': "Quel est le principal indicateur de la fiabilité d'une source d'information ?",
+// 'rep1': 'Sa popularité sur les réseaux sociaux',
+// 'rep2': 'La vérifiabilité des informations par d\'autres sources fiables',
+// 'rep3': 'Le nombre de commentaires sous l\'article',
+// 'rep4': 'Le design du site web',
+// 'soluce': 2,
+// 'id_cours': coursId,
+// });
+//
+// // QCM 2
+// await db.insert('qcm', {
+// 'question': 'Quelle est la meilleure manière de vérifier une information trouvée en ligne ?',
+// 'rep1': 'La partager immédiatement avec ses amis',
+// 'rep2': 'Consulter plusieurs sources fiables et vérifier la cohérence de l\'information',
+// 'rep3': 'Faire confiance à la première source trouvée',
+// 'rep4': 'Vérifier si l\'information est amusante avant de la croire',
+// 'soluce': 2,
+// 'id_cours': coursId,
+// });
+//
+// // QCM 3
+// await db.insert('qcm', {
+// 'question': 'Quel est un signe révélateur d\'une fausse information ?',
+// 'rep1': 'Elle provient d\'un média reconnu et sérieux',
+// 'rep2': 'Elle utilise un ton sensationnaliste et manque de sources vérifiables',
+// 'rep3': 'Elle cite plusieurs experts et références',
+// 'rep4': 'Elle est reprise par plusieurs médias de confiance',
+// 'soluce': 2,
+// 'id_cours': coursId,
+// });
+// }
- cours = Cours(
- idModule: moduleId,
- titre: 'Risques économiques et sociétaux',
- contenu: '');
- await coursRepository.create(cours);
+Future insertModule2() async {
+ final String response =
+ await rootBundle.loadString('lib/data/AppData/Module2/metadata.json');
+ final moduleData = await json.decode(response);
- cours = Cours(
- idModule: moduleId,
- titre: 'EMI - Education aux médias et à l’information',
- contenu: '');
- await coursRepository.create(cours);
+ final module = Module(
+ titre: moduleData['titre'],
+ urlImg: moduleData['urlImg'] ?? 'assets/facto-societe.png',
+ description: moduleData['description']);
+ await moduleRepository.create(module);
}
Future insertModule3() async {
- // Création du Module
- final module = Module(
- titre: 'Thématique 3',
- urlImg: 'lib/data/AppData/facto-societe.png',
- description: 'Les journalistes sont des professionnels de l’information. Pourtant, face à la profusion des sources et, parfois aussi, à l’urgence des situations, ils ne maîtrisent pas tous les clés d’une information traitée éthiquement, professionnellement et de manière responsable. Pourquoi ne pas profiter de ce module pour réviser ses classiques, voire en apprendre davantage sur les techniques de vérification les plus performantes ?'
- );
- final moduleId = await moduleRepository.create(module);
-
- // Création des Cours
- Cours cours = Cours(
- idModule: moduleId,
- titre: 'Déontologie',
- contenu: '');
- // final coursId = await coursRepository.create(cours);
-
- cours = Cours(
- idModule: moduleId,
- titre: 'Osint et Investigation numérique',
- contenu: '');
- await coursRepository.create(cours);
-
- cours = Cours(
- idModule: moduleId,
- titre: 'SR et fact-checking',
- contenu: '');
- await coursRepository.create(cours);
-
- cours = Cours(
- idModule: moduleId,
- titre: 'EMI - Education aux médias et à l’information',
- contenu: '');
- await coursRepository.create(cours);
+ final String response =
+ await rootBundle.loadString('lib/data/AppData/Module3/metadata.json');
+ final moduleData = await json.decode(response);
-}
-
-Future insertModule4() async {
- // Création du Module
final module = Module(
- titre: 'Pour aller plus loin',
- urlImg: 'lib/data/AppData/facto-societe.png',
- description: 'Toutes les références et ressources en relation avec l\'Éducation aux médias et à l’information sont répertoriées ici. '
- );
- final moduleId = await moduleRepository.create(module);
-
- // Création des Cours
- Cours cours = Cours(
- idModule: moduleId,
- titre: 'Références bibliographiques',
- contenu: '');
- // final coursId = await coursRepository.create(cours);
-
- cours = Cours(
- idModule: moduleId,
- titre: 'Ressources en ligne',
- contenu: '');
- await coursRepository.create(cours);
+ titre: moduleData['titre'],
+ urlImg: moduleData['urlImg'] ?? 'assets/facto-societe.png',
+ description: moduleData['description']);
+ await moduleRepository.create(module);
}
Future insertSampleData() async {
- await DatabaseHelper.instance.resetDatabase();
-
- insertModule1();
- insertModule2();
- insertModule3();
- insertModule4();
+ final hasData = await _checkIfDatabaseHasData();
- // Init du singleton CoursSelectionne
- CoursSelectionne coursSelectionne = CoursSelectionne.instance;
- List lstCours = await coursRepository.getAll();
- coursSelectionne.setCours(lstCours[0]);
-
- // Init du singleton ModuleSelectionne
- ModuleSelectionne moduleSelectionne = ModuleSelectionne.instance;
- List lstModule = await moduleRepository.getAll();
- moduleSelectionne.moduleSelectionne = lstModule[0];
-
- /*
- // Création de Mots (Mots pour le MotsCroises)
- final mot1 = Mot(
- idMotsCroises: 1,
- mot: 'journalisme',
- indice: 'Domaine d’étude',
- direction: 'horizontal',
- positionDepartX: 0,
- positionDepartY: 0);
- final mot2 = Mot(
- idMotsCroises: 1,
- mot: 'presse',
- indice: 'Média écrit',
- direction: 'vertical',
- positionDepartX: 1,
- positionDepartY: 1);
- await motRepository.create(mot1);
- await motRepository.create(mot2);
-
- // Création de MotsCroises
- final motsCroises = MotsCroises(idMiniJeu: 1, tailleGrille: '10x10');
- final motsCroisesId = await motsCroisesRepository.create(motsCroises);
-
- // Création d'un MiniJeu
- final miniJeu = MiniJeu(
- idCours: coursId,
- nom: 'Jeu de mots croisés',
- description: 'Mini-jeu de mots croisés sur le journalisme',
- progression: 0);
- final miniJeuId = await miniJeuRepository.create(miniJeu);
- */
-
- if (kDebugMode) {
- print('Toutes les données d\'exemple ont été insérées avec succès.');
- }
- //testRepositories();
-}
-
-Future testRepositories() async {
- final moduleRepository = ModuleRepository();
- final coursRepository = CoursRepository();
- final miniJeuRepository = MiniJeuRepository();
- final mediaCoursRepository = MediaCoursRepository();
- final pageRepository = PageRepository();
- final objectifCoursRepository = ObjectifCoursRepository();
-
- // --- Test Objectif ---
- if (kDebugMode) {
- print('--- Test Objectif ---');
- }
-
- // Récupérer tous les objectifs
- final allObjectifs = await objectifCoursRepository.getAll();
- if (kDebugMode) {
- print('Objectifs disponibles : ${allObjectifs.map((e) => e.description).toList()}');
- }
-
- // Récupérer un objectif par ID
- final objectif = allObjectifs.first;
- final fetchedObjectif = await objectifCoursRepository.getById(objectif.id!);
- if (kDebugMode) {
- print('Objectif récupéré par ID : ${fetchedObjectif?.description}');
- }
-
- // Supprimer un objectif
- await objectifCoursRepository.delete(objectif.id!);
- if (kDebugMode) {
- print('Objectif supprimé.');
- }
-
- // --- Test MiniJeu ---
- if (kDebugMode) {
- print('--- Test MiniJeu ---');
- }
-
- // Récupérer tous les mini-jeux
- final allMiniJeux = await miniJeuRepository.getAll();
- if (kDebugMode) {
- print('Mini-jeux disponibles : ${allMiniJeux.map((e) => e.nom).toList()}');
- }
-
- // Récupérer un mini-jeu par ID
- final miniJeu = allMiniJeux.first;
- final fetchedMiniJeu = await miniJeuRepository.getById(miniJeu.id!);
- if (kDebugMode) {
- print('Mini-jeu récupéré par ID : ${fetchedMiniJeu?.nom}');
- }
-
- // Supprimer un mini-jeu
- await miniJeuRepository.delete(miniJeu.id!);
- if (kDebugMode) {
- print('Mini-jeu supprimé.');
- }
-
- // --- Test MediaCours ---
- if (kDebugMode) {
- print('--- Test MediaCours ---');
- }
-
- // Récupérer tous les médias
- final allMedias = await mediaCoursRepository.getAll();
- if (kDebugMode) {
- print('Médias disponibles : ${allMedias.map((e) => e.url).toList()}');
- }
-
- // Récupérer un média par ID
- final media = allMedias.first;
- final fetchedMedia = await mediaCoursRepository.getById(media.id!);
- if (kDebugMode) {
- print('Média récupéré par ID : ${fetchedMedia?.url}');
- }
-
- // Supprimer un média
- //await mediaCoursRepository.delete(media.id!);
- //print('Média supprimé.');
-
- // --- Test Page ---
- if (kDebugMode) {
- print('--- Test Page ---');
- }
-
-// Récupérer toutes les pages
- final allPages = await pageRepository.getAll();
- if (kDebugMode) {
- print('Pages disponibles : ${allPages.map((e) => e.id).toList()}');
- }
-
-// Récupérer une page par ID
- if (allPages.isNotEmpty) {
- final page = allPages.first;
- final fetchedPage = await pageRepository.getById(page.id!);
+ if (!hasData) {
if (kDebugMode) {
- print('Page récupérée par ID : ${fetchedPage?.id} liée au cours : ${fetchedPage?.idCours}');
+ print('Première installation - Création des données de base');
}
-
- // Supprimer une page
- //await pageRepository.delete(page.id!);
- //print('Page supprimée.');
+ await insertModule1();
+ await insertModule2();
+ await insertModule3();
} else {
if (kDebugMode) {
- print('Aucune page disponible pour le test.');
+ print('Base de données existante chargée');
}
}
- // --- Test Cours ---
- if (kDebugMode) {
- print('--- Test Cours ---');
- }
-
- // Récupérer toutes les courss
- final allCours = await coursRepository.getAll();
- if (kDebugMode) {
- print('Cours disponibles : ${allCours.map((e) => e.titre).toList()}');
+ CoursSelectionne coursSelectionne = CoursSelectionne.instance;
+ List lstCours = await coursRepository.getAll();
+ if (lstCours.isNotEmpty) {
+ coursSelectionne.setCours(lstCours[0]);
}
- // Récupérer une cours par ID
- final cours = allCours.first;
- final fetchedCours = await coursRepository.getById(cours.id!);
if (kDebugMode) {
- print('Cours récupérée par ID : ${fetchedCours?.titre}');
+ print(coursSelectionne);
}
- // méthode loadContenu(Cours cours)
- cours.pages = await pageRepository.getPagesByCourseId(cours.id!);
- if (kDebugMode) {
- print("Nombre de page récupéré : ${cours.pages?.length}");
+ // Init du singleton ModuleSelectionne
+ ModuleSelectionne moduleSelectionne = ModuleSelectionne.instance;
+ List lstModule = await moduleRepository.getAll();
+ if (lstModule.isNotEmpty) {
+ moduleSelectionne.moduleSelectionne = lstModule[0];
}
+}
- for (int i=0; i _checkIfDatabaseHasData() async {
+ try {
+ final cours = await coursRepository.getAll();
+ if (cours.isNotEmpty) {
+ return true;
}
- // Supprimer une cours
- await coursRepository.delete(cours.id!);
- if (kDebugMode) {
- print('Cours supprimée.');
- }
- // --- Test Module ---
- if (kDebugMode) {
- print('--- Test Module ---');
- }
+ final modules = await moduleRepository.getAll();
+ if (modules.isNotEmpty) {
+ return true;
+ }
- // Récupérer tous les module
- final allModulees = await moduleRepository.getAll();
- if (kDebugMode) {
- print('Module disponibles : ${allModulees.map((e) => e.titre).toList()}');
+ return false;
+ } catch (e) {
+ if (kDebugMode) {
+ print('Erreur lors de la vérification de la BDD: $e');
+ }
+ return false;
}
+}
- // Récupérer un module par ID
- final module = allModulees.first;
- final fetchedModule = await moduleRepository.getById(module.id!);
- if (kDebugMode) {
- print('Module récupéré par ID : ${fetchedModule?.titre}');
- }
+Future resetDatabaseForDebug() async {
+ await DatabaseHelper.instance.resetDB();
+ await insertModule1();
+ await insertModule2();
+ await insertModule3();
- // Supprimer un module
- await moduleRepository.delete(module.id!);
if (kDebugMode) {
- print('Module supprimé.');
+ print('Base de données réinitialisée');
}
-}
+}
\ No newline at end of file
diff --git a/lib/database_helper.dart b/lib/database_helper.dart
new file mode 100644
index 0000000..d7697d3
--- /dev/null
+++ b/lib/database_helper.dart
@@ -0,0 +1,110 @@
+import 'package:sqflite/sqflite.dart';
+import 'package:path/path.dart';
+
+class DatabaseHelper {
+ static final DatabaseHelper instance = DatabaseHelper._init();
+ static Database? _database;
+
+ DatabaseHelper._init();
+
+ Future get database async {
+ if (_database != null) return _database!;
+ _database = await _initDB('app.db');
+ return _database!;
+ }
+
+ Future _initDB(String filePath) async {
+ final dbPath = await getDatabasesPath();
+ final path = join(dbPath, filePath);
+ return await openDatabase(
+ path,
+ version: 1,
+ onOpen: (db) async {
+ await _createDB(db, 1);
+ },
+ );
+ }
+
+ Future _createDB(Database db, int version) async {
+ // Table Module
+ await db.execute('''
+ CREATE TABLE IF NOT EXISTS module (
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
+ titre TEXT NOT NULL,
+ description TEXT NOT NULL,
+ urlImg TEXT
+ );
+ ''');
+
+ // Table Cours
+ await db.execute('''
+ CREATE TABLE IF NOT EXISTS cours (
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
+ titre TEXT NOT NULL,
+ description TEXT NOT NULL,
+ contenu TEXT NOT NULL,
+ id_module INTEGER,
+ last_updated TEXT,
+ is_downloaded INTEGER DEFAULT 0,
+ FOREIGN KEY (id_module) REFERENCES module (id) ON DELETE CASCADE
+ );
+ ''');
+
+ // Table Page avec medias en JSON
+ await db.execute('''
+ CREATE TABLE IF NOT EXISTS page (
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
+ description TEXT,
+ contenu TEXT,
+ medias TEXT,
+ est_vue INTEGER DEFAULT 0,
+ id_cours INTEGER NOT NULL,
+ FOREIGN KEY (id_cours) REFERENCES cours (id) ON DELETE CASCADE
+ );
+ ''');
+
+ // Table QCM
+ await db.execute('''
+ CREATE TABLE IF NOT EXISTS qcm (
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
+ question TEXT NOT NULL,
+ rep1 TEXT NOT NULL,
+ rep2 TEXT NOT NULL,
+ rep3 TEXT NOT NULL,
+ rep4 TEXT NOT NULL,
+ soluce INTEGER NOT NULL,
+ id_cours INTEGER NOT NULL,
+ FOREIGN KEY (id_cours) REFERENCES cours (id) ON DELETE CASCADE
+ );
+ ''');
+
+ await db.execute('''
+ CREATE TABLE IF NOT EXISTS Cloze (
+ idCloze INTEGER PRIMARY KEY AUTOINCREMENT,
+ phrase TEXT NOT NULL,
+ idCours INTEGER NOT NULL,
+ rep1 TEXT NOT NULL,
+ rep2 TEXT NOT NULL,
+ rep3 TEXT NOT NULL,
+ rep4 TEXT NOT NULL,
+ soluce INTEGER NOT NULL,
+ FOREIGN KEY(idCours) REFERENCES cours(id)
+ );
+''');
+
+ }
+
+ Future resetDB() async {
+ final dbPath = await getDatabasesPath();
+ final path = join(dbPath, 'app.db');
+ await deleteDatabase(path);
+ _database = await _initDB('app.db');
+ }
+
+ Future close() async {
+ final db = _database;
+ if (db != null) {
+ await db.close();
+ }
+ }
+}
\ No newline at end of file
diff --git a/lib/logic/ProgressionUseCase.dart b/lib/logic/progression_use_case.dart
similarity index 79%
rename from lib/logic/ProgressionUseCase.dart
rename to lib/logic/progression_use_case.dart
index 08cadbd..edbaa82 100644
--- a/lib/logic/ProgressionUseCase.dart
+++ b/lib/logic/progression_use_case.dart
@@ -1,12 +1,16 @@
+import 'package:factoscope/repositories/cours_repository.dart';
+import 'package:factoscope/repositories/module_repository.dart';
+import 'package:factoscope/repositories/page_repository.dart';
import 'package:flutter/foundation.dart';
-import 'package:seriouse_game/repositories/coursRepository.dart';
-import 'package:seriouse_game/repositories/moduleRepository.dart';
-import 'package:seriouse_game/repositories/pageRepository.dart';
+
+import '../models/cours.dart';
+import '../repositories/Cloze/cloze_repository.dart';
class ProgressionUseCase {
final pageRepository = PageRepository();
final coursRepository = CoursRepository();
- final moduleRepository = ModuleRepository();
+ final moduleRepository = ModuleRepository();
+ final ClozeRepository _repository = ClozeRepository();
ProgressionUseCase();
@@ -28,7 +32,8 @@ class ProgressionUseCase {
return pourcentage;
} catch (e) {
if (kDebugMode) {
- print("Erreur lors du calcul du pourcentage de progression globale : $e");
+ print(
+ "Erreur lors du calcul du pourcentage de progression globale : $e");
}
return 0;
}
@@ -52,7 +57,8 @@ class ProgressionUseCase {
return pourcentage;
} catch (e) {
if (kDebugMode) {
- print("Erreur lors du calcul du pourcentage de progression de module : $e");
+ print(
+ "Erreur lors du calcul du pourcentage de progression de module : $e");
}
return 0;
}
@@ -69,7 +75,7 @@ class ProgressionUseCase {
// Calcul du pourcentage de pages vues
double pourcentage;
- if (totalPages>0) {
+ if (totalPages > 0) {
pourcentage = (pagesVues / totalPages) * 100;
} else {
pourcentage = 0;
@@ -84,6 +90,12 @@ class ProgressionUseCase {
}
}
+ Future getNombrePageDeCloze(Cours cours) async {
+ final clozes =
+ await _repository.getByCoursId(cours.id!);
+ return clozes.length;
+ }
+
// Méthode pour récupérer le pourcentage de pages vues pour un cours donné en passant l'ID du cours en paramètre
Future calculerProgressionActuelleCours(int coursId, int page) async {
try {
diff --git a/lib/main.dart b/lib/main.dart
index cd344a7..3ea3f74 100644
--- a/lib/main.dart
+++ b/lib/main.dart
@@ -1,41 +1,92 @@
import 'package:flutter/material.dart';
-import 'package:seriouse_game/service_locator.dart';
+import 'package:factoscope/service_locator.dart';
import 'data_initializer.dart';
+import 'package:flutter_dotenv/flutter_dotenv.dart';
-import 'ui/App.dart';
+import 'ui/app.dart';
-void main() {
+Future main() async {
+ await dotenv.load(fileName: ".env");
setupLocator();
runApp(const MainApp());
- //runApp(MyApp());
}
class MainApp extends StatelessWidget {
const MainApp({super.key});
@override
- Widget build(BuildContext context) {
- // FutureBuilder permet d'attendre que les données d'exemple soient insérés avant le lancement de l'UI
+ Widget build(BuildContext context) {
return FutureBuilder(
- future: insertSampleData(), // Insertion des données dans la bdd
- builder: (context, snapshot) {
- switch (snapshot.connectionState) {
- case ConnectionState.done: // L'insertion est fini :
- return MaterialApp.router( // Voir App.dart pour avoir le routeur et le 1er widget de l'app
- //debugShowCheckedModeBanner: false,
- routerConfig: router,
- );
-
- default: // L'insertion n'a pas fini : Page d'attente #TODO
- return const CircularProgressIndicator();
- }
-
- }
- );
+ // future: insertSampleData(),
+ future: resetDatabaseForDebug(),
+ builder: (context, snapshot) {
+ if (snapshot.connectionState == ConnectionState.done) {
+ return MaterialApp.router(
+ routerConfig: router,
+ debugShowCheckedModeBanner: false,
+ );
+ } else {
+ return MaterialApp(
+ debugShowCheckedModeBanner: false,
+ home: Scaffold(
+ backgroundColor: Colors.white,
+ body: Center(
+ child: Column(
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: [
+ const Icon(
+ Icons.school,
+ size: 80,
+ color: Color.fromARGB(255, 236, 187, 139),
+ ),
+ const SizedBox(height: 24),
+ const Text(
+ 'Factoscope',
+ style: TextStyle(
+ fontSize: 28,
+ fontWeight: FontWeight.bold,
+ color: Colors.black87,
+ ),
+ ),
+ const SizedBox(height: 40),
+ const SizedBox(
+ width: 40,
+ height: 40,
+ child: CircularProgressIndicator(
+ strokeWidth: 3,
+ valueColor: AlwaysStoppedAnimation(
+ Color.fromARGB(255, 236, 187, 139),
+ ),
+ ),
+ ),
+ const SizedBox(height: 16),
+ const Text(
+ 'Chargement...',
+ style: TextStyle(
+ fontSize: 14,
+ color: Colors.black54,
+ ),
+ ),
+ // Message d'erreur si problème
+ if (snapshot.hasError)
+ Padding(
+ padding: const EdgeInsets.all(16.0),
+ child: Text(
+ 'Erreur: ${snapshot.error}',
+ style: const TextStyle(color: Colors.red),
+ textAlign: TextAlign.center,
+ ),
+ ),
+ ],
+ ),
+ ),
+ ),
+ );
+ }
+ });
}
}
-
class MyApp extends StatefulWidget {
const MyApp({super.key});
@@ -62,16 +113,12 @@ class _MyAppState extends State {
title: 'Flutter Demo',
home: Scaffold(
appBar: AppBar(
-
title: const Text("Courses List"),
),
body: const Center(
child: Text("Hello"),
),
-
),
);
}
}
-
-
diff --git a/lib/main_diagnostic.dart b/lib/main_diagnostic.dart
new file mode 100644
index 0000000..e165cd7
--- /dev/null
+++ b/lib/main_diagnostic.dart
@@ -0,0 +1,216 @@
+import 'package:flutter/foundation.dart';
+import 'package:flutter/material.dart';
+import 'package:factoscope/service_locator.dart';
+import 'data_initializer.dart';
+import 'ui/app.dart';
+
+void main() {
+ WidgetsFlutterBinding.ensureInitialized();
+
+ if (kDebugMode) {
+ print('🔵 main() appelé');
+ }
+
+ setupLocator();
+ runApp(const MainApp());
+}
+
+class MainApp extends StatelessWidget {
+ const MainApp({super.key});
+
+ @override
+ Widget build(BuildContext context) {
+ if (kDebugMode) {
+ print('🔵 MainApp.build() appelé');
+ }
+
+ return const MaterialApp(
+ debugShowCheckedModeBanner: false,
+ home: SplashScreen(),
+ );
+ }
+}
+
+class SplashScreen extends StatefulWidget {
+ const SplashScreen({super.key});
+
+ @override
+ State createState() => _SplashScreenState();
+}
+
+class _SplashScreenState extends State {
+ bool _isLoading = true;
+ String _statusMessage = 'Initialisation...';
+
+ @override
+ void initState() {
+ super.initState();
+ if (kDebugMode) {
+ print('🔵 SplashScreen.initState() appelé');
+ }
+ _initialize();
+ }
+
+ Future _initialize() async {
+ try {
+ if (kDebugMode) {
+ print('🔵 Début de l\'initialisation');
+ }
+
+ setState(() {
+ _statusMessage = 'Chargement des données...';
+ });
+
+ await insertSampleData();
+
+ if (kDebugMode) {
+ print('🔵 insertSampleData() terminé');
+ }
+
+ setState(() {
+ _statusMessage = 'Préparation de l\'interface...';
+ });
+
+ // Petit délai pour s'assurer que tout est prêt
+ await Future.delayed(const Duration(milliseconds: 300));
+
+ if (kDebugMode) {
+ print('🔵 Navigation vers l\'app principale');
+ }
+
+ if (mounted) {
+ Navigator.of(context).pushReplacement(
+ MaterialPageRoute(
+ builder: (_) => const ActualApp(),
+ ),
+ );
+ }
+ } catch (e) {
+ if (kDebugMode) {
+ print('🔴 ERREUR lors de l\'initialisation: $e');
+ }
+ setState(() {
+ _statusMessage = 'Erreur: $e';
+ _isLoading = false;
+ });
+ }
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ if (kDebugMode) {
+ print('🔵 SplashScreen.build() appelé');
+ }
+
+ return Scaffold(
+ backgroundColor: Colors.white,
+ body: SafeArea(
+ child: Center(
+ child: Column(
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: [
+ // Logo
+ Container(
+ width: 100,
+ height: 100,
+ decoration: BoxDecoration(
+ color: const Color.fromARGB(255, 236, 187, 139),
+ borderRadius: BorderRadius.circular(20),
+ ),
+ child: const Icon(
+ Icons.school,
+ size: 60,
+ color: Colors.white,
+ ),
+ ),
+ const SizedBox(height: 32),
+
+ // Titre
+ const Text(
+ 'Factoscope',
+ style: TextStyle(
+ fontSize: 32,
+ fontWeight: FontWeight.bold,
+ color: Colors.black87,
+ ),
+ ),
+ const SizedBox(height: 8),
+
+ // Sous-titre
+ const Text(
+ 'Éducation aux médias et à l\'information',
+ style: TextStyle(
+ fontSize: 14,
+ color: Colors.black54,
+ ),
+ textAlign: TextAlign.center,
+ ),
+ const SizedBox(height: 48),
+
+ // Indicateur de chargement
+ if (_isLoading)
+ const SizedBox(
+ width: 40,
+ height: 40,
+ child: CircularProgressIndicator(
+ strokeWidth: 3,
+ valueColor: AlwaysStoppedAnimation(
+ Color.fromARGB(255, 236, 187, 139),
+ ),
+ ),
+ ),
+
+ const SizedBox(height: 16),
+
+ // Message de statut
+ Text(
+ _statusMessage,
+ style: const TextStyle(
+ fontSize: 14,
+ color: Colors.black54,
+ ),
+ textAlign: TextAlign.center,
+ ),
+
+ // Bouton de retry en cas d'erreur
+ if (!_isLoading)
+ Padding(
+ padding: const EdgeInsets.only(top: 24),
+ child: ElevatedButton(
+ onPressed: () {
+ setState(() {
+ _isLoading = true;
+ _statusMessage = 'Nouvelle tentative...';
+ });
+ _initialize();
+ },
+ style: ElevatedButton.styleFrom(
+ backgroundColor: const Color.fromARGB(255, 236, 187, 139),
+ foregroundColor: Colors.white,
+ ),
+ child: const Text('Réessayer'),
+ ),
+ ),
+ ],
+ ),
+ ),
+ ),
+ );
+ }
+}
+
+class ActualApp extends StatelessWidget {
+ const ActualApp({super.key});
+
+ @override
+ Widget build(BuildContext context) {
+ if (kDebugMode) {
+ print('🔵 ActualApp.build() appelé');
+ }
+
+ return MaterialApp.router(
+ routerConfig: router,
+ debugShowCheckedModeBanner: false,
+ );
+ }
+}
\ No newline at end of file
diff --git a/lib/models/Cloze/cloze_page.dart b/lib/models/Cloze/cloze_page.dart
new file mode 100644
index 0000000..ec005fb
--- /dev/null
+++ b/lib/models/Cloze/cloze_page.dart
@@ -0,0 +1,25 @@
+class ClozeQuestion {
+ final int? id;
+ final String phrase;
+ final String rep1;
+ final String rep2;
+ final String rep3;
+ final String rep4;
+ final int soluce;
+ final int idCours;
+
+ ClozeQuestion({this.id, required this.phrase, required this.rep1, required this.rep2, required this.rep3, required this.rep4, required this.soluce, required this.idCours});
+
+ factory ClozeQuestion.fromMap(Map map) {
+ return ClozeQuestion(
+ id: map['idCloze'],
+ phrase: map['phrase'],
+ rep1: map['rep1'],
+ rep2: map['rep2'],
+ rep3: map['rep3'],
+ rep4: map['rep4'],
+ soluce: map['soluce'],
+ idCours: map['idCours'],
+ );
+ }
+}
\ No newline at end of file
diff --git a/lib/models/ListCoursViewModel.dart b/lib/models/ListCoursViewModel.dart
deleted file mode 100644
index 10f71a4..0000000
--- a/lib/models/ListCoursViewModel.dart
+++ /dev/null
@@ -1,34 +0,0 @@
-import 'package:flutter/material.dart';
-import 'package:seriouse_game/logic/ProgressionUseCase.dart';
-import 'package:seriouse_game/models/cours.dart';
-import 'package:seriouse_game/models/module.dart';
-import 'package:seriouse_game/repositories/coursRepository.dart';
-import 'package:seriouse_game/ui/ModuleSelectionne.dart';
-
-//Classe permettant d'extraire les cours d'un module
-class ListCoursViewModel with ChangeNotifier {
-
- final progressionUseCase = ProgressionUseCase();
-
- //Méthode pour changer la liste coursDuModule du Singleton ModuleSelectionne par celle correspondant à la liste des cours du module d'id idModule
- Future recupererCours(int? idModule) async {
-
- CoursRepository repository = CoursRepository();
-
- //On accède à la liste des cours de la base de donnée par la méthode de CoursRepository
- ModuleSelectionne().updateListModule(await repository.getCoursesByModuleId(idModule!));
-
- //la liste change donc on avertit les listeners
- notifyListeners();
- }
-
- Future getProgressionModule(Module module) async {
- return await progressionUseCase.calculerProgressionCours(module.id!)/100;
- }
-
- Future getProgressionCours(Cours cours) async {
- return await progressionUseCase.calculerProgressionCours(cours.id!)/100;
- }
-
-
-}
\ No newline at end of file
diff --git a/lib/models/ListModuleViewModel.dart b/lib/models/ListModuleViewModel.dart
deleted file mode 100644
index 66d839d..0000000
--- a/lib/models/ListModuleViewModel.dart
+++ /dev/null
@@ -1,31 +0,0 @@
-import 'package:flutter/material.dart';
-import 'package:seriouse_game/logic/ProgressionUseCase.dart';
-import 'package:seriouse_game/models/module.dart';
-import 'package:seriouse_game/repositories/moduleRepository.dart';
-
-//Classe permettant d'extraire la liste des modules
-class ListModuleViewModel with ChangeNotifier {
-
- final progressionUseCase = ProgressionUseCase();
-
- List listModule = List.empty();
-
- //Méthode pour changer la liste listmodule par celle correspondant à la liste de tous les modules de l'application
- Future recupererModule() async {
-
- //Création d'un objet repository pour accéder aux modules de l'application
- ModuleRepository repository = ModuleRepository();
-
- //On accède à la liste des module de la base de donnée par la méthode de ModuleRepository
- listModule = await repository.getAll();
-
- //la liste change donc on avertit les listeners
- notifyListeners();
- }
-
- Future getProgressionGlobale() async {
- double progress = await progressionUseCase.calculerProgressionGlobale();
- return progress.round();
- }
-
-}
\ No newline at end of file
diff --git a/lib/models/QCM/qcm.dart b/lib/models/QCM/qcm.dart
index 7c10d1a..3026a27 100644
--- a/lib/models/QCM/qcm.dart
+++ b/lib/models/QCM/qcm.dart
@@ -1,42 +1,52 @@
-
-import 'question.dart';
-import 'reponse.dart';
-
-/// Modèle représentant un QCM (Questionnaire à Choix Multiples).
class QCM {
- final int id;
- final int numSolution;
- final int idCours;
- final int idQuestion;
- Question? question;
- List? reponses;
+ int? id;
+ String question;
+ String rep1;
+ String rep2;
+ String rep3;
+ String rep4;
+ int soluce;
+ int idCours;
QCM({
- required this.id,
- required this.numSolution,
+ this.id,
+ required this.question,
+ required this.rep1,
+ required this.rep2,
+ required this.rep3,
+ required this.rep4,
+ required this.soluce,
required this.idCours,
- required this.idQuestion,
- this.question,
- this.reponses,
});
- /// Crée une instance de QCM à partir d'une map.
+ Map toMap() {
+ return {
+ 'id': id,
+ 'question': question,
+ 'rep1': rep1,
+ 'rep2': rep2,
+ 'rep3': rep3,
+ 'rep4': rep4,
+ 'soluce': soluce,
+ 'id_cours': idCours,
+ };
+ }
+
factory QCM.fromMap(Map map) {
return QCM(
- id: map['idQCM'],
- numSolution: map['numSolution'],
- idCours: map['idCours'],
- idQuestion: map['idQuestion'],
+ id: map['id'],
+ question: map['question'],
+ rep1: map['rep1'],
+ rep2: map['rep2'],
+ rep3: map['rep3'],
+ rep4: map['rep4'],
+ soluce: map['soluce'],
+ idCours: map['id_cours'],
);
}
- /// Convertit l'objet QCM en map pour la base de données.
- Map toMap() {
- return {
- 'idQCM': id,
- 'numSolution': numSolution,
- 'idCours': idCours,
- 'idQuestion': idQuestion,
- };
+ // Helper pour obtenir les réponses sous forme de liste
+ List getReponses() {
+ return [rep1, rep2, rep3, rep4];
}
-}
\ No newline at end of file
+}
diff --git a/lib/models/QCM/reponse.dart b/lib/models/QCM/reponse.dart
index 57f1efd..424c302 100644
--- a/lib/models/QCM/reponse.dart
+++ b/lib/models/QCM/reponse.dart
@@ -7,7 +7,13 @@ class Reponse {
final String? caption;
final String type;
- Reponse({required this.id, required this.idQCM, this.text, this.imageUrl, this.caption, required this.type});
+ Reponse(
+ {required this.id,
+ required this.idQCM,
+ this.text,
+ this.imageUrl,
+ this.caption,
+ required this.type});
/// Crée une instance de Reponse à partir d'une map.
factory Reponse.fromMap(Map map) {
@@ -17,7 +23,11 @@ class Reponse {
text: map['txt'],
imageUrl: map['urlImage'],
caption: map['caption'],
- type: map.containsKey('txt') ? 'text' : map.containsKey('urlImage') ? 'image' : 'unknown',
+ type: map.containsKey('txt')
+ ? 'text'
+ : map.containsKey('urlImage')
+ ? 'image'
+ : 'unknown',
);
}
diff --git a/lib/models/cours.dart b/lib/models/cours.dart
index 153dee9..54106bc 100644
--- a/lib/models/cours.dart
+++ b/lib/models/cours.dart
@@ -1,39 +1,57 @@
-import 'package:seriouse_game/models/objectifCours.dart';
-import 'package:seriouse_game/models/page.dart';
+import 'package:factoscope/models/page.dart';
class Cours {
- int? id;
- int idModule;
- String titre;
- String contenu;
- List? pages;
- List? objectifs;
+ int? id;
+ int? idModule;
+ String titre;
+ String contenu;
+ String description;
+ int isDownloaded;
+ List? pages;
+
Cours({
this.id,
- required this.idModule,
+ this.idModule,
required this.titre,
required this.contenu,
+ required this.description,
+ this.isDownloaded = 0,
+ this.pages,
});
- // Convertir une Cours en Map pour SQLite
Map toMap() {
return {
'id': id,
- 'id_Module': idModule,
+ 'id_module': idModule,
'titre': titre,
'contenu': contenu,
+ 'description': description,
+ 'is_downloaded': isDownloaded,
};
}
- // Construire une Cours depuis un Map (SQLite)
factory Cours.fromMap(Map map) {
return Cours(
id: map['id'],
- idModule: map['id_module'],
+ idModule: map['id_module'] as int?,
titre: map['titre'],
contenu: map['contenu'],
+ description: map['description'],
+ isDownloaded: map['is_downloaded'] ?? 0,
);
}
-
-}
+ factory Cours.fromJson(Map json) {
+ return Cours(
+ id: json['id'],
+ idModule: json['id_module'],
+ titre: json['titre'],
+ contenu: json['contenu'] ?? json['description'],
+ description: json['description'],
+ isDownloaded: 1,
+ pages: json['pages'] != null
+ ? (json['pages'] as List).map((page) => Page.fromJson(page)).toList()
+ : null,
+ );
+ }
+}
\ No newline at end of file
diff --git a/lib/models/list_cours_view_model.dart b/lib/models/list_cours_view_model.dart
new file mode 100644
index 0000000..6d447fa
--- /dev/null
+++ b/lib/models/list_cours_view_model.dart
@@ -0,0 +1,87 @@
+import 'package:flutter/material.dart';
+import 'package:factoscope/logic/progression_use_case.dart';
+import 'package:factoscope/models/cours.dart';
+import 'package:factoscope/models/module.dart';
+import 'package:factoscope/repositories/cours_repository.dart';
+import 'package:factoscope/ui/module_selectionne.dart';
+import 'package:http/http.dart' as http;
+import 'dart:convert';
+
+import '../config.dart';
+
+class ListCoursViewModel with ChangeNotifier {
+ final progressionUseCase = ProgressionUseCase();
+ final CoursRepository _coursRepository = CoursRepository();
+ bool _isLoading = false;
+ List _cours = [];
+
+ bool get isLoading => _isLoading;
+ List get cours => _cours;
+
+ Future getCours(int? idModule) async {
+ if (idModule == null) return;
+
+ _isLoading = true;
+ notifyListeners();
+
+ try {
+ _cours = await _coursRepository.getCoursesByModuleId(idModule);
+ ModuleSelectionne().updateListModule(_cours);
+ } catch (e) {
+ debugPrint("Erreur lors de la récupération des cours : $e");
+ } finally {
+ _isLoading = false;
+ notifyListeners();
+ }
+ }
+
+ Future getAllCours() async {
+ _isLoading = true;
+ notifyListeners();
+
+ try {
+ _cours = await _coursRepository.getAll();
+ } catch (e) {
+ debugPrint("Erreur lors de la récupération de tous les cours : $e");
+ } finally {
+ _isLoading = false;
+ notifyListeners();
+ }
+ }
+
+ Future downloadCours(int coursId) async {
+ _isLoading = true;
+ notifyListeners();
+
+ try {
+ final response = await http
+ .get(Uri.parse('${AppConfig.effectiveApiUrl}/api/cours/$coursId'));
+ if (response.statusCode == 200) {
+ final courseData = jsonDecode(response.body);
+
+ // Créer ou mettre à jour le cours avec ses pages et médias en JSON
+ await _coursRepository.createOrUpdate(Cours.fromJson(courseData));
+
+ // Marquer le cours comme téléchargé
+ await _coursRepository.markAsDownloaded(coursId);
+
+ await getCours(ModuleSelectionne().moduleSelectionne.id);
+ }
+ } catch (e) {
+ debugPrint("Erreur lors du téléchargement du cours : $e");
+ } finally {
+ _isLoading = false;
+ notifyListeners();
+ }
+ }
+
+ // Calcule la progression d'un module
+ Future getProgressionModule(Module module) async {
+ return await progressionUseCase.calculerProgressionCours(module.id!) / 100;
+ }
+
+ // Calcule la progression d'un cours
+ Future getProgressionCours(Cours cours) async {
+ return await progressionUseCase.calculerProgressionCours(cours.id!) / 100;
+ }
+}
\ No newline at end of file
diff --git a/lib/models/list_module_view_model.dart b/lib/models/list_module_view_model.dart
new file mode 100644
index 0000000..6972b1a
--- /dev/null
+++ b/lib/models/list_module_view_model.dart
@@ -0,0 +1,31 @@
+import 'package:flutter/foundation.dart';
+import 'package:factoscope/logic/progression_use_case.dart';
+import 'package:factoscope/models/module.dart';
+import 'package:factoscope/repositories/module_repository.dart';
+
+// Classe permettant d'extraire la liste des modules
+class ListModuleViewModel with ChangeNotifier {
+ final progressionUseCase = ProgressionUseCase();
+
+ List listModule = List.empty();
+
+ Future recupererModule() async {
+ try {
+ listModule = await ModuleRepository().getAll();
+ notifyListeners();
+ } catch (e) {
+ if (kDebugMode) {
+ print("Erreur lors de la récupération des modules : $e");
+ }
+ }
+ }
+
+ Future getProgressionGlobale() async {
+ double progress = await progressionUseCase.calculerProgressionGlobale();
+ return progress.round();
+ }
+
+ Future getProgressionModule(Module module) async {
+ return 0.0;
+ }
+}
diff --git a/lib/models/mediaCours.dart b/lib/models/mediaCours.dart
deleted file mode 100644
index a42e613..0000000
--- a/lib/models/mediaCours.dart
+++ /dev/null
@@ -1,41 +0,0 @@
-class MediaCours {
- int? id;
- int idPage;
- int ordre;
- String url;
- String type;
- String? caption;
-
- MediaCours({
- this.id,
- required this.idPage,
- required this.ordre,
- required this.url,
- required this.type,
- this.caption,
- });
-
- // Conversion en Map pour SQLite
- Map toMap() {
- return {
- 'id': id,
- 'id_page': idPage,
- 'ordre': ordre,
- 'url': url,
- 'type': type,
- 'caption': caption,
- };
- }
-
- // Conversion d'une Map SQLite en objet MediaCours
- factory MediaCours.fromMap(Map map) {
- return MediaCours(
- id: map['id'],
- idPage: map['id_page'],
- ordre: map['ordre'],
- url: map['url'],
- type: map['type'],
- caption: map['caption'],
- );
- }
-}
diff --git a/lib/models/minijeu.dart b/lib/models/mini_jeu.dart
similarity index 88%
rename from lib/models/minijeu.dart
rename to lib/models/mini_jeu.dart
index f6a7415..c70cad0 100644
--- a/lib/models/minijeu.dart
+++ b/lib/models/mini_jeu.dart
@@ -1,9 +1,9 @@
class MiniJeu {
- int? id;
- int idCours;
- String nom;
- String? description;
- int progression;
+ int? id;
+ int idCours;
+ String nom;
+ String? description;
+ int progression;
MiniJeu({
this.id,
@@ -34,6 +34,4 @@ class MiniJeu {
progression: map['progression'],
);
}
-
-
}
diff --git a/lib/models/module.dart b/lib/models/module.dart
index ef37cc8..0450c87 100644
--- a/lib/models/module.dart
+++ b/lib/models/module.dart
@@ -1,12 +1,12 @@
-import 'package:seriouse_game/models/cours.dart';
-
+import 'package:factoscope/models/cours.dart';
class Module {
- int? id; // `id` est nullable pour les nouvelles entrées
- String titre;
- String urlImg;
- String description;
- List? cours;
+ int? id;
+ String titre;
+ String urlImg;
+ String description;
+ List? cours;
+
Module({
this.id,
required this.urlImg,
@@ -14,17 +14,15 @@ class Module {
required this.description,
});
- // Convertir un objet en Map pour SQLite
Map toMap() {
return {
'id': id,
- 'urlImg':urlImg,
+ 'urlImg': urlImg,
'titre': titre,
'description': description,
};
}
- // Convertir une ligne SQLite en objet Module
static Module fromMap(Map map) {
return Module(
id: map['id'],
@@ -33,5 +31,4 @@ class Module {
description: map['description'],
);
}
-
}
diff --git a/lib/models/objectifCours.dart b/lib/models/objectifCours.dart
deleted file mode 100644
index d565202..0000000
--- a/lib/models/objectifCours.dart
+++ /dev/null
@@ -1,25 +0,0 @@
-class ObjectifCours {
- int? id;
- int idCours;
- String description;
-
- ObjectifCours({this.id, required this.idCours, required this.description});
-
- // Convertir en Map pour SQLite
- Map toMap() {
- return {
- 'id': id,
- 'id_cours': idCours,
- 'description': description,
- };
- }
-
- // Conversion Map vers l'objet ObjectifCours
- factory ObjectifCours.fromMap(Map map) {
- return ObjectifCours(
- id: map['id'],
- idCours: map['id_cours'],
- description: map['description'],
- );
- }
-}
diff --git a/lib/models/page.dart b/lib/models/page.dart
index 61db3b6..314a406 100644
--- a/lib/models/page.dart
+++ b/lib/models/page.dart
@@ -1,44 +1,117 @@
-import 'package:seriouse_game/models/mediaCours.dart';
+import 'dart:convert';
+
+import 'package:flutter/foundation.dart';
class Page {
int? id;
- int ordre;
+ String? description;
+ String? contenu;
int idCours;
- String urlAudio;
int estVue;
- String? description ;
- List? medias;
+ List? medias;
Page({
this.id,
- required this.ordre,
- this.urlAudio = "",
- this.estVue=0,
+ this.description,
+ this.contenu,
required this.idCours,
- this.description ,
+ this.estVue = 0,
+ this.medias,
});
- // Convertir un objet Page en Map pour SQLite
Map toMap() {
return {
'id': id,
- 'ordre': ordre,
+ 'description': description,
+ 'contenu': contenu,
'id_cours': idCours,
- 'description':description,
- 'est_vue':estVue,
- 'urlAudio':urlAudio,
+ 'est_vue': estVue,
+ 'medias': medias != null ? jsonEncode(medias!.map((m) => m.toJson()).toList()) : null,
};
}
- // Créer un objet Page à partir d'une Map SQLite
factory Page.fromMap(Map map) {
+ List? mediaList;
+ if (map['medias'] != null && map['medias'] != '') {
+ try {
+ final decoded = jsonDecode(map['medias'] as String) as List;
+ mediaList = decoded.map((m) => MediaItem.fromJson(m)).toList();
+ } catch (e) {
+ if (kDebugMode) {
+ print("Erreur parsing medias JSON: $e");
+ }
+ mediaList = null;
+ }
+ }
+
return Page(
id: map['id'],
- ordre: map['ordre'],
- idCours: map['id_cours'],
description: map['description'],
- estVue: map['est_vue'],
- urlAudio: map['urlAudio']
+ contenu: map['contenu'],
+ idCours: map['id_cours'],
+ estVue: map['est_vue'] ?? 0,
+ medias: mediaList,
+ );
+ }
+
+ factory Page.fromJson(Map json) {
+ List? mediaList;
+ if (json['medias'] != null) {
+ if (json['medias'] is String) {
+ // Si c'est une string JSON, on la décode
+ try {
+ final decoded = jsonDecode(json['medias']) as List;
+ mediaList = decoded.map((m) => MediaItem.fromJson(m)).toList();
+ } catch (e) {
+ if (kDebugMode) {
+ print("Erreur parsing medias JSON string: $e");
+ }
+ }
+ } else if (json['medias'] is List) {
+ // Si c'est déjà une liste
+ mediaList = (json['medias'] as List).map((m) => MediaItem.fromJson(m)).toList();
+ }
+ }
+
+ return Page(
+ id: json['id'],
+ description: json['description'],
+ contenu: json['content'],
+ idCours: json['id_cours'],
+ estVue: json['est_vue'] ?? 0,
+ medias: mediaList,
+ );
+ }
+}
+
+class MediaItem {
+ int ordre;
+ String url;
+ String type;
+ String? caption;
+
+ MediaItem({
+ required this.ordre,
+ required this.url,
+ required this.type,
+ this.caption,
+ });
+
+ Map toJson() {
+ return {
+ 'ordre': ordre,
+ 'url': url,
+ 'type': type,
+ if (caption != null) 'caption': caption,
+ };
+ }
+
+ factory MediaItem.fromJson(Map json) {
+ return MediaItem(
+ ordre: json['ordre'] ?? 0,
+ url: json['url'] ?? '',
+ type: json['type'] ?? 'text',
+ caption: json['caption'],
);
}
}
\ No newline at end of file
diff --git a/lib/repositories/Cloze/cloze_repository.dart b/lib/repositories/Cloze/cloze_repository.dart
new file mode 100644
index 0000000..a121b96
--- /dev/null
+++ b/lib/repositories/Cloze/cloze_repository.dart
@@ -0,0 +1,31 @@
+import '../../database_helper.dart';
+import '../../models/Cloze/cloze_page.dart';
+
+class ClozeRepository {
+ final DatabaseHelper _dbHelper = DatabaseHelper.instance;
+
+ Future> getByCoursId(int coursId) async {
+ final db = await _dbHelper.database;
+ final List