diff --git a/.flutter-plugins-dependencies b/.flutter-plugins-dependencies index 18b8405..72e19bf 100644 --- a/.flutter-plugins-dependencies +++ b/.flutter-plugins-dependencies @@ -1 +1 @@ -{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"qr_code_scanner","path":"C:\\\\Users\\\\thoma\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dartlang.org\\\\qr_code_scanner-1.0.0\\\\","native_build":true,"dependencies":[]},{"name":"sqflite","path":"C:\\\\Users\\\\thoma\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dartlang.org\\\\sqflite-2.0.3+1\\\\","native_build":true,"dependencies":[]}],"android":[{"name":"qr_code_scanner","path":"C:\\\\Users\\\\thoma\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dartlang.org\\\\qr_code_scanner-1.0.0\\\\","native_build":true,"dependencies":[]},{"name":"sqflite","path":"C:\\\\Users\\\\thoma\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dartlang.org\\\\sqflite-2.0.3+1\\\\","native_build":true,"dependencies":[]}],"macos":[{"name":"sqflite","path":"C:\\\\Users\\\\thoma\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dartlang.org\\\\sqflite-2.0.3+1\\\\","native_build":true,"dependencies":[]}],"linux":[],"windows":[],"web":[]},"dependencyGraph":[{"name":"qr_code_scanner","dependencies":[]},{"name":"sqflite","dependencies":[]}],"date_created":"2022-08-18 17:59:37.167796","version":"3.0.3"} \ No newline at end of file +{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"qr_code_scanner","path":"C:\\\\Users\\\\thoma\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dartlang.org\\\\qr_code_scanner-1.0.0\\\\","native_build":true,"dependencies":[]},{"name":"sqflite","path":"C:\\\\Users\\\\thoma\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dartlang.org\\\\sqflite-2.0.3+1\\\\","native_build":true,"dependencies":[]}],"android":[{"name":"qr_code_scanner","path":"C:\\\\Users\\\\thoma\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dartlang.org\\\\qr_code_scanner-1.0.0\\\\","native_build":true,"dependencies":[]},{"name":"sqflite","path":"C:\\\\Users\\\\thoma\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dartlang.org\\\\sqflite-2.0.3+1\\\\","native_build":true,"dependencies":[]}],"macos":[{"name":"sqflite","path":"C:\\\\Users\\\\thoma\\\\AppData\\\\Local\\\\Pub\\\\Cache\\\\hosted\\\\pub.dartlang.org\\\\sqflite-2.0.3+1\\\\","native_build":true,"dependencies":[]}],"linux":[],"windows":[],"web":[]},"dependencyGraph":[{"name":"qr_code_scanner","dependencies":[]},{"name":"sqflite","dependencies":[]}],"date_created":"2022-08-25 17:55:14.179888","version":"3.0.3"} \ No newline at end of file diff --git a/lib/Helpers/DatabaseHelper.dart b/lib/Helpers/DatabaseHelper.dart new file mode 100644 index 0000000..53e12bd --- /dev/null +++ b/lib/Helpers/DatabaseHelper.dart @@ -0,0 +1,240 @@ +import 'dart:convert'; + +import 'package:manager_api/api.dart'; +import 'package:mymuseum_visitapp/Models/visitContext.dart'; +import 'package:path/path.dart'; +import 'package:sqflite/sqflite.dart'; + +enum DatabaseTableType { + main, + configurations, + sections, + resources +} + +class DatabaseHelper { + static final _databaseName = "visit_database.db"; + static final _databaseVersion = 1; + + static final mainTable = 'visitAppContext'; + static final columnLanguage = 'language'; + + static final columnLabel = 'label'; + static final columnId = 'id'; + static final columnData = 'data'; + static final columnType = 'type'; + static final columnDateCreation = 'dateCreation'; + static final columnIsMobile = 'isMobile'; + static final columnIsTablet = 'isTablet'; + static final columnIsOffline = 'isOffline'; + + static final configurationsTable = 'configurations'; + static final columnLanguages = 'languages'; + static final columnPrimaryColor = 'primaryColor'; + static final columnSecondaryColor = 'secondaryColor'; + + static final sectionsTable = 'sections'; + static final columnTitle = 'title'; + static final columnDescription = 'description'; + static final columnImageId = 'imageId'; + static final columnImageSource = 'imageSource'; + static final columnConfigurationId = 'configurationId'; + static final columnIsSubSection = 'isSubSection'; + static final columnParentId = 'parentId'; + static final columnOrderOfElement = 'orderOfElement'; + + static final resourcesTable = 'resources'; + + DatabaseHelper._privateConstructor(); + static final DatabaseHelper instance = DatabaseHelper._privateConstructor(); + + static Database? _database; + Future get database async => + _database ??= await _initDatabase(); + + Future _initDatabase() async { + String path = join(await getDatabasesPath(), _databaseName); + return await openDatabase(path, + version: _databaseVersion, onCreate: _onCreate); + } + + // SQL code to create the database table + Future _onCreate(Database db, int version) async { + await db.execute(''' + CREATE TABLE $mainTable ( + $columnId TEXT NOT NULL PRIMARY KEY, + $columnLanguage TEXT NOT NULL + ) + '''); + await db.execute(''' + CREATE TABLE $configurationsTable ( + $columnId TEXT NOT NULL PRIMARY KEY, + $columnLabel TEXT NOT NULL, + $columnLanguages TEXT NOT NULL, + $columnDateCreation TEXT NOT NULL, + $columnPrimaryColor TEXT, + $columnSecondaryColor TEXT, + $columnIsMobile BOOLEAN NOT NULL CHECK ($columnIsMobile IN (0,1)), + $columnIsTablet BOOLEAN NOT NULL CHECK ($columnIsTablet IN (0,1)), + $columnIsOffline BOOLEAN NOT NULL CHECK ($columnIsOffline IN (0,1)) + ) + '''); + + await db.execute(''' + CREATE TABLE $sectionsTable ( + $columnId TEXT NOT NULL PRIMARY KEY, + $columnLabel TEXT NOT NULL, + $columnTitle TEXT NOT NULL, + $columnDescription TEXT, + $columnImageId TEXT, + $columnImageSource TEXT, + $columnConfigurationId TEXT NOT NULL, + $columnIsSubSection BOOLEAN NOT NULL CHECK ($columnIsSubSection IN (0,1)), + $columnParentId TEXT, + $columnType INT NOT NULL, + $columnData TEXT NOT NULL, + $columnDateCreation TEXT NOT NULL, + $columnOrderOfElement TEXT NOT NULL + ) + '''); + + await db.execute(''' + CREATE TABLE $resourcesTable ( + $columnId TEXT NOT NULL PRIMARY KEY, + $columnLabel TEXT NOT NULL, + $columnData TEXT NOT NULL, + $columnType INT NOT NULL + ) + '''); + } + + Future insert(DatabaseTableType type, Map info) async { + Database db = await instance.database; + + if(info.containsKey("languages")) { + info.update("languages", (value) => jsonEncode(value)); + print("languages BEFORE"); + print(info["languages"]); + } + var test = await instance.getData(type); + if((type == DatabaseTableType.main && test != null) || (type != DatabaseTableType.main && test!.where((t) => info[columnId] == t.id).isNotEmpty)) { + var res = await db.update(_getTableName(type), info); + return res; + } else { + var res = await db.insert(_getTableName(type), info); + return res; + } + } + + Future update(DatabaseTableType type, Map info, String id) async { + // Get a reference to the database. + final db = await instance.database; + + await db.update( + _getTableName(type), + info, + where: "$columnId = ?", + whereArgs: [id], + ); + } + + Future>> queryAllRows(DatabaseTableType type) async { + Database db = await instance.database; + var res = await db.query(_getTableName(type), orderBy: "$columnId DESC"); + return res; + } + + Future delete(String id, DatabaseTableType type) async { + Database db = await instance.database; + return await db.delete(_getTableName(type), where: '$columnId = ?', whereArgs: [id]); + } + + Future>> clearTable(DatabaseTableType type) async { + Database db = await instance.database; + String tableName = _getTableName(type); + return await db.rawQuery("DELETE FROM $tableName"); + } + + Future getData(DatabaseTableType type) async { + dynamic dataToReturn; + + if(type != DatabaseTableType.main) + { + dataToReturn = []; + } + + await DatabaseHelper.instance.queryAllRows(type).then((value) { + print("value -----"); + print(value); + value.forEach((element) { + print("DB - CONTEXT --- "); + switch(type) { + case DatabaseTableType.main: + dataToReturn = VisitAppContext( + id: element["id"], + language: element["language"] + ); + break; + case DatabaseTableType.configurations: + dataToReturn.add(ConfigurationDTO( + id: element["id"], + label: element["label"], + primaryColor: element["primaryColor"], + secondaryColor: element["secondaryColor"], + languages: List.from(jsonDecode(element["languages"])), + dateCreation: DateTime.tryParse(element["dateCreation"]), + isMobile: element["isMobile"] == 1 ? true : false, + isTablet: element["isTablet"] == 1 ? true : false, + isOffline: element["isOffline"] == 1 ? true : false + )); + break; + case DatabaseTableType.sections: + print("RESUUUUUUUULT"); + print(element['title']); + print(json.decode(element['title'])); + print(List.from(element["title"])); + dataToReturn.add(SectionDTO( + id: element["id"], + label: element["label"], + title: element['title'].map((q) => TranslationDTO.fromJson(q)).toList(), + description: json.decode(element['description']).map((q) => TranslationDTO.fromJson(q)).toList(), + imageId: element["imageId"], + imageSource: element["imageSource"], + configurationId: element["configurationId"], + type: element["type"], // TODO + data: element["data"], // TODO + dateCreation: DateTime.tryParse(element["dateCreation"]), + order: element["orderOfElement"], + )); + print("RESUUUUUUUULT"); + break; + case DatabaseTableType.resources: + dataToReturn.add(ResourceDTO( + id: element["id"], + label: element["label"], + data: element["data"], // TODO + type: element["type"] // TODO + )); + break; + } + }); + }).catchError((error) { + print(error); + }); + print(dataToReturn); + return dataToReturn; + } + + String _getTableName(DatabaseTableType type) { + switch(type) { + case DatabaseTableType.main: + return mainTable; + case DatabaseTableType.configurations: + return configurationsTable; + case DatabaseTableType.sections: + return sectionsTable; + case DatabaseTableType.resources: + return resourcesTable; + } + } +} \ No newline at end of file diff --git a/lib/Models/visitContext.dart b/lib/Models/visitContext.dart index 8f5b618..52de53a 100644 --- a/lib/Models/visitContext.dart +++ b/lib/Models/visitContext.dart @@ -1,34 +1,36 @@ import 'package:flutter/material.dart'; +import 'package:manager_api/api.dart'; class VisitAppContext with ChangeNotifier{ - String? userId = ""; - String? token = ""; - String? host = ""; + String? id = ""; + //String? token = ""; + //String? host = ""; String? language = ""; + List? configurations; - VisitAppContext({this.userId, this.token, this.host, this.language}); + VisitAppContext({this.language, this.id}); Map toMap() { return { - 'userId': userId, - 'host': host, + 'id': id, + //'host': host, 'language': language, - 'token': token + //'token': token }; } factory VisitAppContext.fromJson(Map json) { return VisitAppContext( - userId: json['userId'] as String, - host: json['host'] as String, + id: json['id'] as String, + /*host: json['host'] as String,*/ language: json['language'] as String, - token: json['token'] as String, + //token: json['token'] as String, ); } // Implement toString to make it easier to see information about @override String toString() { - return 'VisitAppContext{userId: $userId, language: $language, host: $host}'; + return 'VisitAppContext{id: $id, language: $language}'; } } \ No newline at end of file diff --git a/lib/Screens/Home/home.dart b/lib/Screens/Home/home.dart index 4292dd0..302324e 100644 --- a/lib/Screens/Home/home.dart +++ b/lib/Screens/Home/home.dart @@ -1,4 +1,5 @@ +import 'dart:convert'; import 'dart:io'; import 'package:auto_size_text/auto_size_text.dart'; @@ -7,6 +8,7 @@ import 'package:manager_api/api.dart'; import 'package:mymuseum_visitapp/Components/CustomAppBar.dart'; import 'package:mymuseum_visitapp/Components/Loading.dart'; import 'package:mymuseum_visitapp/Components/ScannerBouton.dart'; +import 'package:mymuseum_visitapp/Helpers/DatabaseHelper.dart'; import 'package:mymuseum_visitapp/Helpers/networkCheck.dart'; import 'package:mymuseum_visitapp/Screens/Visit/visit.dart'; import 'package:mymuseum_visitapp/app_context.dart'; @@ -39,7 +41,7 @@ class _HomePageState extends State { width: size.width, height: size.height, child: FutureBuilder( - future: getConfiguration(appContext.clientAPI), + future: getConfigurations(appContext.clientAPI), builder: (context, AsyncSnapshot snapshot) { if (snapshot.connectionState == ConnectionState.done) { configurations = List.from(snapshot.data).where((configuration) => configuration.isMobile!).toList(); @@ -95,9 +97,9 @@ class _HomePageState extends State { margin: const EdgeInsets.all(8), child: InkWell( onTap: () async { - print("TODO download"); + downloadClicked(appContext, configurations[index]); }, - child: Icon(Icons.download_outlined, color: Colors.white), + child: const Icon(Icons.download_outlined, color: Colors.white), ), /*AutoSizeText( configurations[index].isOffline.toString(), @@ -133,22 +135,95 @@ class _HomePageState extends State { ); } - Future?> getConfiguration(Client client) async { + Future?> getConfigurations(Client client) async { try { + List? configurations; bool isOnline = await hasNetwork(); if(isOnline) { //var client = new Client("http://192.168.31.140:8089"); // TODO REMOVE - List? configurations = await client.configurationApi!.configurationGet(); - print(configurations); - return configurations; + configurations = await client.configurationApi!.configurationGet(); + + return configurations ?? []; + } else { + print("Search in local DB as we don't have internet connection"); + configurations = List.from(await DatabaseHelper.instance.getData(DatabaseTableType.configurations)); + print("RESULT AAH"); + return configurations ?? []; // TODO return local list.. + } + } catch (e) { + print(e); + print("IN CATCH"); + return []; + } + } + + Future?> getAllSections(Client client, String configurationId) async { + try { + bool isOnline = await hasNetwork(); + if(isOnline) { + List? sections = await client.sectionApi!.sectionGetFromConfiguration(configurationId); + print(sections); + + return sections; } else { return []; // TODO return local list.. } } catch (e) { print(e); print("IN CATCH"); + return []; } } + + Future downloadClicked(AppContext appContext, ConfigurationDTO configuration) async { + // Display config only downloaded - TODO + + // Update local DB - Configuration + await DatabaseHelper.instance.insert(DatabaseTableType.configurations, configuration.toJson()); + + var teeest = await DatabaseHelper.instance.getData(DatabaseTableType.configurations); + print("RESULT new or update config"); + print(teeest); + + print("TODO download"); + List? sections = await getAllSections(appContext.clientAPI, configuration.id!); + + if(sections!.isNotEmpty) { + // Update local DB - Sections + for(var section in sections) { + print("Section to store == "); + print(section.toJson()); + print(section.type == SectionType.Quizz); + + var test = sectionToMap(section); + print("SECTION TOOOOO MAAAAAAAAAAAAAAAAAAAAP"); + print(test); + + + await DatabaseHelper.instance.insert(DatabaseTableType.sections, sectionToMap(section)); + } + } + + } + + Map sectionToMap(SectionDTO section) { + return { + 'id': section.id, + 'label': section.label, + 'title': jsonEncode(section.title), + 'description': jsonEncode(section.description), + 'imageId': section.imageId, + 'imageSource': section.imageSource, + 'configurationId': section.configurationId, + 'isSubSection': section.isSubSection, + 'parentId': section.parentId, + 'type': section.type!.toJson(), + 'data': section.data, + 'dateCreation': section.dateCreation!.toUtc().toIso8601String(), + 'orderOfElement': section.order, + //'token': token + }; + } } boxDecoration(ConfigurationDTO configuration, bool isSelected) { // TODO to change diff --git a/lib/app_context.dart b/lib/app_context.dart index 4ee98e7..1ddf58a 100644 --- a/lib/app_context.dart +++ b/lib/app_context.dart @@ -6,7 +6,7 @@ import 'Models/visitContext.dart'; class AppContext with ChangeNotifier { VisitAppContext _visitContext; - Client clientAPI = Client("http://192.168.31.140:8089"); + Client clientAPI = Client("http://192.168.31.140:8089"); // Replace by https://api.mymuseum.be AppContext(this._visitContext); diff --git a/lib/main.dart b/lib/main.dart index b63917f..b94cbf9 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -3,6 +3,7 @@ import 'package:mymuseum_visitapp/Screens/Article/article.dart'; import 'package:mymuseum_visitapp/Screens/Home/home.dart'; import 'package:provider/provider.dart'; +import 'Helpers/DatabaseHelper.dart'; import 'Models/visitContext.dart'; import 'Screens/Scanner/scanner_old.dart'; import 'app_context.dart'; @@ -11,14 +12,14 @@ import 'constants.dart'; void main() async { WidgetsFlutterBinding.ensureInitialized(); String initialRoute; - VisitAppContext localContext = VisitAppContext(language: "FR", host: "http://192.168.31.140:8089"); - - //localContext = await DatabaseHelper.instance.getData(); + VisitAppContext? localContext = await DatabaseHelper.instance.getData(DatabaseTableType.main); if(localContext != null) { print("we've got an local db !"); print(localContext); } else { + localContext = VisitAppContext(language: "FR", id: "UserId_Init"); + DatabaseHelper.instance.insert(DatabaseTableType.main, localContext.toMap()); print("NO LOCAL DB !"); } diff --git a/manager_api/lib/model/section_type.dart b/manager_api/lib/model/section_type.dart index 33c1f24..3441269 100644 --- a/manager_api/lib/model/section_type.dart +++ b/manager_api/lib/model/section_type.dart @@ -23,23 +23,23 @@ class SectionType { int toJson() => value; - static const number0 = SectionType._(0); - static const number1 = SectionType._(1); - static const number2 = SectionType._(2); - static const number3 = SectionType._(3); - static const number4 = SectionType._(4); - static const number5 = SectionType._(5); - static const number6 = SectionType._(6); + static const Map = SectionType._(0); + static const Slider = SectionType._(1); + static const Video = SectionType._(2); + static const Web = SectionType._(3); + static const Menu = SectionType._(4); + static const Quizz = SectionType._(5); + static const Article = SectionType._(6); /// List of all possible values in this [enum][SectionType]. static const values = [ - number0, - number1, - number2, - number3, - number4, - number5, - number6, + Map, + Slider, + Video, + Web, + Menu, + Quizz, + Article ]; static SectionType? fromJson(dynamic value) => SectionTypeTypeTransformer().decode(value); @@ -78,13 +78,13 @@ class SectionTypeTypeTransformer { SectionType? decode(dynamic data, {bool allowNull = true}) { if (data != null) { switch (data) { - case 0: return SectionType.number0; - case 1: return SectionType.number1; - case 2: return SectionType.number2; - case 3: return SectionType.number3; - case 4: return SectionType.number4; - case 5: return SectionType.number5; - case 6: return SectionType.number6; + case 'Map': return SectionType.Map; + case 'Slider': return SectionType.Slider; + case 'Video': return SectionType.Video; + case 'Web': return SectionType.Web; + case 'Menu': return SectionType.Menu; + case 'Quizz': return SectionType.Quizz; + case 'Article': return SectionType.Article; default: if (!allowNull) { throw ArgumentError('Unknown enum value to decode: $data');