mymuseum-visitapp/lib/Screens/section_page.dart
2025-07-04 17:21:17 +02:00

368 lines
15 KiB
Dart

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/Agenda/agenda_page.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/Menu/menu_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<SectionPage> createState() => _SectionPageState();
}
class _SectionPageState extends State<SectionPage> {
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
SectionDTO? sectionDTO;
late VisitAppContext visitAppContext;
late dynamic rawSectionData;
List<ResourceModel?> resourcesModel = <ResourceModel?>[];
late final MapContext mapContext = MapContext(null);
List<Map<String, dynamic>>? icons;
String? mainAudioId;
@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<AppContext>(context);
Size size = MediaQuery.of(context).size;
visitAppContext = appContext.getContext();
var test = SectionDTO.fromJson(jsonDecode(jsonEncode(widget.rawSection)));
return Scaffold(
key: _scaffoldKey,
resizeToAvoidBottomInset: false,
body: MediaQuery.removeViewInsets(
context: context,
removeBottom: true,
child: OrientationBuilder(
builder: (context, orientation) {
return FutureBuilder(
future: getSectionDetail(appContext, visitAppContext.clientAPI, widget.sectionId),
builder: (context, AsyncSnapshot<dynamic> snapshot) {
var sectionResult = snapshot.data;
if(sectionDTO != null && sectionResult != null) {
switch(sectionDTO!.type) {
case SectionType.Agenda:
AgendaDTO agendaDTO = AgendaDTO.fromJson(sectionResult)!;
return AgendaPage(section: agendaDTO);
case SectionType.Article:
ArticleDTO articleDTO = ArticleDTO.fromJson(sectionResult)!;
return ArticlePage(
visitAppContextIn: widget.visitAppContextIn,
articleDTO: articleDTO,
resourcesModel: resourcesModel,
mainAudioId: mainAudioId,
);
case SectionType.Map:
MapDTO mapDTO = MapDTO.fromJson(sectionResult)!;
return ChangeNotifierProvider<MapContext>.value(
value: mapContext,
child: MapPage(section: mapDTO, icons: icons ?? []),
);
case SectionType.Menu:
MenuDTO menuDTO = MenuDTO.fromJson(sectionResult)!;
return MenuPage(section: menuDTO, isImageBackground: widget.configuration.isSectionImageBackground!);
case SectionType.Pdf:
PdfDTO pdfDTO = PdfDTO.fromJson(sectionResult)!;
return PDFPage(section: pdfDTO);
case SectionType.Puzzle:
PuzzleDTO puzzleDTO = PuzzleDTO.fromJson(sectionResult)!;
return PuzzlePage(section: puzzleDTO);
case SectionType.Quiz:
QuizDTO quizDTO = QuizDTO.fromJson(sectionResult)!;
return QuizPage(
visitAppContextIn: widget.visitAppContextIn,
quizDTO: quizDTO,
resourcesModel: resourcesModel,
);
case SectionType.Slider:
SliderDTO sliderDTO = SliderDTO.fromJson(sectionResult)!;
return SliderPage(section: sliderDTO);
case SectionType.Video:
VideoDTO videoDTO = VideoDTO.fromJson(sectionResult)!;
return VideoPage(section: videoDTO);
case SectionType.Weather:
WeatherDTO weatherDTO = WeatherDTO.fromJson(sectionResult)!;
return WeatherPage(section: weatherDTO);
case SectionType.Web:
WebDTO webDTO = WebDTO.fromJson(sectionResult)!;
return WebPage(section: webDTO);
default:
return const Center(child: Text("Unsupported type"));
}
} else {
return const LoadingCommon();
}
}
);
}
),
)
);
}
Future<dynamic> getSectionDetail(AppContext appContext, Client client, String sectionId) async {
try {
bool isConfigOffline = widget.configuration.isOffline!;
if(widget.rawSection == null) {
if(isConfigOffline)
{
// OFFLINE
List<Map<String, dynamic>> 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<SectionDTO>().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<Map<String, dynamic>> 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!).value;
var othersToDownload = articleDTO.contents!.map((c) => c.resourceId);
mainAudioId = audioToDownload;
var resourcesToDownload = [];
resourcesToDownload.add(audioToDownload);
resourcesToDownload.addAll(othersToDownload);
for (var resourceToDownload in resourcesToDownload) {
if(isConfigOffline)
{
// OFFLINE
List<Map<String, dynamic>> ressourceArticle = await DatabaseHelper.instance.queryWithColumnId(DatabaseTableType.resources, resourceToDownload);
if(ressourceArticle.isNotEmpty) {
resourcesModel.add(DatabaseHelper.instance.getResourceFromDB(ressourceArticle.first));
} else {
print("EMPTY resourcesModel - second");
}
}
else
{
// ONLINE
ResourceDTO? resourceDTO = await client.resourceApi!.resourceGetDetail(resourceToDownload);
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 = resourceDTO.type;
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<Uint8List> 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<File?> _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<FileSystemEntity> 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<List<Map<String, dynamic>>> 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<Map<String, dynamic>> 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;
}