import 'dart:convert'; import 'dart:io'; import 'dart:typed_data'; //import 'package:confetti/confetti.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:manager_api_new/api.dart'; import 'package:mymuseum_visitapp/Components/CustomAppBar.dart'; import 'package:mymuseum_visitapp/Components/loading_common.dart'; import 'package:mymuseum_visitapp/Helpers/DatabaseHelper.dart'; import 'package:mymuseum_visitapp/Helpers/translationHelper.dart'; import 'package:mymuseum_visitapp/Models/articleRead.dart'; import 'package:mymuseum_visitapp/Models/resourceModel.dart'; import 'package:mymuseum_visitapp/Models/visitContext.dart'; import 'package:mymuseum_visitapp/Screens/Sections/Article/article_page.dart'; import 'package:mymuseum_visitapp/Screens/Sections/Map/map_context.dart'; import 'package:mymuseum_visitapp/Screens/Sections/Map/map_page.dart'; import 'package:mymuseum_visitapp/Screens/Sections/PDF/pdf_page.dart'; import 'package:mymuseum_visitapp/Screens/Sections/Puzzle/puzzle_page.dart'; import 'package:mymuseum_visitapp/Screens/Sections/Quiz/quizz_page.dart'; import 'package:mymuseum_visitapp/Screens/Sections/Slider/slider_page.dart'; import 'package:mymuseum_visitapp/Screens/Sections/Video/video_page.dart'; import 'package:mymuseum_visitapp/Screens/Sections/Weather/weather_page.dart'; import 'package:mymuseum_visitapp/Screens/Sections/Web/web_page.dart'; import 'package:mymuseum_visitapp/app_context.dart'; import 'package:mymuseum_visitapp/client.dart'; import 'package:provider/provider.dart'; import 'package:http/http.dart' as http; import 'package:image/image.dart' as IMG; import 'dart:ui' as ui; import 'package:path_provider/path_provider.dart'; class SectionPage extends StatefulWidget { const SectionPage({Key? key, required this.rawSection, required this.visitAppContextIn, required this.configuration, required this.sectionId}) : super(key: key); final Object? rawSection; final String sectionId; final ConfigurationDTO configuration; final VisitAppContext visitAppContextIn; @override State createState() => _SectionPageState(); } class _SectionPageState extends State { final GlobalKey _scaffoldKey = GlobalKey(); SectionDTO? sectionDTO; late VisitAppContext visitAppContext; late dynamic rawSectionData; List resourcesModel = []; late final MapContext mapContext = MapContext(null); List>? icons; @override void initState() { widget.visitAppContextIn.isContentCurrentlyShown = true; super.initState(); } @override void dispose() { visitAppContext.isContentCurrentlyShown = false; super.dispose(); } @override Widget build(BuildContext context) { final appContext = Provider.of(context); Size size = MediaQuery.of(context).size; visitAppContext = appContext.getContext(); var test = SectionDTO.fromJson(jsonDecode(jsonEncode(widget.rawSection))); return Scaffold( key: _scaffoldKey, resizeToAvoidBottomInset: false, appBar: test!.type == SectionType.Menu || test.type == SectionType.Agenda ? CustomAppBar( title: sectionDTO != null ? TranslationHelper.get(sectionDTO!.title, visitAppContext) : "", isHomeButton: false, ) : null, body: MediaQuery.removeViewInsets( context: context, removeBottom: true, child: OrientationBuilder( builder: (context, orientation) { return FutureBuilder( future: getSectionDetail(appContext, visitAppContext.clientAPI, widget.sectionId), builder: (context, AsyncSnapshot snapshot) { var sectionResult = snapshot.data; if(sectionDTO != null && sectionResult != null) { switch(sectionDTO!.type) { case SectionType.Article: ArticleDTO articleDTO = ArticleDTO.fromJson(sectionResult)!; return ArticlePage(visitAppContextIn: widget.visitAppContextIn, articleDTO: articleDTO, resourcesModel: resourcesModel); case SectionType.Quiz: QuizDTO quizDTO = QuizDTO.fromJson(sectionResult)!; return QuizPage(visitAppContextIn: widget.visitAppContextIn, quizDTO: quizDTO, resourcesModel: resourcesModel); case SectionType.Web: WebDTO webDTO = WebDTO.fromJson(sectionResult)!; return WebPage(section: webDTO); case SectionType.Pdf: PdfDTO pdfDTO = PdfDTO.fromJson(sectionResult)!; return PDFPage(section: pdfDTO); case SectionType.Video: VideoDTO videoDTO = VideoDTO.fromJson(sectionResult)!; return VideoPage(section: videoDTO); case SectionType.Puzzle: PuzzleDTO puzzleDTO = PuzzleDTO.fromJson(sectionResult)!; return PuzzlePage(section: puzzleDTO); case SectionType.Slider: SliderDTO sliderDTO = SliderDTO.fromJson(sectionResult)!; return SliderPage(section: sliderDTO); case SectionType.Map: MapDTO mapDTO = MapDTO.fromJson(sectionResult)!; return ChangeNotifierProvider.value( value: mapContext, child: MapPage(section: mapDTO, icons: icons ?? []), ); case SectionType.Weather: WeatherDTO weatherDTO = WeatherDTO.fromJson(sectionResult)!; return WeatherPage(section: weatherDTO); default: return const Center(child: Text("Unsupported type")); } } else { return const LoadingCommon(); } } ); } ), ) ); } Future getSectionDetail(AppContext appContext, Client client, String sectionId) async { try { bool isConfigOffline = widget.configuration.isOffline!; if(widget.rawSection == null) { if(isConfigOffline) { // OFFLINE List> sectionTest = await DatabaseHelper.instance.queryWithColumnId(DatabaseTableType.sections, sectionId); if(sectionTest.isNotEmpty) { sectionDTO = DatabaseHelper.instance.getSectionFromDB(sectionTest.first); try { SectionRead sectionRead = SectionRead(id: sectionDTO!.id!, readTime: DateTime.now().millisecondsSinceEpoch); await DatabaseHelper.instance.insert(DatabaseTableType.articleRead, sectionRead.toMap()); visitAppContext.readSections.add(sectionRead); appContext.setContext(visitAppContext); } catch (e) { print("DATABASE ERROR SECTIONREAD"); print(e); } } else { print("EMPTY SECTION"); } } else { // ONLINE rawSectionData = await client.sectionApi!.sectionGetDetail(sectionId); SectionDTO sectionOnline = jsonDecode(jsonEncode(rawSectionData)).map((json) => SectionDTO.fromJson(json)).whereType().toList(); sectionDTO = sectionOnline; } /*setState(() { //print(sectionDTO!.title); });*/ } else { rawSectionData = widget.rawSection; sectionDTO = SectionDTO.fromJson(jsonDecode(jsonEncode(rawSectionData))); } switch(sectionDTO!.type) { case SectionType.Quiz: QuizDTO? quizDTO = QuizDTO.fromJson(rawSectionData); if(quizDTO != null) { quizDTO.questions!.sort((a, b) => a.order!.compareTo(b.order!)); if(quizDTO.questions != null && quizDTO.questions!.isNotEmpty) { quizDTO.questions!.sort((a, b) => a.order!.compareTo(b.order!)); for (var question in quizDTO.questions!) { if(isConfigOffline) { // OFFLINE if(question.imageBackgroundResourceId != null) { List> ressourceQuizz = await DatabaseHelper.instance.queryWithColumnId(DatabaseTableType.resources, question.imageBackgroundResourceId!); if(ressourceQuizz.isNotEmpty) { resourcesModel.add(DatabaseHelper.instance.getResourceFromDB(ressourceQuizz.first)); } else { print("EMPTY resourcesModel - second"); } } } else { // ONLINE if(question.imageBackgroundResourceId != null) { resourcesModel.add(ResourceModel(id: question.imageBackgroundResourceId, source: question.imageBackgroundResourceUrl, type: ResourceType.Image)); } } } } } break; case SectionType.Article: ArticleDTO articleDTO = ArticleDTO.fromJson(rawSectionData)!; var audioToDownload = articleDTO.audioIds!.firstWhere((a) => a.language == visitAppContext.language!); if(audioToDownload.value != null) { if(isConfigOffline) { // OFFLINE List> ressourceArticle = await DatabaseHelper.instance.queryWithColumnId(DatabaseTableType.resources, audioToDownload.value!); if(ressourceArticle.isNotEmpty) { resourcesModel.add(DatabaseHelper.instance.getResourceFromDB(ressourceArticle.first)); } else { print("EMPTY resourcesModel - second"); } } else { // ONLINE ResourceDTO? resourceDTO = await client.resourceApi!.resourceGetDetail(audioToDownload.value!); if(resourceDTO != null && resourceDTO.url != null) { // ONLINE //ResourceModel? resourceAudioOnline = await ApiService.downloadAudio(client, resourceDTO.url!, resourceDTO.id!); ResourceModel resourceAudioOnline = ResourceModel(); resourceAudioOnline.id = resourceDTO.id; resourceAudioOnline.source = resourceDTO.url; resourceAudioOnline.type = ResourceType.Audio; resourcesModel.add(resourceAudioOnline); /*Uint8List base64String = base64Decode(resourceAudioOnline.path!); // GET FROM FILE audiobytes = base64String;*/ } else { print("EMPTY resourcesModel online - audio"); } } } break; case SectionType.Map: MapDTO mapDTO = MapDTO.fromJson(rawSectionData)!; icons = await getByteIcons(visitAppContext, mapDTO); break; default: break; } return rawSectionData; } catch (e) { print(e); print("IN CATCH"); return null; } } } Future getBytesFromAsset(ByteData data, int width) async { //ByteData data = await rootBundle.load(path); ui.Codec codec = await ui.instantiateImageCodec(data.buffer.asUint8List(), targetWidth: width); ui.FrameInfo fi = await codec.getNextFrame(); return (await fi.image.toByteData(format: ui.ImageByteFormat.png))!.buffer.asUint8List(); } Uint8List resizeImage(Uint8List data, int width) { Uint8List resizedData = data; IMG.Image img = IMG.decodeImage(data)!; IMG.Image resized = IMG.copyResize(img, width: width); resizedData = Uint8List.fromList(IMG.encodeJpg(resized)); return resizedData; } Future _checkIfLocalResourceExists(VisitAppContext visitAppContext, String iconId) async { try { Directory? appDocumentsDirectory = Platform.isIOS ? await getApplicationDocumentsDirectory() : await getDownloadsDirectory(); String localPath = appDocumentsDirectory!.path; Directory configurationDirectory = Directory('$localPath/${visitAppContext.configuration!.id}'); List fileList = configurationDirectory.listSync(); if(fileList.any((fileL) => fileL.uri.pathSegments.last.contains(iconId))) { File file = File(fileList.firstWhere((fileL) => fileL.uri.pathSegments.last.contains(iconId)).path); return file; } } catch(e) { print("ERROR _checkIfLocalResourceExists CachedCustomResource"); print(e); } return null; } Future>> getByteIcons(VisitAppContext visitAppContext, MapDTO mapDTO) async { //var mapDTO = MapDTO.fromJson(jsonDecode(section.data!)); Uint8List selectedMarkerIcon; if (mapDTO.iconSource != null) { if (kIsWeb) { Uint8List fileData = await http.readBytes(Uri.parse(mapDTO.iconSource!)); selectedMarkerIcon = resizeImage(fileData, 40); } else { File? localIcon = await _checkIfLocalResourceExists(visitAppContext, mapDTO.iconResourceId!); if(localIcon == null) { final ByteData imageData = await NetworkAssetBundle(Uri.parse(mapDTO.iconSource!)).load(""); selectedMarkerIcon = await getBytesFromAsset(imageData, 50); } else { Uint8List bytes = await localIcon.readAsBytes(); selectedMarkerIcon = await getBytesFromAsset(ByteData.view(bytes.buffer), 50); } } } else { // Icône par défaut final ByteData bytes = await rootBundle.load('assets/icons/marker.png'); selectedMarkerIcon = await getBytesFromAsset(bytes, 25); } List> icons = []; icons.add({'id': null, 'icon': selectedMarkerIcon}); // Utiliser Future.forEach() pour itérer de manière asynchrone sur la liste des catégories await Future.forEach(mapDTO.categories!, (cat) async { if (cat.resourceDTO != null && cat.resourceDTO!.url != null && cat.resourceDTO!.id != null) { Uint8List categoryIcon; if (kIsWeb) { categoryIcon = await http.readBytes(Uri.parse(cat.resourceDTO!.url!)); } else { File? localIcon = await _checkIfLocalResourceExists(visitAppContext, cat.resourceDTO!.id!); if(localIcon == null) { final ByteData imageData = await NetworkAssetBundle(Uri.parse(cat.resourceDTO!.url!)).load(""); categoryIcon = await getBytesFromAsset(imageData, 50); } else { Uint8List bytes = await localIcon.readAsBytes(); categoryIcon = await getBytesFromAsset(ByteData.view(bytes.buffer), 50); } } icons.add({'id': cat.id, 'icon': categoryIcon}); } }); return icons; }