diff --git a/lib/Screens/Scanner/scanner_old.dart b/AR-TEST/Scanner/scanner_old.dart
similarity index 100%
rename from lib/Screens/Scanner/scanner_old.dart
rename to AR-TEST/Scanner/scanner_old.dart
diff --git a/lib/Screens/Tests/DebugOptionsWidget.dart b/AR-TEST/Tests/DebugOptionsWidget.dart
similarity index 100%
rename from lib/Screens/Tests/DebugOptionsWidget.dart
rename to AR-TEST/Tests/DebugOptionsWidget.dart
diff --git a/lib/Screens/Tests/TestAR.dart b/AR-TEST/Tests/TestAR.dart
similarity index 100%
rename from lib/Screens/Tests/TestAR.dart
rename to AR-TEST/Tests/TestAR.dart
diff --git a/lib/Screens/Tests/XRTest.dart b/AR-TEST/Tests/XRTest.dart
similarity index 100%
rename from lib/Screens/Tests/XRTest.dart
rename to AR-TEST/Tests/XRTest.dart
diff --git a/lib/Screens/Tests/cloudtest.dart b/AR-TEST/Tests/cloudtest.dart
similarity index 100%
rename from lib/Screens/Tests/cloudtest.dart
rename to AR-TEST/Tests/cloudtest.dart
diff --git a/lib/Screens/Tests/localtest.dart b/AR-TEST/Tests/localtest.dart
similarity index 100%
rename from lib/Screens/Tests/localtest.dart
rename to AR-TEST/Tests/localtest.dart
diff --git a/lib/Screens/Tests/testother.dart b/AR-TEST/Tests/testother.dart
similarity index 100%
rename from lib/Screens/Tests/testother.dart
rename to AR-TEST/Tests/testother.dart
diff --git a/android/app/build.gradle b/android/app/build.gradle
index 01ad02e..9a0a51f 100644
--- a/android/app/build.gradle
+++ b/android/app/build.gradle
@@ -39,13 +39,21 @@ apply plugin: 'kotlin-android'
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"*/
android {
- compileSdkVersion 34
+ namespace = "be.unov.mymuseum.fortsaintheribert"
+ compileSdkVersion 35
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
+ packagingOptions {
+ pickFirst 'lib/arm64-v8a/libc++_shared.so'
+ pickFirst 'lib/x86_64/libc++_shared.so'
+ pickFirst 'lib/x86/libc++_shared.so'
+ pickFirst 'lib/armeabi-v7a/libc++_shared.so'
+ }
+
kotlinOptions {
jvmTarget = '1.8'
}
diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml
index 56ae07a..5fee667 100644
--- a/android/app/src/main/AndroidManifest.xml
+++ b/android/app/src/main/AndroidManifest.xml
@@ -51,7 +51,8 @@
-
+
diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties
index cfe88f6..89e56bd 100644
--- a/android/gradle/wrapper/gradle-wrapper.properties
+++ b/android/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.1-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-all.zip
diff --git a/android/settings.gradle b/android/settings.gradle
index 5ea421c..02c755b 100644
--- a/android/settings.gradle
+++ b/android/settings.gradle
@@ -31,7 +31,7 @@ pluginManagement {
plugins {
id "dev.flutter.flutter-plugin-loader" version "1.0.0"
- id "com.android.application" version "7.2.0" apply false
+ id "com.android.application" version "8.1.0" apply false
id "org.jetbrains.kotlin.android" version "1.9.0" apply false
}
diff --git a/assets/icons/marker.png b/assets/icons/marker.png
new file mode 100644
index 0000000..0ef8e10
Binary files /dev/null and b/assets/icons/marker.png differ
diff --git a/lib/Components/ScannerDialog.dart b/lib/Components/ScannerDialog.dart
index 42845a5..02c4593 100644
--- a/lib/Components/ScannerDialog.dart
+++ b/lib/Components/ScannerDialog.dart
@@ -2,14 +2,14 @@ import 'package:flutter/material.dart';
import 'dart:io';
import 'package:flutter/foundation.dart';
import 'package:manager_api_new/api.dart';
+import 'package:mymuseum_visitapp/Components/SlideFromRouteRight.dart';
import 'package:mymuseum_visitapp/Helpers/translationHelper.dart';
import 'package:mymuseum_visitapp/Models/visitContext.dart';
import 'package:mymuseum_visitapp/Screens/section_page.dart';
import 'package:mymuseum_visitapp/app_context.dart';
import 'package:mymuseum_visitapp/constants.dart';
import 'package:permission_handler/permission_handler.dart';
-import 'package:qr_code_scanner/qr_code_scanner.dart';
-
+import 'package:mobile_scanner/mobile_scanner.dart';
class ScannerDialog extends StatefulWidget {
const ScannerDialog({Key? key, required this.appContext}) : super(key: key);
@@ -21,19 +21,16 @@ class ScannerDialog extends StatefulWidget {
}
class _ScannerDialogState extends State {
- Barcode? result;
- QRViewController? controller;
- final GlobalKey qrKey = GlobalKey(debugLabel: 'QR');
+ final MobileScannerController controller = MobileScannerController();
+ bool isProcessing = false;
- // In order to get hot reload to work we need to pause the camera if the platform
- // is android, or resume the camera if the platform is iOS.
@override
void reassemble() {
super.reassemble();
if (Platform.isAndroid) {
- controller!.pauseCamera();
+ controller.stop();
}
- controller!.resumeCamera();
+ controller.start();
}
@override
@@ -41,194 +38,121 @@ class _ScannerDialogState extends State {
Size size = MediaQuery.of(context).size;
return Container(
- height: size.height *0.5,
- width: size.width *0.9,
+ height: size.height * 0.5,
+ width: size.width * 0.9,
child: Stack(
children: [
Center(
child: ClipRRect(
borderRadius: BorderRadius.circular(10.0),
- child: _buildQrView(context),
- )
- ),
- Positioned(
- top: 0,
- right: 0,
- child: Container(
- width: 45,
- height: 45,
- decoration: BoxDecoration(
- shape: BoxShape.rectangle,
- color: kMainColor1,
- borderRadius: BorderRadius.circular(20.0),
+ child: MobileScanner(
+ controller: controller,
+ //allowDuplicates: false,
+ onDetect: (barcodes) => _onDetect(barcodes),
),
- margin: const EdgeInsets.all(8),
- child: InkWell(
- onTap: () async {
- await controller?.toggleFlash();
- setState(() {});
- },
- child: FutureBuilder(
- future: controller?.getFlashStatus(),
- builder: (context, snapshot) {
- return const Icon(Icons.flash_on, color: Colors.white);
- },
- )),
),
),
- Positioned(
- bottom: 0,
- right: 0,
- child: Container(
- width: 45,
- height: 45,
- decoration: BoxDecoration(
- shape: BoxShape.rectangle,
- color: kMainColor1,
- borderRadius: BorderRadius.circular(20.0),
- ),
- margin: const EdgeInsets.all(8),
- child: InkWell(
- onTap: () async {
- await controller?.flipCamera();
- setState(() {});
- },
- child: FutureBuilder(
- future: controller?.getCameraInfo(),
- builder: (context, snapshot) {
- return const Icon(Icons.flip_camera_android, color: Colors.white);
- },
- )),
- ),
+ _buildControlButton(
+ icon: Icons.flash_on,
+ onTap: () => controller.toggleTorch(),
+ alignment: Alignment.topRight,
+ ),
+ _buildControlButton(
+ icon: Icons.flip_camera_android,
+ onTap: () => controller.switchCamera(),
+ alignment: Alignment.bottomRight,
),
],
),
);
}
- Widget _buildQrView(BuildContext context) {
- // For this example we check how width or tall the device is and change the scanArea and overlay accordingly.
- var scanArea = (MediaQuery.of(context).size.width < 400 ||
- MediaQuery.of(context).size.height < 400)
- ? 225.0
- : 300.0;
-
- // To ensure the Scanner view is properly sizes after rotation
- // we need to listen for Flutter SizeChanged notification and update controller
- return QRView(
- key: qrKey,
- onQRViewCreated: _onQRViewCreated,
- overlay: QrScannerOverlayShape(
- borderColor: kMainColor1,
- borderRadius: 10,
- borderLength: 25,
- borderWidth: 5,
- overlayColor: Colors.black.withValues(alpha: 0.55),
- cutOutSize: 225.0),
- onPermissionSet: (ctrl, p) => _onPermissionSet(context, ctrl, p),
+ Widget _buildControlButton({
+ required IconData icon,
+ required VoidCallback onTap,
+ required Alignment alignment,
+ }) {
+ return Align(
+ alignment: alignment,
+ child: Container(
+ width: 45,
+ height: 45,
+ margin: const EdgeInsets.all(8),
+ decoration: BoxDecoration(
+ shape: BoxShape.rectangle,
+ color: kMainColor1,
+ borderRadius: BorderRadius.circular(20.0),
+ ),
+ child: InkWell(
+ onTap: onTap,
+ child: Icon(icon, color: Colors.white),
+ ),
+ ),
);
}
- _onQRViewCreated(QRViewController controller) {
- setState(() {
- this.controller = controller;
- });
- if (Platform.isAndroid) {
- controller.pauseCamera();
- }
- controller.resumeCamera();
- controller.scannedDataStream.listen((scanData) {
- setState(() {
- result = scanData;
+ void _onDetect(BarcodeCapture capture) {
+ if (isProcessing) return;
- var code = result == null ? "" : result!.code.toString();
- if(result!.format == BarcodeFormat.qrcode) {
- controller.pauseCamera();
+ final barcode = capture.barcodes.first;
+ final code = barcode.rawValue ?? "";
- RegExp regExp = RegExp(r'^(?:https:\/\/web\.myinfomate\.be\/([^\/]+)\/([^\/]+)\/([^\/]+)|([^\/]+))$');
- var match = regExp.firstMatch(code);
- String? instanceId;
- String? configurationId;
- String? sectionId;
+ if (barcode.format == BarcodeFormat.qrCode && code.isNotEmpty) {
+ isProcessing = true;
- if (match != null) {
- instanceId = match.group(1);
- configurationId = match.group(2);
- sectionId = match.group(3) ?? match.group(4);
+ RegExp regExp = RegExp(r'^(?:https:\/\/web\.mymuseum\.be\/([^\/]+)\/([^\/]+)\/([^\/]+)|([^\/]+))$'); // myinfomate
+ var match = regExp.firstMatch(code);
+ String? instanceId = match?.group(1);
+ String? configurationId = match?.group(2);
+ String? sectionId = match?.group(3) ?? match?.group(4);
- print('InstanceId: $instanceId');
- print('ConfigurationId: $configurationId');
- print('SectionId: $sectionId');
- } else {
- print('L\'URL ne correspond pas au format attendu.');
- }
-
-
- //print("QR CODE FOUND");
- /*ScaffoldMessenger.of(context).showSnackBar(
- SnackBar(content: Text('QR CODE FOUND - ${code.toString()}')),
- );*/
-
- VisitAppContext visitAppContext = widget.appContext!.getContext();
-
- if(!visitAppContext.sectionIds!.contains(sectionId) || sectionId == null) {
- ScaffoldMessenger.of(context).showSnackBar(
- SnackBar(content: Text(TranslationHelper.getFromLocale('invalidQRCode', widget.appContext!.getContext())), backgroundColor: kMainColor2),
- );
- Navigator.of(context).pop();
-
- } else {
- SectionDTO section = visitAppContext.currentSections!.firstWhere((cs) => cs!.id == sectionId)!;
- Navigator.pushReplacement(
- context,
- MaterialPageRoute(
- builder: (context) {
- return SectionPage(configuration: visitAppContext.configuration!, rawSection: null, visitAppContextIn: visitAppContext, sectionId: section.id!);
- },
- ),
- );
- }
- }
- });
- });
- }
-
- Future _onPermissionSet(BuildContext context, QRViewController ctrl, bool p) async {
- //log('${DateTime.now().toIso8601String()}_onPermissionSet $p');
- if (!p) {
- var status = await Permission.camera.status;
- if(!status.isGranted) {
+ if (match == null || sectionId == null) {
ScaffoldMessenger.of(context).showSnackBar(
- const SnackBar(content: Text('no Permission')),
+ SnackBar(content: Text("L'URL ne correspond pas au format attendu."), backgroundColor: kMainColor2),
);
+ Navigator.of(context).pop();
+ return;
+ }
- // You can request multiple permissions at once.
- Map statuses = await [
- Permission.camera,
- ].request();
- print(statuses[Permission.camera]);
- print(status);
+ VisitAppContext visitAppContext = widget.appContext!.getContext();
+
+ if (visitAppContext.sectionIds == null || !visitAppContext.sectionIds!.contains(sectionId)) {
+ ScaffoldMessenger.of(context).showSnackBar(
+ SnackBar(content: Text(TranslationHelper.getFromLocale('invalidQRCode', visitAppContext)), backgroundColor: kMainColor2),
+ );
+ Navigator.of(context).pop();
+ } else {
+ dynamic rawSection = visitAppContext.currentSections!.firstWhere((cs) => cs!['id'] == sectionId)!;
+ Navigator.of(context).pop();
+ Navigator.push(
+ context,
+ SlideFromRightRoute(page: SectionPage(
+ configuration: visitAppContext.configuration!,
+ rawSection: rawSection,
+ visitAppContextIn: visitAppContext,
+ sectionId: rawSection['id'],
+ )),
+ );
}
}
}
@override
void dispose() {
- controller?.dispose();
+ controller.dispose();
super.dispose();
}
}
-showScannerDialog (BuildContext context, AppContext appContext) {
+showScannerDialog(BuildContext context, AppContext appContext) {
showDialog(
- builder: (BuildContext context) => AlertDialog(
- shape: const RoundedRectangleBorder(
- borderRadius: BorderRadius.all(Radius.circular(10.0))
- ),
- content: ScannerDialog(appContext: appContext),
- contentPadding: EdgeInsets.zero,
- ), context: context
+ context: context,
+ builder: (BuildContext context) => AlertDialog(
+ shape: const RoundedRectangleBorder(
+ borderRadius: BorderRadius.all(Radius.circular(10.0)),
+ ),
+ content: ScannerDialog(appContext: appContext),
+ contentPadding: EdgeInsets.zero,
+ ),
);
}
-
-
diff --git a/lib/Components/audio_player.dart b/lib/Components/audio_player.dart
index baa3cfc..bbb78ff 100644
--- a/lib/Components/audio_player.dart
+++ b/lib/Components/audio_player.dart
@@ -30,6 +30,7 @@ class _AudioPlayerFloatingContainerState extends State(context);
VisitAppContext visitAppContext = appContext.getContext();
+ Size size = MediaQuery.of(context).size;
- return FloatingActionButton(
- backgroundColor: Color(int.parse(visitAppContext.configuration!.primaryColor!.split('(0x')[1].split(')')[0], radix: 16)).withValues(alpha: 0.7),
- onPressed: () async {
+ return InkWell(
+ onTap: () async {
if(!isplaying && !audioplayed){
//player.play(BytesSource(audiobytes));
//await player.setUrl(widget.resourceURl);
@@ -170,77 +197,84 @@ class _AudioPlayerFloatingContainerState extends State? sectionIds; // Use to valid QR code found
List? beaconSections;
- List? currentSections;
+ List? currentSections;
List readSections = [];
bool isContentCurrentlyShown = false;
bool isScanningBeacons = false;
diff --git a/lib/Screens/Home/home.dart b/lib/Screens/Home/home.dart
index 0abb15b..6dcf7aa 100644
--- a/lib/Screens/Home/home.dart
+++ b/lib/Screens/Home/home.dart
@@ -21,8 +21,6 @@ import 'package:mymuseum_visitapp/app_context.dart';
import 'package:mymuseum_visitapp/client.dart';
import 'package:mymuseum_visitapp/constants.dart';
import 'package:provider/provider.dart';
-
-import '../Tests/TestAR.dart';
import 'configurations_list.dart';
class HomePage extends StatefulWidget {
diff --git a/lib/Screens/Home/home_3.0.dart b/lib/Screens/Home/home_3.0.dart
index 3a273c7..b24452b 100644
--- a/lib/Screens/Home/home_3.0.dart
+++ b/lib/Screens/Home/home_3.0.dart
@@ -25,8 +25,6 @@ import 'package:mymuseum_visitapp/app_context.dart';
import 'package:mymuseum_visitapp/client.dart';
import 'package:mymuseum_visitapp/constants.dart';
import 'package:provider/provider.dart';
-
-import '../Tests/TestAR.dart';
import 'configurations_list.dart';
class HomePage3 extends StatefulWidget {
diff --git a/lib/Screens/Sections/Map/filter_tree.dart b/lib/Screens/Sections/Map/filter_tree.dart
new file mode 100644
index 0000000..eda4ff7
--- /dev/null
+++ b/lib/Screens/Sections/Map/filter_tree.dart
@@ -0,0 +1,173 @@
+import 'dart:io';
+
+import 'package:flutter/material.dart';
+
+import 'package:collection/collection.dart';
+import 'package:mymuseum_visitapp/Screens/Sections/Map/tree_node.dart';
+
+class FilterTree extends StatefulWidget {
+ final List data;
+ final bool selectOneToAll;
+ final Function(TreeNode node, bool checked, int commonId) onChecked;
+ final Function(TreeNode node, int id) onClicked;
+ final Color? textColor;
+ final Color? checkBoxColor;
+ final EdgeInsets? childrenPadding;
+
+ FilterTree(
+ {this.checkBoxColor,
+ this.textColor,
+ this.childrenPadding,
+ required this.onChecked,
+ required this.onClicked,
+ required this.data,
+ required this.selectOneToAll});
+
+ @override
+ _FilterTree createState() => _FilterTree();
+}
+
+class _FilterTree extends State {
+ @override
+ void initState() {
+ super.initState();
+ }
+
+ Map map = {};
+ @override
+ Widget build(BuildContext context) {
+ return ListView.builder(
+ itemBuilder: (BuildContext context, int index) {
+ return _buildNode(widget.data[index], EdgeInsets.all(0));
+ },
+ itemCount: widget.data.length,
+ );
+ }
+
+ Widget _buildNode(TreeNode node, EdgeInsets childrenPadding) {
+ var nonCheckedIcon = Icon(
+ Icons.check_box_outline_blank,
+ color: widget.checkBoxColor ?? Colors.green,
+ );
+ var checkedIcon = Icon(
+ Icons.check_box,
+ color: widget.checkBoxColor ?? Colors.green,
+ );
+
+ // Si le nœud a des enfants, retourne l'ExpansionTile avec les enfants
+ if (node.children.isNotEmpty) {
+ return Padding(
+ padding: childrenPadding,
+ child: InkWell(
+ onTap: () {
+ widget.onClicked(node, node.id);
+ },
+ child: ExpansionTile(
+ iconColor: widget.checkBoxColor,
+ collapsedIconColor: widget.checkBoxColor,
+ tilePadding: EdgeInsets.fromLTRB(0, 0, 0, 0),
+ initiallyExpanded: node.show,
+ title: Container(
+ margin: EdgeInsets.only(left: 0),
+ padding: EdgeInsets.only(left: 0),
+ child: Text(
+ node.title,
+ style: TextStyle(color: widget.textColor ?? Colors.black),
+ ),
+ ),
+ leading: IconButton(
+ icon: node.checked ? checkedIcon : nonCheckedIcon,
+ onPressed: () {
+ setState(() {
+ _toggleNodeSelection(node, !node.checked);
+ widget.onChecked(node, node.checked, node.id);
+ });
+ },
+ ),
+ children: node.children
+ .map((child) => _buildNode(
+ child, widget.childrenPadding ?? EdgeInsets.all(0)))
+ .toList(),
+ ),
+ ),
+ );
+ } else {
+ // Si le nœud n'a pas d'enfants, retourne simplement le titre sans ExpansionTile
+ // avec le même padding que les éléments avec des enfants
+ return Padding(
+ padding: childrenPadding,
+ child: InkWell(
+ onTap: () {
+ widget.onClicked(node, node.id);
+ },
+ child: ListTile(
+ contentPadding: childrenPadding, // Utilisez le padding des enfants
+ title: Text(
+ node.title,
+ style: TextStyle(color: widget.textColor ?? Colors.black),
+ ),
+ leading: IconButton(
+ icon: node.checked ? checkedIcon : nonCheckedIcon,
+ onPressed: () {
+ setState(() {
+ _toggleNodeSelection(node, !node.checked);
+ widget.onChecked(node, node.checked, node.id);
+ });
+ },
+ ),
+ ),
+ ),
+ );
+ }
+ }
+
+
+ void _toggleNodeSelection(TreeNode node, bool isChecked) {
+ node.checked = isChecked;
+ _updateParentNodes(node, isChecked);
+ for (var child in node.children) {
+ _toggleNodeSelection(child, isChecked);
+ }
+ }
+
+ void _updateParentNodes(TreeNode node, bool checked) {
+ //First Check it has parent node
+ bool canContinue = false;
+ if (node.pid != 0) {
+ canContinue = true;
+ }
+
+ //if it have parent node then check all childrens are checked or non checked
+ bool canCheck = true;
+ if (!checked) {
+ for (int i = 0; i < node.children.length; i++) {
+ if (node.children[i].checked != checked) {
+ canCheck = false;
+ }
+ }
+ }
+
+ if (canCheck) {
+ node.checked = checked;
+ }
+
+ if (canContinue) {
+ checkEachNode(widget.data, node, checked);
+ }
+ // if all childrens are non checked the check parent node in widget.node if it matches node id then check above parent node
+ }
+
+ checkEachNode(List checkNode, TreeNode node, bool checked) {
+ bool canStop = false;
+ for (int i = 0; i < checkNode.length; i++) {
+ if (checkNode[i].children.isNotEmpty) {
+ checkEachNode(checkNode[i].children, node, checked);
+ }
+ if (checkNode[i].id == node.pid && !canStop) {
+ canStop = true;
+ _updateParentNodes(checkNode[i], checked);
+ break;
+ }
+ }
+ }
+}
diff --git a/lib/Screens/Sections/Map/flutter_map_view.dart b/lib/Screens/Sections/Map/flutter_map_view.dart
new file mode 100644
index 0000000..7ce7408
--- /dev/null
+++ b/lib/Screens/Sections/Map/flutter_map_view.dart
@@ -0,0 +1,136 @@
+import 'package:flutter/material.dart';
+import 'package:flutter_map/flutter_map.dart';
+import 'package:latlong2/latlong.dart';
+import 'package:manager_api_new/api.dart';
+import 'package:mymuseum_visitapp/Models/visitContext.dart';
+import 'package:mymuseum_visitapp/Screens/Sections/Map/map_context.dart';
+import 'package:mymuseum_visitapp/app_context.dart';
+import 'package:provider/provider.dart';
+import 'package:html/parser.dart' show parse;
+import 'package:latlong2/latlong.dart' as ll;
+
+class FlutterMapView extends StatefulWidget {
+ final MapDTO? mapDTO;
+ final List geoPoints;
+ final List