Thomas Fransolet 9f582dd8a7 Lot K : tablet-app reconstruit et rebranché sur le contrat Postgres v3
Premier vrai build depuis avril. Le diagnostic des docs — « un seul défaut,
purement Gradle, peut-être réglé par 5a6701d » — tenait parce que personne
n'avait lancé la commande.

K1 — dix crans d'outillage, chacun dicté par l'erreur du précédent :
Gradle 7.5 → 8.11.1, AGP 7.2.0 → 8.9.1, Kotlin 1.9.0 → 2.3.10,
enableUncompressedNativeLibs retirée (supprimée en AGP 8.1), jcenter → mavenCentral,
heap 1536M → 4096M, Jetifier coupé, et retrait du resolutionStrategy qui forçait
androidx.lifecycle à 2.4.0 « to fix mapbox issue » : il réglait un problème d'il y
a trois ans et causait celui d'aujourd'hui, mapbox_maps_flutter 2.21.1 appelant
setViewTreeLifecycleOwner. Les trois derniers crans étaient de simples alignements
sur mymuseum-visitapp, qui utilise le même plugin sans ces problèmes.

Le bloc buildscript commenté de android/build.gradle est supprimé : il déclarait
une config qui n'était pas celle appliquée et a fait conclure deux fois à tort.

K2 — les 132 erreurs Dart que le Gradle masquait. Trois causes : roundedValue,
isDate, isHour, isSectionImageBackground et screenPercentageSectionsMainPage ont
migré vers AppConfigurationLink ; GeoPointDTO.latitude/longitude sont devenus
geometry ; le reste en découlait. Deux bugs latents trouvés au passage :

- applicationInstanceDTO n'était assigné que si l'instance avait l'IA — il servait
  de drapeau d'assistant. Ce DTO portant désormais les AppConfigurationLink, les
  cinq réglages seraient retombés sur leurs défauts sur MDLF et le Fort, sans
  erreur ni log. Drapeau rendu explicite, en préservant le ET instance × canal.
- ConfigurationDTO.isTablet ayant disparu, le filtre des configurations tablette
  n'avait plus de source : il porte sur les liens du canal AppType.Tablet.

La formule de clé par coordonnées de geo_point_filter, dupliquée à quatre endroits
alors que les deux côtés de l'appariement doivent produire la même valeur, ne vit
plus qu'à un seul (Helpers/geo.dart). Ce fichier documente aussi les deux
conventions de coordonnées du projet : [lng, lat] pour les GeoPoint, [lat, lng]
pour les géométries de GuidedStep.

K4 — l'écran Game repris de mymuseum-visitapp, Screens/Puzzle supprimé. La tablette
gagne le puzzle glissant, le bouton d'indice et un dimensionnement au ratio de
l'image. Les couleurs, codées en dur par flavor client chez mymuseum, sont dérivées
de configuration.primaryColor : tablet-app n'a pas de flavor, un seul APK sert tous
les clients.

Reste à vérifier sur device : le rendu de l'écran Game, et l'écran de sélection de
configuration, qui sera vide si les configurations ne sont pas rattachées au canal
tablette.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-12 12:18:07 +02:00

662 lines
30 KiB
Dart

import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'dart:math';
import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/services.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_widget_from_html/flutter_widget_from_html.dart';
import 'package:manager_api_new/api.dart';
import 'package:package_info_plus/package_info_plus.dart';
import 'package:path_provider/path_provider.dart';
import 'package:provider/provider.dart';
import 'package:tablet_app/Services/statisticsService.dart';
import 'package:tablet_app/Components/loading_common.dart';
import 'package:tablet_app/Helpers/DatabaseHelper.dart';
import 'package:tablet_app/Helpers/ImageCustomProvider.dart';
import 'package:tablet_app/Helpers/MQTTHelper.dart';
import 'package:tablet_app/Helpers/translationHelper.dart';
import 'package:tablet_app/Screens/Agenda/agenda_view.dart';
import 'package:tablet_app/Screens/Article/article_view.dart';
import 'package:tablet_app/Screens/Configuration/config_view.dart';
import 'package:tablet_app/Screens/MainView/section_page_detail.dart';
import 'package:tablet_app/Screens/Weather/weather_view.dart';
import 'package:tablet_app/Screens/Map/map_context.dart';
import 'package:tablet_app/Screens/Map/map_view.dart';
import 'package:tablet_app/Models/tabletContext.dart';
import 'package:tablet_app/Screens/Menu/menu_view.dart';
import 'package:tablet_app/Screens/PDF/pdf_view.dart';
import 'package:tablet_app/Screens/Game/game_page.dart';
import 'package:tablet_app/Screens/Slider/slider_view.dart';
import 'package:tablet_app/Screens/Video/video_view.dart';
import 'package:tablet_app/Screens/Web/web_view.dart';
import 'package:tablet_app/Services/downloadService.dart';
import 'package:tablet_app/app_context.dart';
import 'package:tablet_app/constants.dart';
import 'package:intl/intl.dart';
import 'package:http/http.dart' as http;
import 'package:image/image.dart' as IMG;
import 'dart:ui' as ui;
import 'package:tablet_app/Components/assistant_chat_view.dart';
import '../Quizz/quizz_view.dart';
import 'language_selection.dart';
class MainViewWidget extends StatefulWidget {
MainViewWidget();
@override
_MainViewWidget createState() => _MainViewWidget();
}
class _MainViewWidget extends State<MainViewWidget> {
Size sizeScreen = new Size(1080.0, 1920.0); // Tablet resolution
SectionDTO? sectionSelected;
late ConfigurationDTO configurationDTO;
/// isDate, isHour, isSectionImageBackground et screenPercentageSectionsMainPage
/// ont quitté ConfigurationDTO avec Postgres v3 : ils vivent sur le lien
/// instance ↔ configuration.
AppConfigurationLink? appConfigurationLink;
ValueNotifier<DateTime?> currentHourDate = ValueNotifier<DateTime?>((DateTime.now().toUtc()).add(Duration(hours: 1)));
late Color backgroundColor;
int rowCount = 4;
bool isImageBackground = false;
List<SectionDTO>? sectionsLocal;
late List<dynamic> rawSectionsData;
bool isInit = true; // Use to make it faster and to load resource at init
bool isDialogOpen = false;
@override
void initState() {
final appContext = Provider.of<AppContext>(context, listen: false);
configurationDTO = appContext.getContext().configuration;
appConfigurationLink = appContext.getContext().currentAppConfigurationLink;
if(appConfigurationLink?.isHour == true) {
Timer.periodic(Duration(seconds: 1), (Timer t) => _getTime(currentHourDate));
}
isImageBackground = appConfigurationLink?.isSectionImageBackground ?? true;
super.initState();
}
void _getTime(ValueNotifier<DateTime?> valueNotifier) {
//final DateTime now = DateTime.now();
//final String formattedDateTime = _formatDateTime(now);
//setState(() {
//_timeString = formattedDateTime;
valueNotifier.value = (DateTime.now().toUtc()).add(Duration(hours: 2));
//});
}
@override
Widget build(BuildContext context) {
final appContext = Provider.of<AppContext>(context);
SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: []);
Size size = MediaQuery.of(context).size;
backgroundColor = appContext.getContext().configuration != null ? new Color(int.parse(appContext.getContext().configuration.secondaryColor.split('(0x')[1].split(')')[0], radix: 16)) : Colors.white;
Color textColor = backgroundColor.computeLuminance() > 0.5 ? Colors.black : Colors.white;
TabletAppContext tabletAppContext = appContext.getContext() as TabletAppContext;
// TODO REMOVE
/*if (!MQTTHelper.instance.isInstantiated)
MQTTHelper.instance.connect(appContext);*/
return Scaffold(
resizeToAvoidBottomInset: false,
body: Container(
height: size.height,
width: size.width,
color: configurationDTO.imageId == null ? configurationDTO.secondaryColor != null ? backgroundColor : kBackgroundGrey : null,
decoration: configurationDTO.imageId != null ? BoxDecoration(
image: new DecorationImage(
fit: BoxFit.cover,
colorFilter: new ColorFilter.mode(Colors.grey.withValues(alpha: 0.1), BlendMode.color),
image: ImageCustomProvider.getImageProvider(appContext, configurationDTO.imageId!, configurationDTO.imageSource!)
),
) : null,
child: Stack(
children: [
if(currentHourDate.value != null)
ValueListenableBuilder<DateTime?>(
valueListenable: currentHourDate,
builder: (context, value, _) {
return Positioned(
top: 0,
left: 0,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if(value != null && appConfigurationLink?.isHour == true)
Text(DateFormat('HH:mm').format(value), style: TextStyle(fontSize: 20, color: textColor)),
if(value != null && appConfigurationLink?.isDate == true)
if(appContext.getContext().language.toString().toUpperCase() == "EN")
Text(DateFormat('MM/dd').format(value), style: TextStyle(fontSize: 15, color: textColor)),
if(value != null && appConfigurationLink?.isDate == true)
if(appContext.getContext().language.toString().toUpperCase() != "EN")
Text(DateFormat('dd/MM').format(value), style: TextStyle(fontSize: 15, color: textColor)),
],
),
)
);
},
),
LanguageSelection(size: size),
Center(
child: Container(
height: appConfigurationLink?.screenPercentageSectionsMainPage != null ? size.height * (appConfigurationLink!.screenPercentageSectionsMainPage! / 100) : size.height * 0.85,
width: size.width * 0.9,
child: isInit ? FutureBuilder(
future: getSections(size, appContext),
builder: (context, AsyncSnapshot<dynamic> snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
if (snapshot.data == null) {
// Show select config
return Text("");
}
else {
return getGridSections(appContext, textColor);
}
} else if (snapshot.connectionState == ConnectionState.none) {
return Text("No data");
} else {
return Center(
child: Container(
child: LoadingCommon()
)
);
}
}
) : getGridSections(appContext, textColor),
),
),
Positioned(
bottom: 0,
right: 0,
child: Padding(
padding: const EdgeInsets.all(4.0),
child: FutureBuilder(
future: getPlatformInfo(),
builder: (context, AsyncSnapshot<dynamic> snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
return Text(snapshot.data.version, style: TextStyle(fontSize: 8));
}
return SizedBox();
}
),
)
),
if (tabletAppContext.isAssistantEnabled)
Positioned(
bottom: 24,
right: 24,
child: FloatingActionButton.extended(
backgroundColor: kMainGrey,
icon: const Icon(Icons.chat_bubble_outline, color: Colors.white),
label: const Text("Assistant", style: TextStyle(color: Colors.white, fontSize: 16)),
onPressed: () {
showGeneralDialog(
context: context,
barrierDismissible: true,
barrierLabel: 'Assistant',
barrierColor: Colors.black45,
transitionDuration: const Duration(milliseconds: 250),
pageBuilder: (dialogContext, __, ___) => Align(
alignment: Alignment.centerRight,
child: AssistantChatView(
tabletAppContext: tabletAppContext,
configurationId: tabletAppContext.configuration?.id,
onNavigateToSection: (sectionId, sectionTitle) {
Navigator.of(dialogContext).pop();
final index = sectionsLocal?.indexWhere((s) => s.id == sectionId) ?? -1;
if (index >= 0) {
Navigator.push(context, MaterialPageRoute(
builder: (_) => SectionPageDetail(
configurationDTO: configurationDTO,
sectionDTO: sectionsLocal![index],
textColor: textColor,
isImageBackground: isImageBackground,
elementToShow: getContent(tabletAppContext, sectionsLocal![index], isImageBackground, rawSectionsData[index]),
isFromMenu: false,
),
));
}
},
),
),
);
},
),
)
/*if(configurationDTO.weatherCity != null && configurationDTO.weatherCity!.length > 2 && configurationDTO.weatherResult != null)
Positioned(
bottom: 0,
left: 0,
child: Padding(
padding: const EdgeInsets.all(5.0),
child: Builder(
builder: (context) {
Map<String, dynamic> weatherResultInJson = jsonDecode(configurationDTO.weatherResult!);
WeatherData weatherDataResult = WeatherData.fromJson(weatherResultInJson);
return WeatherView(weatherData: weatherDataResult);
}
),
))*/
]),
),
);
}
Future<ConfigurationDTO?> getCurrentConfiguration(dynamic appContext) async {
TabletAppContext tabletAppContext = await appContext.getContext();
try {
ConfigurationDTO? configurationDTO = await tabletAppContext.clientAPI!.configurationApi!.configurationGetDetail(tabletAppContext.configuration!.id!); // tabletAppContext.configuration!.id! // 65c5f0ee4c030e63ce16bff5 TODO Remove
tabletAppContext.configuration = configurationDTO;
backgroundColor = tabletAppContext.configuration != null ? new Color(int.parse(appContext.getContext().configuration.secondaryColor.split('(0x')[1].split(')')[0], radix: 16)) : Colors.white;
TabletAppContext? localContext = await DatabaseHelper.instance.getData();
if (localContext != null) { // Check if sql DB exist
await DatabaseHelper.instance.update(tabletAppContext);
} else {
await DatabaseHelper.instance.insert(tabletAppContext);
}
/*
appContext.setContext(tabletAppContext);
// STORE IT LOCALLY (SQLite)
TabletAppContext? localContext = await DatabaseHelper.instance.getData();
if (localContext != null) { // Check if sql DB exist
await DatabaseHelper.instance.update(tabletAppContext);
} else {
await DatabaseHelper.instance.insert(tabletAppContext);
}*/
return configurationDTO;
} catch (e) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('Une erreur est survenue lors de la récupération de la configuration'),
),
);
}
}
Future<List<SectionDTO>?> getSections(Size size, dynamic appContext) async {
TabletAppContext tabletAppContext = await appContext.getContext();
// DIALOG HERE
if(!isDialogOpen) {
isDialogOpen = true;
var result = await showDialog(
builder: (BuildContext dialogContext) => AlertDialog(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(tabletAppContext.currentAppConfigurationLink?.roundedValue?.toDouble() ?? 20.0))
),
content: Container(
width: 400,
height: 200,
child: DownloadConfigurationWidget(),
),
actions: <Widget>[],
), context: context
);
isDialogOpen = false;
} else {
print("ALREADY OPEN LAAAA");
}
await getCurrentConfiguration(appContext);
// Load applicationInstanceDTO to check if assistant/statistics are enabled
try {
if (tabletAppContext.instanceId != null) {
final instanceDTO = await tabletAppContext.clientAPI!.instanceApi!.instanceGetDetail(tabletAppContext.instanceId!);
if (instanceDTO != null && instanceDTO.applicationInstanceDTOs != null) {
final tabletInstance = instanceDTO.applicationInstanceDTOs!
.where((a) => a.appType == AppType.Tablet)
.firstOrNull;
if (tabletInstance != null) {
// Assigné inconditionnellement : ce DTO ne sert plus seulement de drapeau
// d'assistant, il porte aussi les AppConfigurationLink d'où viennent
// roundedValue, isDate, isHour, isSectionImageBackground et
// screenPercentageSectionsMainPage depuis Postgres v3. Le laisser null
// sur une instance sans IA renverrait tous ces réglages à leurs valeurs
// par défaut, sans erreur visible.
tabletAppContext.applicationInstanceDTO = tabletInstance;
tabletAppContext.isAssistantEnabled =
instanceDTO.isAssistant == true && tabletInstance.isAssistant == true;
if (tabletInstance.hasStats == true) {
tabletAppContext.statisticsService = StatisticsService(
clientAPI: tabletAppContext.clientAPI!,
instanceId: tabletAppContext.instanceId,
configurationId: tabletAppContext.configuration?.id,
appType: 'Tablet',
language: tabletAppContext.language,
);
}
}
}
appContext.setContext(tabletAppContext);
}
} catch (e) {
print('Failed to load applicationInstanceDTO: $e');
}
print(sectionsLocal);
if(isInit) {
try {
final rawList = await tabletAppContext.clientAPI!.sectionApi!.sectionGetFromConfigurationDetail(tabletAppContext.configuration!.id!);
rawSectionsData = jsonDecode(jsonEncode(rawList));
List<SectionDTO> sectionList = jsonDecode(jsonEncode(rawSectionsData)).map((json) => SectionDTO.fromJson(json)).whereType<SectionDTO>().toList();
sectionsLocal = sectionList;
isInit = false;
return sectionList;
} catch (e) {
print(e);
print("IN CATCH");
Navigator.pushAndRemoveUntil(
context,
MaterialPageRoute(
builder: (context) {
return ConfigViewWidget();
},
),
(Route<dynamic> route) => false // For pushAndRemoveUntil
);
}
}
return sectionsLocal;
}
getGridSections(AppContext appContext, Color textColor) {
TabletAppContext tabletAppContext = appContext.getContext() as TabletAppContext;
if(sectionsLocal != null) {
var isPortrait = MediaQuery.of(context).orientation == Orientation.portrait;
return Center(
child: Container(
//color: Colors.greenAccent,
child: GridView.builder(
shrinkWrap: true,
gridDelegate: new SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: rowCount),
itemCount: sectionsLocal!.length,
itemBuilder: (BuildContext context, int index) {
return InkWell(
onTap: () {
setState(() {
//sectionSelected = sectionsLocal![index];
Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return SectionPageDetail(configurationDTO: configurationDTO, sectionDTO: sectionsLocal![index], textColor: textColor, isImageBackground: isImageBackground, elementToShow: getContent(tabletAppContext, sectionsLocal![index], isImageBackground, rawSectionsData[index]), isFromMenu: false);
},
),// For pushAndRemoveUntil
);
});
},
child: Container(
decoration: isImageBackground ? boxDecoration(appContext, sectionsLocal![index], false, rawSectionsData[index]) : null,
//color: Colors.yellow,
padding: EdgeInsets.all(isImageBackground ? 18 : 5),
margin: EdgeInsets.symmetric(vertical: isImageBackground ? 25 : 10, horizontal: 25),
child: isImageBackground ? Align(
alignment: Alignment.bottomRight,
child: FractionallySizedBox(
heightFactor: 0.5,
child: Container(
//color: Colors.green,
child: SizedBox(
width: double.infinity,
child: Align(
alignment: Alignment.centerRight,
child: HtmlWidget(
sectionsLocal![index].title!.firstWhere((translation) => translation.language == appContext.getContext().language).value ?? "",
customStylesBuilder: (element) {
return {'text-align': 'right', 'font-family': "Roboto"};
},
textStyle: TextStyle(fontSize: isPortrait ? 10 : 25),//calculateFontSize(constraints.maxWidth, constraints.maxHeight, kIsWeb ? kWebMenuTitleDetailSize : kMenuTitleDetailSize)),
),
),
),
)
),
) : Column(
children: [
Expanded(
flex: 8,
child: Container(
decoration: BoxDecoration(
color: sectionsLocal![index].imageSource == null ? kBackgroundLight : null, // default color if no image
shape: BoxShape.rectangle,
image: sectionsLocal![index].imageSource != null || sectionsLocal![index].type == SectionType.Video ? new DecorationImage(
fit: BoxFit.cover,
image: ImageCustomProvider.getImageProvider(appContext, sectionsLocal![index].imageId, sectionsLocal![index].type == SectionType.Video ? getYoutubeThumbnailUrl(rawSectionsData[index]) : sectionsLocal![index].imageSource!),
): null,
),
)
),
Expanded(
flex: 2,
child: Center(
child: HtmlWidget(
sectionsLocal![index].title!.where((translation) => translation.language == appContext.getContext().language).firstOrNull?.value ?? "",
customStylesBuilder: (element) {
return {'text-align': 'center', 'font-family': "Roboto"};
},
textStyle: TextStyle(fontSize: isPortrait ? 10 : 25),//calculateFontSize(constraints.maxWidth, constraints.maxHeight, kIsWeb ? kWebMenuTitleDetailSize : kMenuTitleDetailSize)),
),
)
)
],
)
),
);
}
),
),
);
} else {
Center(
child: Text("Aucune section à afficher", style: TextStyle(fontSize: kNoneInfoOrIncorrect)),
);
}
}
getPlatformInfo() async {
return await PackageInfo.fromPlatform();
}
}
boxDecoration(AppContext appContext, SectionDTO section, bool isSelected, Object rawSectionData) {
TabletAppContext tabletAppContext = appContext.getContext() as TabletAppContext;
return BoxDecoration(
color: !isSelected ? kBackgroundLight : section.imageSource == null ? kBackgroundLight : null,
shape: BoxShape.rectangle,
borderRadius: BorderRadius.circular(tabletAppContext.currentAppConfigurationLink?.roundedValue?.toDouble() ?? 30.0),
image: section.imageSource != null || section.type == SectionType.Video ? new DecorationImage(
fit: BoxFit.cover,
colorFilter: !isSelected? new ColorFilter.mode(kBackgroundLight.withValues(alpha: 0.2), BlendMode.dstATop) : null,
image: ImageCustomProvider.getImageProvider(appContext, section.imageId, section.type == SectionType.Video ? getYoutubeThumbnailUrl(rawSectionData) : section.imageSource!),
): null,
boxShadow: [
BoxShadow(
color: kBackgroundSecondGrey,
spreadRadius: 0.5,
blurRadius: 5,
offset: Offset(0, 1.5), // changes position of shadow
),
],
);
}
Future<List<Map<String, dynamic>>> getByteIcons(TabletAppContext tabletAppContext, MapDTO mapDTO) async {
//var mapDTO = MapDTO.fromJson(jsonDecode(section.data!));
var 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(tabletAppContext, 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(tabletAppContext, 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;
}
Future<File?> _checkIfLocalResourceExists(TabletAppContext tabletAppContext, String iconId) async {
try {
Directory? appDocumentsDirectory = Platform.isIOS ? await getApplicationDocumentsDirectory() : await getDownloadsDirectory();
String localPath = appDocumentsDirectory!.path;
Directory configurationDirectory = Directory('$localPath/${tabletAppContext.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<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;
}
Widget getContent(TabletAppContext tabletAppContext, SectionDTO sectionSelected, bool isImageBackground, Object rawSectionData) {
switch (sectionSelected.type) {
case SectionType.Map : // MAP
MapDTO mapDTO = MapDTO.fromJson(rawSectionData)!;
return ChangeNotifierProvider<MapContext>(
create: (_) =>
MapContext(null),
child: FutureBuilder(
future: getByteIcons(tabletAppContext, mapDTO),
builder: (context, AsyncSnapshot<dynamic> snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
return MapView(section: mapDTO, icons: snapshot.data);
} else if (snapshot.connectionState == ConnectionState.none) {
return Text("No data");
} else {
return Center(
child: Container(
child: LoadingCommon()
)
);
}
}
) /*FutureBuilder(
future: _url,
builder: (BuildContext context, AsyncSnapshot snapshot) => snapshot.hasData
? WebViewWidget(url: snapshot.data,)
: CircularProgressIndicator()),*/
);
case SectionType.Web : // WEB
WebDTO webDTO = WebDTO.fromJson(rawSectionData)!;
return WebView(section: webDTO);
case SectionType.Video : // Video
VideoDTO videoDTO = VideoDTO.fromJson(rawSectionData)!;
return VideoView(section: videoDTO);
case SectionType.Slider :
SliderDTO sliderDTO = SliderDTO.fromJson(rawSectionData)!;
return SliderView(section: sliderDTO);
case SectionType.Menu :
MenuDTO menuDTO = MenuDTO.fromJson(rawSectionData)!;
return MenuView(section: menuDTO, isImageBackground: isImageBackground);
case SectionType.Quiz :
QuizDTO quizDTO = QuizDTO.fromJson(rawSectionData)!;
return QuizzView(section: quizDTO);
case SectionType.Pdf :
PdfDTO pdfDTO = PdfDTO.fromJson(rawSectionData)!;
return PDFViewWidget(section: pdfDTO);
case SectionType.Game :
GameDTO gameDTO = GameDTO.fromJson(rawSectionData)!;
return GamePage(section: gameDTO);
case SectionType.Agenda :
AgendaDTO agendaDTO = AgendaDTO.fromJson(rawSectionData)!;
return AgendaView(section: agendaDTO);
/*case SectionType.article : // TODO
elementToShow = ArticleView(section: sectionSelected);
break;*/
case SectionType.Weather :
WeatherDTO weatherDTO = WeatherDTO.fromJson(rawSectionData)!;
return WeatherView(section: weatherDTO);
default:
return Center(child: Text("Ce type n'est pas supporté"));
};
}