diff --git a/.flutter-plugins-dependencies b/.flutter-plugins-dependencies index 72e19bf..0b70042 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-25 17:55:14.179888","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-26 18:14:06.211747","version":"3.0.3"} \ No newline at end of file diff --git a/lib/Helpers/DatabaseHelper.dart b/lib/Helpers/DatabaseHelper.dart index 53e12bd..0ad88c7 100644 --- a/lib/Helpers/DatabaseHelper.dart +++ b/lib/Helpers/DatabaseHelper.dart @@ -1,6 +1,7 @@ import 'dart:convert'; import 'package:manager_api/api.dart'; +import 'package:mymuseum_visitapp/Models/resourceModel.dart'; import 'package:mymuseum_visitapp/Models/visitContext.dart'; import 'package:path/path.dart'; import 'package:sqflite/sqflite.dart'; @@ -101,7 +102,6 @@ class DatabaseHelper { await db.execute(''' CREATE TABLE $resourcesTable ( $columnId TEXT NOT NULL PRIMARY KEY, - $columnLabel TEXT NOT NULL, $columnData TEXT NOT NULL, $columnType INT NOT NULL ) @@ -118,9 +118,24 @@ class DatabaseHelper { } 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); + if(type != DatabaseTableType.main) { + print("UPDATE $type - length before ${test.length}"); + } else { + print("UPDATE $type - main table"); + } + var res = await db.update( + _getTableName(type), + info, + where: "$columnId = ?", + whereArgs: [info[columnId]], + ); return res; } else { + if(type != DatabaseTableType.main) { + print("INSERT $type - length before ${test.length}"); + } else { + print("INSERT $type - main table"); + } var res = await db.insert(_getTableName(type), info); return res; } @@ -144,6 +159,12 @@ class DatabaseHelper { return res; } + Future>> queryWithId(DatabaseTableType type, String id) async { + Database db = await instance.database; + var res = await db.query(_getTableName(type), where: '$columnId = ?', whereArgs: [id]); + return res; + } + Future delete(String id, DatabaseTableType type) async { Database db = await instance.database; return await db.delete(_getTableName(type), where: '$columnId = ?', whereArgs: [id]); @@ -164,10 +185,8 @@ class DatabaseHelper { } await DatabaseHelper.instance.queryAllRows(type).then((value) { - print("value -----"); - print(value); + print("DB - getData - CONTEXT --- $type --> "); value.forEach((element) { - print("DB - CONTEXT --- "); switch(type) { case DatabaseTableType.main: dataToReturn = VisitAppContext( @@ -176,52 +195,19 @@ class DatabaseHelper { ); 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 - )); + dataToReturn.add(getConfigurationFromDB(element)); 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"); + dataToReturn.add(getSectionFromDB(element)); break; case DatabaseTableType.resources: - dataToReturn.add(ResourceDTO( - id: element["id"], - label: element["label"], - data: element["data"], // TODO - type: element["type"] // TODO - )); + dataToReturn.add(getResourceFromDB(element)); break; } }); }).catchError((error) { print(error); }); - print(dataToReturn); return dataToReturn; } @@ -237,4 +223,44 @@ class DatabaseHelper { return resourcesTable; } } + + ConfigurationDTO getConfigurationFromDB(dynamic element) { + return 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 + ); + } + + SectionDTO getSectionFromDB(dynamic element) { + var titles = List.from(json.decode(element['title']).map((q) => TranslationDTO.fromJson(q)).toList()); + var descriptions = List.from(json.decode(element['description']).map((q) => TranslationDTO.fromJson(q)).toList()); + return SectionDTO( + id: element["id"], + label: element["label"], + title: titles, + description: descriptions, + imageId: element["imageId"], + imageSource: element["imageSource"], + configurationId: element["configurationId"], + type: SectionType.values[element["type"]], + data: element["data"], + dateCreation: DateTime.tryParse(element["dateCreation"]), + order: int.parse(element["orderOfElement"]), + ); + } + + ResourceModel getResourceFromDB(dynamic element) { + return ResourceModel( + id: element["id"], + data: element["data"], + type: ResourceType.values[element["type"]] + ); + } } \ No newline at end of file diff --git a/lib/Helpers/translationHelper.dart b/lib/Helpers/translationHelper.dart new file mode 100644 index 0000000..54c41e7 --- /dev/null +++ b/lib/Helpers/translationHelper.dart @@ -0,0 +1,12 @@ +import 'package:manager_api/api.dart'; +import 'package:mymuseum_visitapp/app_context.dart'; + +class TranslationHelper { + static String get(List? translationDTO, AppContext appContext) { + try { + return translationDTO!.where((element) => element.language == appContext.getContext().language).first.value!; + } catch (_) { + return ""; + } + } +} diff --git a/lib/Models/resourceModel.dart b/lib/Models/resourceModel.dart new file mode 100644 index 0000000..b5e7d97 --- /dev/null +++ b/lib/Models/resourceModel.dart @@ -0,0 +1,31 @@ +import 'package:flutter/material.dart'; +import 'package:manager_api/api.dart'; + +class ResourceModel { + String? id = ""; + String? data = ""; + ResourceType? type; + + ResourceModel({this.id, this.data, this.type}); + + Map toMap() { + return { + 'id': id, + 'data': data, + 'type': type!.value + }; + } + + factory ResourceModel.fromJson(Map json) { + return ResourceModel( + id: json['id'] as String, + data: json['data'] as String, + type: json['type'] as ResourceType + ); + } + + @override + String toString() { + return 'ResourceModel{id: $id, type: $type, data: $data}'; + } +} \ No newline at end of file diff --git a/lib/Screens/Article/article.dart b/lib/Screens/Article/article.dart index 03cd3a0..8f8dacd 100644 --- a/lib/Screens/Article/article.dart +++ b/lib/Screens/Article/article.dart @@ -1,9 +1,20 @@ +import 'dart:convert'; + import 'package:flutter/material.dart'; +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/Helpers/translationHelper.dart'; +import 'package:mymuseum_visitapp/Models/resourceModel.dart'; import 'package:mymuseum_visitapp/Screens/Scanner/scanner_old.dart'; +import 'package:mymuseum_visitapp/app_context.dart'; +import 'package:mymuseum_visitapp/client.dart'; import 'package:mymuseum_visitapp/constants.dart'; +import 'package:provider/provider.dart'; class ArticlePage extends StatefulWidget { const ArticlePage({Key? key, required this.articleId}) : super(key: key); @@ -15,27 +26,70 @@ class ArticlePage extends StatefulWidget { } class _ArticlePageState extends State { + SectionDTO? sectionDTO; + ArticleDTO? articleDTO; + ResourceModel? resourceModel; @override Widget build(BuildContext context) { + final appContext = Provider.of(context); return Scaffold( appBar: CustomAppBar( title: "ArticlePage", isHomeButton: false, ), - body: Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text(widget.articleId), - Text( - 'coucou', - style: Theme.of(context).textTheme.headline4, - ), - ], - ), + body: FutureBuilder( + future: getArticle(appContext.clientAPI, widget.articleId), + builder: (context, AsyncSnapshot snapshot) { + if(articleDTO != null && sectionDTO != null) { + return Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text(TranslationHelper.get(sectionDTO!.title, appContext)), + Text( + TranslationHelper.get(articleDTO!.content, appContext), + style: Theme.of(context).textTheme.headline4, + textAlign: TextAlign.center, + ), + resourceModel != null ? Image.memory(base64Decode(resourceModel!.data!)) : const Text("image"), + ], + ), + ); + } else { + return const Loading(); + } + + } ), floatingActionButton: const ScannerBouton(isReplacement: true), ); } + + Future getArticle(Client client, String articleId) async { + try { + bool isOnline = await hasNetwork(); + if(true) { + await DatabaseHelper.instance.queryWithId(DatabaseTableType.sections, articleId).then((value) async { + sectionDTO = DatabaseHelper.instance.getSectionFromDB(value.first); + if(sectionDTO!.type == SectionType.Article) { + articleDTO = ArticleDTO.fromJson(jsonDecode(sectionDTO!.data!)); + if(articleDTO!.images!.isNotEmpty) { + await DatabaseHelper.instance.queryWithId(DatabaseTableType.resources, articleDTO!.images!.first.resourceId!).then((value) { + resourceModel = DatabaseHelper.instance.getResourceFromDB(value.first); + }); + } + } + + }); + } else { + // TODO ONLINE + return null; // TODO return local list.. + } + } catch (e) { + print(e); + print("IN CATCH"); + return null; + } + } } diff --git a/lib/Screens/Home/home.dart b/lib/Screens/Home/home.dart index 302324e..3934543 100644 --- a/lib/Screens/Home/home.dart +++ b/lib/Screens/Home/home.dart @@ -1,15 +1,16 @@ +import 'package:flutter/material.dart'; import 'dart:convert'; import 'dart:io'; import 'package:auto_size_text/auto_size_text.dart'; -import 'package:flutter/material.dart'; 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/Models/resourceModel.dart'; import 'package:mymuseum_visitapp/Screens/Visit/visit.dart'; import 'package:mymuseum_visitapp/app_context.dart'; import 'package:mymuseum_visitapp/client.dart'; @@ -162,8 +163,6 @@ class _HomePageState extends State { bool isOnline = await hasNetwork(); if(isOnline) { List? sections = await client.sectionApi!.sectionGetFromConfiguration(configurationId); - print(sections); - return sections; } else { return []; // TODO return local list.. @@ -175,32 +174,72 @@ class _HomePageState extends State { } } + Future getAndDownloadImage(Client client, ImageDTO imageDTO) async { + try { + bool isOnline = await hasNetwork(); + if(isOnline) { + var source = imageDTO.source_; + if(imageDTO.source_!.contains("localhost:5000")) { + source = imageDTO.source_!.replaceAll("http://localhost:5000", client.apiApi!.basePath); + } + HttpClient client2 = HttpClient(); + var _downloadData = []; + client2.getUrl(Uri.parse(source!)) + .then((HttpClientRequest request) { + return request.close(); + }) + .then((HttpClientResponse response) { + response.listen((d) => _downloadData.addAll(d), + onDone: () async { + final base64Str = base64.encode(_downloadData); + ResourceModel resourceModel = ResourceModel(id: imageDTO.resourceId, data: base64Str, type: ResourceType.Image); + await DatabaseHelper.instance.insert(DatabaseTableType.resources, resourceModel.toMap()); + //var test = base64.decode(base64Str); + //return base64Str; + /*setState(() { + base64TEST = base64Str; + });*/ + } + ); + }); + + //return file; + } else { + //return null; // 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); + //var teeest = await DatabaseHelper.instance.getData(DatabaseTableType.configurations); - 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)); + // TODO handle other type of section + if(section.type == SectionType.Article) { + // Download all images.. + ArticleDTO? articleDTO = ArticleDTO.fromJson(jsonDecode(section.data!)); + + if(articleDTO != null) { + for(var image in articleDTO!.images!) { + await getAndDownloadImage(appContext.clientAPI, image); + } + } + } + } } @@ -217,7 +256,7 @@ class _HomePageState extends State { 'configurationId': section.configurationId, 'isSubSection': section.isSubSection, 'parentId': section.parentId, - 'type': section.type!.toJson(), + 'type': section.type!.value, 'data': section.data, 'dateCreation': section.dateCreation!.toUtc().toIso8601String(), 'orderOfElement': section.order, diff --git a/manager_api/lib/model/resource_type.dart b/manager_api/lib/model/resource_type.dart index f7e6d41..cbdb6fa 100644 --- a/manager_api/lib/model/resource_type.dart +++ b/manager_api/lib/model/resource_type.dart @@ -23,17 +23,17 @@ class ResourceType { int toJson() => value; - static const number0 = ResourceType._(0); - static const number1 = ResourceType._(1); - static const number2 = ResourceType._(2); - static const number3 = ResourceType._(3); + static const Image = ResourceType._(0); + static const Video = ResourceType._(1); + static const ImageUrl = ResourceType._(2); + static const VideoUrl = ResourceType._(3); /// List of all possible values in this [enum][ResourceType]. static const values = [ - number0, - number1, - number2, - number3, + Image, + Video, + ImageUrl, + VideoUrl ]; static ResourceType? fromJson(dynamic value) => ResourceTypeTypeTransformer().decode(value); @@ -72,10 +72,10 @@ class ResourceTypeTypeTransformer { ResourceType? decode(dynamic data, {bool allowNull = true}) { if (data != null) { switch (data) { - case 0: return ResourceType.number0; - case 1: return ResourceType.number1; - case 2: return ResourceType.number2; - case 3: return ResourceType.number3; + case "Image": return ResourceType.Image; + case "Video": return ResourceType.Video; + case "ImageUrl": return ResourceType.ImageUrl; + case "VideoUrl": return ResourceType.VideoUrl; default: if (!allowNull) { throw ArgumentError('Unknown enum value to decode: $data');