Slider ok, map wip + update gradle etc + qr scanner to mobile scanner
This commit is contained in:
parent
7aca0638ce
commit
4e9dc59df9
@ -39,13 +39,21 @@ apply plugin: 'kotlin-android'
|
|||||||
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"*/
|
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"*/
|
||||||
|
|
||||||
android {
|
android {
|
||||||
compileSdkVersion 34
|
namespace = "be.unov.mymuseum.fortsaintheribert"
|
||||||
|
compileSdkVersion 35
|
||||||
|
|
||||||
compileOptions {
|
compileOptions {
|
||||||
sourceCompatibility JavaVersion.VERSION_1_8
|
sourceCompatibility JavaVersion.VERSION_1_8
|
||||||
targetCompatibility 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 {
|
kotlinOptions {
|
||||||
jvmTarget = '1.8'
|
jvmTarget = '1.8'
|
||||||
}
|
}
|
||||||
|
|||||||
@ -51,7 +51,8 @@
|
|||||||
<meta-data
|
<meta-data
|
||||||
android:name="flutterEmbedding"
|
android:name="flutterEmbedding"
|
||||||
android:value="2" />
|
android:value="2" />
|
||||||
|
<meta-data android:name="com.google.android.geo.API_KEY"
|
||||||
|
android:value="AIzaSyDg6ApuZb6TRsauIyHJ9-XVwGYeh7MsWXE"/>
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="com.google.firebase.messaging.default_notification_icon"
|
android:name="com.google.firebase.messaging.default_notification_icon"
|
||||||
android:resource="@drawable/logo" />
|
android:resource="@drawable/logo" />
|
||||||
|
|||||||
@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
|
|||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
zipStorePath=wrapper/dists
|
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
|
||||||
|
|||||||
@ -31,7 +31,7 @@ pluginManagement {
|
|||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
id "dev.flutter.flutter-plugin-loader" version "1.0.0"
|
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
|
id "org.jetbrains.kotlin.android" version "1.9.0" apply false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
BIN
assets/icons/marker.png
Normal file
BIN
assets/icons/marker.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.7 KiB |
@ -2,14 +2,14 @@ import 'package:flutter/material.dart';
|
|||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:manager_api_new/api.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/Helpers/translationHelper.dart';
|
||||||
import 'package:mymuseum_visitapp/Models/visitContext.dart';
|
import 'package:mymuseum_visitapp/Models/visitContext.dart';
|
||||||
import 'package:mymuseum_visitapp/Screens/section_page.dart';
|
import 'package:mymuseum_visitapp/Screens/section_page.dart';
|
||||||
import 'package:mymuseum_visitapp/app_context.dart';
|
import 'package:mymuseum_visitapp/app_context.dart';
|
||||||
import 'package:mymuseum_visitapp/constants.dart';
|
import 'package:mymuseum_visitapp/constants.dart';
|
||||||
import 'package:permission_handler/permission_handler.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 {
|
class ScannerDialog extends StatefulWidget {
|
||||||
const ScannerDialog({Key? key, required this.appContext}) : super(key: key);
|
const ScannerDialog({Key? key, required this.appContext}) : super(key: key);
|
||||||
@ -21,19 +21,16 @@ class ScannerDialog extends StatefulWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class _ScannerDialogState extends State<ScannerDialog> {
|
class _ScannerDialogState extends State<ScannerDialog> {
|
||||||
Barcode? result;
|
final MobileScannerController controller = MobileScannerController();
|
||||||
QRViewController? controller;
|
bool isProcessing = false;
|
||||||
final GlobalKey qrKey = GlobalKey(debugLabel: 'QR');
|
|
||||||
|
|
||||||
// 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
|
@override
|
||||||
void reassemble() {
|
void reassemble() {
|
||||||
super.reassemble();
|
super.reassemble();
|
||||||
if (Platform.isAndroid) {
|
if (Platform.isAndroid) {
|
||||||
controller!.pauseCamera();
|
controller.stop();
|
||||||
}
|
}
|
||||||
controller!.resumeCamera();
|
controller.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -41,194 +38,121 @@ class _ScannerDialogState extends State<ScannerDialog> {
|
|||||||
Size size = MediaQuery.of(context).size;
|
Size size = MediaQuery.of(context).size;
|
||||||
|
|
||||||
return Container(
|
return Container(
|
||||||
height: size.height *0.5,
|
height: size.height * 0.5,
|
||||||
width: size.width *0.9,
|
width: size.width * 0.9,
|
||||||
child: Stack(
|
child: Stack(
|
||||||
children: [
|
children: [
|
||||||
Center(
|
Center(
|
||||||
child: ClipRRect(
|
child: ClipRRect(
|
||||||
borderRadius: BorderRadius.circular(10.0),
|
borderRadius: BorderRadius.circular(10.0),
|
||||||
child: _buildQrView(context),
|
child: MobileScanner(
|
||||||
)
|
controller: controller,
|
||||||
),
|
//allowDuplicates: false,
|
||||||
Positioned(
|
onDetect: (barcodes) => _onDetect(barcodes),
|
||||||
top: 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?.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),
|
_buildControlButton(
|
||||||
child: InkWell(
|
icon: Icons.flash_on,
|
||||||
onTap: () async {
|
onTap: () => controller.toggleTorch(),
|
||||||
await controller?.flipCamera();
|
alignment: Alignment.topRight,
|
||||||
setState(() {});
|
|
||||||
},
|
|
||||||
child: FutureBuilder(
|
|
||||||
future: controller?.getCameraInfo(),
|
|
||||||
builder: (context, snapshot) {
|
|
||||||
return const Icon(Icons.flip_camera_android, color: Colors.white);
|
|
||||||
},
|
|
||||||
)),
|
|
||||||
),
|
),
|
||||||
|
_buildControlButton(
|
||||||
|
icon: Icons.flip_camera_android,
|
||||||
|
onTap: () => controller.switchCamera(),
|
||||||
|
alignment: Alignment.bottomRight,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildQrView(BuildContext context) {
|
Widget _buildControlButton({
|
||||||
// For this example we check how width or tall the device is and change the scanArea and overlay accordingly.
|
required IconData icon,
|
||||||
var scanArea = (MediaQuery.of(context).size.width < 400 ||
|
required VoidCallback onTap,
|
||||||
MediaQuery.of(context).size.height < 400)
|
required Alignment alignment,
|
||||||
? 225.0
|
}) {
|
||||||
: 300.0;
|
return Align(
|
||||||
|
alignment: alignment,
|
||||||
// To ensure the Scanner view is properly sizes after rotation
|
child: Container(
|
||||||
// we need to listen for Flutter SizeChanged notification and update controller
|
width: 45,
|
||||||
return QRView(
|
height: 45,
|
||||||
key: qrKey,
|
margin: const EdgeInsets.all(8),
|
||||||
onQRViewCreated: _onQRViewCreated,
|
decoration: BoxDecoration(
|
||||||
overlay: QrScannerOverlayShape(
|
shape: BoxShape.rectangle,
|
||||||
borderColor: kMainColor1,
|
color: kMainColor1,
|
||||||
borderRadius: 10,
|
borderRadius: BorderRadius.circular(20.0),
|
||||||
borderLength: 25,
|
),
|
||||||
borderWidth: 5,
|
child: InkWell(
|
||||||
overlayColor: Colors.black.withValues(alpha: 0.55),
|
onTap: onTap,
|
||||||
cutOutSize: 225.0),
|
child: Icon(icon, color: Colors.white),
|
||||||
onPermissionSet: (ctrl, p) => _onPermissionSet(context, ctrl, p),
|
),
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
_onQRViewCreated(QRViewController controller) {
|
|
||||||
setState(() {
|
|
||||||
this.controller = controller;
|
|
||||||
});
|
|
||||||
if (Platform.isAndroid) {
|
|
||||||
controller.pauseCamera();
|
|
||||||
}
|
|
||||||
controller.resumeCamera();
|
|
||||||
controller.scannedDataStream.listen((scanData) {
|
|
||||||
setState(() {
|
|
||||||
result = scanData;
|
|
||||||
|
|
||||||
var code = result == null ? "" : result!.code.toString();
|
|
||||||
if(result!.format == BarcodeFormat.qrcode) {
|
|
||||||
controller.pauseCamera();
|
|
||||||
|
|
||||||
RegExp regExp = RegExp(r'^(?:https:\/\/web\.myinfomate\.be\/([^\/]+)\/([^\/]+)\/([^\/]+)|([^\/]+))$');
|
|
||||||
var match = regExp.firstMatch(code);
|
|
||||||
String? instanceId;
|
|
||||||
String? configurationId;
|
|
||||||
String? sectionId;
|
|
||||||
|
|
||||||
if (match != null) {
|
|
||||||
instanceId = match.group(1);
|
|
||||||
configurationId = match.group(2);
|
|
||||||
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<void> _onPermissionSet(BuildContext context, QRViewController ctrl, bool p) async {
|
void _onDetect(BarcodeCapture capture) {
|
||||||
//log('${DateTime.now().toIso8601String()}_onPermissionSet $p');
|
if (isProcessing) return;
|
||||||
if (!p) {
|
|
||||||
var status = await Permission.camera.status;
|
final barcode = capture.barcodes.first;
|
||||||
if(!status.isGranted) {
|
final code = barcode.rawValue ?? "";
|
||||||
|
|
||||||
|
if (barcode.format == BarcodeFormat.qrCode && code.isNotEmpty) {
|
||||||
|
isProcessing = true;
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
if (match == null || sectionId == null) {
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
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.
|
VisitAppContext visitAppContext = widget.appContext!.getContext();
|
||||||
Map<Permission, PermissionStatus> statuses = await [
|
|
||||||
Permission.camera,
|
if (visitAppContext.sectionIds == null || !visitAppContext.sectionIds!.contains(sectionId)) {
|
||||||
].request();
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
print(statuses[Permission.camera]);
|
SnackBar(content: Text(TranslationHelper.getFromLocale('invalidQRCode', visitAppContext)), backgroundColor: kMainColor2),
|
||||||
print(status);
|
);
|
||||||
|
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
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
controller?.dispose();
|
controller.dispose();
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
showScannerDialog (BuildContext context, AppContext appContext) {
|
showScannerDialog(BuildContext context, AppContext appContext) {
|
||||||
showDialog(
|
showDialog(
|
||||||
|
context: context,
|
||||||
builder: (BuildContext context) => AlertDialog(
|
builder: (BuildContext context) => AlertDialog(
|
||||||
shape: const RoundedRectangleBorder(
|
shape: const RoundedRectangleBorder(
|
||||||
borderRadius: BorderRadius.all(Radius.circular(10.0))
|
borderRadius: BorderRadius.all(Radius.circular(10.0)),
|
||||||
),
|
),
|
||||||
content: ScannerDialog(appContext: appContext),
|
content: ScannerDialog(appContext: appContext),
|
||||||
contentPadding: EdgeInsets.zero,
|
contentPadding: EdgeInsets.zero,
|
||||||
), context: context
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -30,6 +30,7 @@ class _AudioPlayerFloatingContainerState extends State<AudioPlayerFloatingContai
|
|||||||
int maxduration = 100;
|
int maxduration = 100;
|
||||||
Duration? durationAudio;
|
Duration? durationAudio;
|
||||||
String currentpostlabel = "00:00";
|
String currentpostlabel = "00:00";
|
||||||
|
bool _isDisposed = false;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
@ -107,13 +108,13 @@ class _AudioPlayerFloatingContainerState extends State<AudioPlayerFloatingContai
|
|||||||
});
|
});
|
||||||
});*/
|
});*/
|
||||||
|
|
||||||
if(audiobytes != null) {
|
/*if(audiobytes != null) {
|
||||||
print("GOT AUDIOBYYYTES - LOCALLY SOSO");
|
print("GOT AUDIOBYYYTES - LOCALLY SOSO");
|
||||||
await player.setAudioSource(LoadedSource(audiobytes!));
|
await player.setAudioSource(LoadedSource(audiobytes!));
|
||||||
} else {
|
} else {
|
||||||
print("GET SOUND BY URL");
|
print("GET SOUND BY URL");
|
||||||
await player.dynamicSet(url: widget.resourceURl);
|
await player.dynamicSet(url: widget.resourceURl);
|
||||||
}
|
}*/
|
||||||
|
|
||||||
if(widget.isAuto) {
|
if(widget.isAuto) {
|
||||||
//player.play(BytesSource(audiobytes));
|
//player.play(BytesSource(audiobytes));
|
||||||
@ -126,10 +127,36 @@ class _AudioPlayerFloatingContainerState extends State<AudioPlayerFloatingContai
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
super.initState();
|
super.initState();
|
||||||
|
|
||||||
|
Future.microtask(() async {
|
||||||
|
try {
|
||||||
|
if (_isDisposed || !mounted) return;
|
||||||
|
|
||||||
|
if (widget.audioBytes != null) {
|
||||||
|
await player.setAudioSource(LoadedSource(widget.audioBytes!));
|
||||||
|
} else {
|
||||||
|
await player.dynamicSet(url: widget.resourceURl);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_isDisposed || !mounted) return;
|
||||||
|
|
||||||
|
if (widget.isAuto) {
|
||||||
|
await player.play();
|
||||||
|
setState(() {
|
||||||
|
isplaying = true;
|
||||||
|
audioplayed = true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (e, stack) {
|
||||||
|
debugPrint('Audio error: $e');
|
||||||
|
debugPrintStack(stackTrace: stack);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
|
_isDisposed = true;
|
||||||
player.stop();
|
player.stop();
|
||||||
player.dispose();
|
player.dispose();
|
||||||
super.dispose();
|
super.dispose();
|
||||||
@ -144,10 +171,10 @@ class _AudioPlayerFloatingContainerState extends State<AudioPlayerFloatingContai
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final appContext = Provider.of<AppContext>(context);
|
final appContext = Provider.of<AppContext>(context);
|
||||||
VisitAppContext visitAppContext = appContext.getContext();
|
VisitAppContext visitAppContext = appContext.getContext();
|
||||||
|
Size size = MediaQuery.of(context).size;
|
||||||
|
|
||||||
return FloatingActionButton(
|
return InkWell(
|
||||||
backgroundColor: Color(int.parse(visitAppContext.configuration!.primaryColor!.split('(0x')[1].split(')')[0], radix: 16)).withValues(alpha: 0.7),
|
onTap: () async {
|
||||||
onPressed: () async {
|
|
||||||
if(!isplaying && !audioplayed){
|
if(!isplaying && !audioplayed){
|
||||||
//player.play(BytesSource(audiobytes));
|
//player.play(BytesSource(audiobytes));
|
||||||
//await player.setUrl(widget.resourceURl);
|
//await player.setUrl(widget.resourceURl);
|
||||||
@ -170,6 +197,12 @@ class _AudioPlayerFloatingContainerState extends State<AudioPlayerFloatingContai
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
child: Container(
|
||||||
|
width: size.width,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Color(int.parse(visitAppContext.configuration!.primaryColor!.split('(0x')[1].split(')')[0], radix: 16)).withValues(alpha: 0.7),
|
||||||
|
borderRadius: BorderRadius.circular(visitAppContext.configuration!.roundedValue?.toDouble() ?? 15.0),
|
||||||
|
),
|
||||||
child: isplaying ? Column(
|
child: isplaying ? Column(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
@ -241,6 +274,7 @@ class _AudioPlayerFloatingContainerState extends State<AudioPlayerFloatingContai
|
|||||||
)
|
)
|
||||||
],
|
],
|
||||||
),*/
|
),*/
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -16,7 +16,7 @@ class VisitAppContext with ChangeNotifier {
|
|||||||
ConfigurationDTO? configuration;
|
ConfigurationDTO? configuration;
|
||||||
List<String?>? sectionIds; // Use to valid QR code found
|
List<String?>? sectionIds; // Use to valid QR code found
|
||||||
List<BeaconSection?>? beaconSections;
|
List<BeaconSection?>? beaconSections;
|
||||||
List<SectionDTO?>? currentSections;
|
List<dynamic>? currentSections;
|
||||||
List<SectionRead> readSections = [];
|
List<SectionRead> readSections = [];
|
||||||
bool isContentCurrentlyShown = false;
|
bool isContentCurrentlyShown = false;
|
||||||
bool isScanningBeacons = false;
|
bool isScanningBeacons = false;
|
||||||
|
|||||||
@ -21,8 +21,6 @@ import 'package:mymuseum_visitapp/app_context.dart';
|
|||||||
import 'package:mymuseum_visitapp/client.dart';
|
import 'package:mymuseum_visitapp/client.dart';
|
||||||
import 'package:mymuseum_visitapp/constants.dart';
|
import 'package:mymuseum_visitapp/constants.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
import '../Tests/TestAR.dart';
|
|
||||||
import 'configurations_list.dart';
|
import 'configurations_list.dart';
|
||||||
|
|
||||||
class HomePage extends StatefulWidget {
|
class HomePage extends StatefulWidget {
|
||||||
|
|||||||
@ -25,8 +25,6 @@ import 'package:mymuseum_visitapp/app_context.dart';
|
|||||||
import 'package:mymuseum_visitapp/client.dart';
|
import 'package:mymuseum_visitapp/client.dart';
|
||||||
import 'package:mymuseum_visitapp/constants.dart';
|
import 'package:mymuseum_visitapp/constants.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
import '../Tests/TestAR.dart';
|
|
||||||
import 'configurations_list.dart';
|
import 'configurations_list.dart';
|
||||||
|
|
||||||
class HomePage3 extends StatefulWidget {
|
class HomePage3 extends StatefulWidget {
|
||||||
|
|||||||
173
lib/Screens/Sections/Map/filter_tree.dart
Normal file
173
lib/Screens/Sections/Map/filter_tree.dart
Normal file
@ -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<TreeNode> 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<FilterTree> {
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, int> 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<TreeNode> 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
136
lib/Screens/Sections/Map/flutter_map_view.dart
Normal file
136
lib/Screens/Sections/Map/flutter_map_view.dart
Normal file
@ -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<GeoPointDTO> geoPoints;
|
||||||
|
final List<Map<String, dynamic>> icons;
|
||||||
|
final String? language;
|
||||||
|
const FlutterMapView({
|
||||||
|
Key? key,
|
||||||
|
this.mapDTO,
|
||||||
|
required this.geoPoints,
|
||||||
|
required this.icons,
|
||||||
|
this.language,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
_FlutterMapViewState createState() => _FlutterMapViewState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _FlutterMapViewState extends State<FlutterMapView> {
|
||||||
|
late List<GeoPointDTO> markersList;
|
||||||
|
late List<Marker> markers;
|
||||||
|
bool filterZoneSelected = false;
|
||||||
|
MapController? mapController;
|
||||||
|
|
||||||
|
List<Marker> createPoints(mapContext) {
|
||||||
|
markersList = [];
|
||||||
|
markers = [];
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
widget.geoPoints.forEach((point) {
|
||||||
|
if (point.title!.where((translation) => translation.language == widget.language).isNotEmpty) {
|
||||||
|
var textSansHTML = parse(point.title!.firstWhere((translation) => translation.language == widget.language).value);
|
||||||
|
point.id = i;
|
||||||
|
point.title = point.title!.where((t) => t.language == widget.language).toList();
|
||||||
|
markersList.add(point);
|
||||||
|
|
||||||
|
//var icon = point.categorie == null ? BitmapDescriptor.fromBytes(widget.icons.where((i) => i['id'] == null).first['icon']) : widget.icons.any((i) => i['id'] == point.categorieId) ? BitmapDescriptor.fromBytes(widget.icons.where((i) => i['id'] == point.categorieId).first['icon']) : BitmapDescriptor.fromBytes(widget.icons.where((i) => i['id'] == null).first['icon']); //widget.selectedMarkerIcon,;
|
||||||
|
|
||||||
|
markers.add(
|
||||||
|
Marker(
|
||||||
|
width: 80.0,
|
||||||
|
height: 80.0,
|
||||||
|
point: LatLng(double.tryParse(point.latitude!)!, double.tryParse(point.longitude!)!),
|
||||||
|
child: GestureDetector(
|
||||||
|
onTap: () {
|
||||||
|
/*final mapContext = Provider.of<MapContext>(context, listen: false);
|
||||||
|
mapContext.setSelectedPoint(point);
|
||||||
|
mapContext.setSelectedPointForNavigate(point);*/
|
||||||
|
mapContext.setSelectedPoint(point);
|
||||||
|
//mapContext.setSelectedPointForNavigate(point);
|
||||||
|
},
|
||||||
|
child: widget.icons.firstWhere((i) => i['id'] == point.categorieId, orElse: () => widget.icons.first)['icon'] != null ? Image.memory(widget.icons.firstWhere((i) => i['id'] == point.categorieId, orElse: () => widget.icons.first)['icon']) : Icon(Icons.pin_drop, color: Colors.red),//widget.icons.firstWhere((i) => i['id'] == point.categorieId, orElse: () => widget.icons.first)['icon'],
|
||||||
|
)
|
||||||
|
),
|
||||||
|
);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return markers;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final mapContext = Provider.of<MapContext>(context);
|
||||||
|
final appContext = Provider.of<AppContext>(context);
|
||||||
|
VisitAppContext visitAppContext = appContext.getContext() as VisitAppContext;
|
||||||
|
|
||||||
|
markers = createPoints(mapContext);
|
||||||
|
|
||||||
|
if (mapController == null) { // mapContext.getSelectedPointForNavigate() != null
|
||||||
|
/*var geoPoint = mapContext.getSelectedPointForNavigate();
|
||||||
|
var center = LatLng(double.tryParse(geoPoint.latitude!)!, double.tryParse(geoPoint.longitude!)!);*/
|
||||||
|
mapController = MapController();
|
||||||
|
|
||||||
|
//mapController!.move(center, widget.mapDTO!.zoom != null ? widget.mapDTO!.zoom!.toDouble() : 12);
|
||||||
|
mapContext.setSelectedPointForNavigate(null); // Reset after navigation
|
||||||
|
}
|
||||||
|
|
||||||
|
return Stack(
|
||||||
|
children: [
|
||||||
|
FlutterMap(
|
||||||
|
mapController: mapController,
|
||||||
|
options: MapOptions(
|
||||||
|
initialCenter: widget.mapDTO!.longitude != null && widget.mapDTO!.latitude != null ? ll.LatLng(double.tryParse(widget.mapDTO!.latitude!)!, double.tryParse(widget.mapDTO!.longitude!)!) : ll.LatLng(4.865105, 50.465503), //.toJson()
|
||||||
|
initialZoom: widget.mapDTO!.zoom != null ? widget.mapDTO!.zoom!.toDouble() : 12,
|
||||||
|
onTap: (Tap, lnt) => {
|
||||||
|
mapContext.setSelectedPointForNavigate(null),
|
||||||
|
mapContext.setSelectedPoint(null),
|
||||||
|
}
|
||||||
|
),
|
||||||
|
children: [
|
||||||
|
TileLayer(
|
||||||
|
urlTemplate: "https://mt1.google.com/vt/lyrs=m&x={x}&y={y}&z={z}",
|
||||||
|
userAgentPackageName: 'be.unov.myinfomate.tablet',
|
||||||
|
),
|
||||||
|
MarkerLayer(
|
||||||
|
markers: markers
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
child: Builder(
|
||||||
|
builder: (context) {
|
||||||
|
return Consumer<MapContext>(
|
||||||
|
builder: (context, mapContext, _) {
|
||||||
|
var geoPoint = mapContext.getSelectedPointForNavigate() as GeoPointDTO?;
|
||||||
|
if (geoPoint != null && mapController != null) {
|
||||||
|
print("COUCOU IL FAUT NAVIGATE FLUTTER MAP");
|
||||||
|
mapController!.move(LatLng(double.tryParse(geoPoint.latitude!)!, double.tryParse(geoPoint.longitude!)!), mapController!.camera.zoom/*, widget.mapDTO!.zoom != null ? widget.mapDTO!.zoom!.toDouble() : 16*/); // keep actual zoom
|
||||||
|
}
|
||||||
|
return SizedBox();
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
390
lib/Screens/Sections/Map/geo_point_filter.dart
Normal file
390
lib/Screens/Sections/Map/geo_point_filter.dart
Normal file
@ -0,0 +1,390 @@
|
|||||||
|
import 'dart:ui';
|
||||||
|
import 'dart:math';
|
||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:manager_api_new/api.dart';
|
||||||
|
import 'package:mymuseum_visitapp/Helpers/translationHelper.dart';
|
||||||
|
import 'package:mymuseum_visitapp/Models/visitContext.dart';
|
||||||
|
import 'package:mymuseum_visitapp/Screens/Sections/Map/filter_tree.dart';
|
||||||
|
import 'package:mymuseum_visitapp/Screens/Sections/Map/tree_node.dart';
|
||||||
|
import 'package:mymuseum_visitapp/app_context.dart';
|
||||||
|
import 'package:mymuseum_visitapp/constants.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
import 'package:html/parser.dart' show parse;
|
||||||
|
import 'package:diacritic/diacritic.dart';
|
||||||
|
|
||||||
|
import 'map_context.dart';
|
||||||
|
|
||||||
|
class GeoPointFilter extends StatefulWidget {
|
||||||
|
final String language;
|
||||||
|
final List<GeoPointDTO> geoPoints;
|
||||||
|
final List<CategorieDTO> categories;
|
||||||
|
final Function(List<GeoPointDTO>?) filteredPoints;
|
||||||
|
final MapProvider provider;
|
||||||
|
|
||||||
|
GeoPointFilter({required this.language, required this.geoPoints, required this.categories, required this.filteredPoints, required this.provider});
|
||||||
|
|
||||||
|
@override
|
||||||
|
_GeoPointFilterState createState() => _GeoPointFilterState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _GeoPointFilterState extends State<GeoPointFilter> with SingleTickerProviderStateMixin {
|
||||||
|
List<GeoPointDTO> selectedGeoPoints = [];
|
||||||
|
late List<TreeNode> _filteredNodes;
|
||||||
|
late ValueNotifier<String> _searchTextNotifier;
|
||||||
|
final TextEditingController _searchController = TextEditingController();
|
||||||
|
FocusNode focusNode = FocusNode();
|
||||||
|
bool _isExpanded = false;
|
||||||
|
bool _showContent = false;
|
||||||
|
|
||||||
|
late AnimationController _controller;
|
||||||
|
late Animation<double> _widthAnimation;
|
||||||
|
late Size screenSize;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void didChangeDependencies() {
|
||||||
|
super.didChangeDependencies();
|
||||||
|
screenSize = MediaQuery.of(context).size;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
_searchTextNotifier = ValueNotifier<String>('');
|
||||||
|
|
||||||
|
_controller = AnimationController(vsync: this, duration: const Duration(milliseconds: 300));
|
||||||
|
_widthAnimation = Tween<double>(begin: 40, end: 350).animate(
|
||||||
|
CurvedAnimation(parent: _controller, curve: Curves.easeInOut),
|
||||||
|
);
|
||||||
|
|
||||||
|
_filteredNodes = buildTreeNodes(widget.categories, widget.geoPoints);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_searchController.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
void _toggleExpansion() {
|
||||||
|
setState(() {
|
||||||
|
if (_isExpanded) {
|
||||||
|
_showContent = false;
|
||||||
|
_isExpanded = false;
|
||||||
|
} else {
|
||||||
|
_isExpanded = true;
|
||||||
|
Future.delayed(const Duration(milliseconds: 300), () {
|
||||||
|
if (_isExpanded) {
|
||||||
|
setState(() => _showContent = true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
_isExpanded ? _controller.forward() : _controller.reverse();
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
List<TreeNode> buildTreeNodes(List<CategorieDTO> categories, List<GeoPointDTO> geoPoints) {
|
||||||
|
List<TreeNode> nodes = [];
|
||||||
|
|
||||||
|
// Pour chaque point sans categorie, créer un noeud
|
||||||
|
for(var pointWithoutCat in geoPoints.where((gp) => gp.categorieId == null))
|
||||||
|
{
|
||||||
|
if(pointWithoutCat.title!.where((l) => l.language == widget.language).firstOrNull != null) {
|
||||||
|
TreeNode nodeWithoutCat = TreeNode(
|
||||||
|
id: 000 + int.parse(
|
||||||
|
(pointWithoutCat.latitude ?? '').substring(0, min(pointWithoutCat.latitude!.length, 10)).replaceAll(".", "").replaceAll("-","") + (pointWithoutCat.longitude ?? '').substring(0, min(pointWithoutCat.longitude!.length, 10)).replaceAll(".", "").replaceAll("-","")
|
||||||
|
),
|
||||||
|
title: parse(pointWithoutCat.title!.firstWhere((l) => l.language == widget.language).value!).documentElement!.text,
|
||||||
|
children: [],
|
||||||
|
checked: true, // default true
|
||||||
|
show: false,
|
||||||
|
pid: 0,
|
||||||
|
commonID: 0,
|
||||||
|
);
|
||||||
|
nodes.add(nodeWithoutCat);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pour chaque catégorie, créez un nœud parent
|
||||||
|
for (var category in categories) {
|
||||||
|
if(category.label!.where((l) => l.language == widget.language).firstOrNull != null)
|
||||||
|
{
|
||||||
|
TreeNode categoryNode = TreeNode(
|
||||||
|
id: 100 + (category.id ?? 0),
|
||||||
|
title: parse(category.label!.firstWhere((l) => l.language == widget.language).value!).documentElement!.text,
|
||||||
|
children: [],
|
||||||
|
checked: true, // default true
|
||||||
|
show: false,
|
||||||
|
pid: 0,
|
||||||
|
commonID: 0,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Ajoutez les géopoints correspondant à cette catégorie en tant qu'enfants du nœud parent
|
||||||
|
for (var geoPoint in geoPoints.where((gp) => gp.categorieId != null)) {
|
||||||
|
if (geoPoint.categorieId == category.id && geoPoint.title!.where((l) => l.language == widget.language).firstOrNull != null) {
|
||||||
|
TreeNode geoPointNode = TreeNode(
|
||||||
|
id: 000 + int.parse(
|
||||||
|
(geoPoint.latitude ?? '').substring(0, min(geoPoint.latitude!.length, 10)).replaceAll(".", "").replaceAll("-", "") + (geoPoint.longitude ?? '').substring(0, min(geoPoint.longitude!.length, 10)).replaceAll(".", "").replaceAll("-", "")
|
||||||
|
),
|
||||||
|
title: parse(geoPoint.title!.firstWhere((l) => l.language == widget.language).value!).documentElement!.text,
|
||||||
|
checked: true, // default true
|
||||||
|
show: false,
|
||||||
|
children: [],
|
||||||
|
pid: 0,
|
||||||
|
commonID: 0,
|
||||||
|
);
|
||||||
|
categoryNode.children.add(geoPointNode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
nodes.add(categoryNode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
nodes.sort((a, b) => a.title.compareTo(b.title));
|
||||||
|
|
||||||
|
return nodes;
|
||||||
|
}
|
||||||
|
|
||||||
|
void filterNodes() {
|
||||||
|
String searchText = _searchController.text;
|
||||||
|
setState(() {
|
||||||
|
_filteredNodes = searchText.isEmpty
|
||||||
|
? buildTreeNodes(widget.categories, widget.geoPoints)
|
||||||
|
: _filterNodesBySearchText(searchText);
|
||||||
|
|
||||||
|
// if unfocus, then
|
||||||
|
//if(searchText.isEmpty) {
|
||||||
|
// widget.filteredPoints = //todo
|
||||||
|
sendFilteredGeoPoint();
|
||||||
|
//}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
sendFilteredGeoPoint() {
|
||||||
|
List<GeoPointDTO> checkedGeoPoints = [];
|
||||||
|
// Parcourez les nœuds filtrés pour récupérer les GeoPointDTO correspondants qui sont cochés
|
||||||
|
for (var node in _filteredNodes) {
|
||||||
|
if (node.children.isNotEmpty) {
|
||||||
|
for (var childNode in node.children) {
|
||||||
|
if (childNode.checked) {
|
||||||
|
var point = widget.geoPoints.firstWhere(
|
||||||
|
(point) {
|
||||||
|
String latitudePart = (point.latitude ?? '')
|
||||||
|
.substring(0, min(point.latitude!.length, 10))
|
||||||
|
.replaceAll(".", "")
|
||||||
|
.replaceAll("-", "");
|
||||||
|
String longitudePart = (point.longitude ?? '')
|
||||||
|
.substring(0, min(point.longitude!.length, 10))
|
||||||
|
.replaceAll(".", "")
|
||||||
|
.replaceAll("-", "");
|
||||||
|
int combinedValue = int.parse(latitudePart + longitudePart);
|
||||||
|
|
||||||
|
return combinedValue == childNode.id;
|
||||||
|
},
|
||||||
|
orElse: () => GeoPointDTO(id: -1),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (point.id != -1) {
|
||||||
|
checkedGeoPoints.add(point);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if(node.checked) {
|
||||||
|
var point = widget.geoPoints.firstWhere(
|
||||||
|
(point) {
|
||||||
|
String latitudePart = (point.latitude ?? '')
|
||||||
|
.substring(0, min(point.latitude!.length, 10))
|
||||||
|
.replaceAll(".", "")
|
||||||
|
.replaceAll("-", "");
|
||||||
|
String longitudePart = (point.longitude ?? '')
|
||||||
|
.substring(0, min(point.longitude!.length, 10))
|
||||||
|
.replaceAll(".", "")
|
||||||
|
.replaceAll("-", "");
|
||||||
|
int combinedValue = int.parse(latitudePart + longitudePart);
|
||||||
|
return combinedValue == node.id;
|
||||||
|
},
|
||||||
|
orElse: () => GeoPointDTO(id: -1),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (point.id != -1) {
|
||||||
|
checkedGeoPoints.add(point);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Passez la liste des GeoPointDTO cochés à la fonction filteredPoints
|
||||||
|
widget.filteredPoints(checkedGeoPoints);
|
||||||
|
}
|
||||||
|
|
||||||
|
List<TreeNode> _filterNodesBySearchText(String searchText) {
|
||||||
|
List<TreeNode> filteredNodes = [];
|
||||||
|
for (var node in buildTreeNodes(widget.categories, widget.geoPoints)) {
|
||||||
|
if (_nodeOrChildrenContainsText(node, searchText)) {
|
||||||
|
if(node.children.isNotEmpty) {
|
||||||
|
for (var childNode in node.children) {
|
||||||
|
if (_nodeOrChildrenContainsText(childNode, searchText)) {
|
||||||
|
filteredNodes.add(childNode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
filteredNodes.add(node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return filteredNodes;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool _nodeOrChildrenContainsText(TreeNode node, String searchText) {
|
||||||
|
// Remove accent and other special characters
|
||||||
|
String normalizedSearchText = removeDiacritics(searchText.toLowerCase());
|
||||||
|
String normalizedTitle = removeDiacritics(node.title.toLowerCase());
|
||||||
|
|
||||||
|
if (normalizedTitle.contains(normalizedSearchText)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
for (var childNode in node.children) {
|
||||||
|
if (_nodeOrChildrenContainsText(childNode, searchText)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final appContext = Provider.of<AppContext>(context);
|
||||||
|
VisitAppContext visitAppContext = appContext.getContext();
|
||||||
|
var currentLanguage = visitAppContext.language;
|
||||||
|
final mapContext = Provider.of<MapContext>(context);
|
||||||
|
|
||||||
|
var primaryColor = visitAppContext.configuration != null ? visitAppContext.configuration!.primaryColor != null ? Color(int.parse(visitAppContext.configuration!.primaryColor!.split('(0x')[1].split(')')[0], radix: 16)) : kSecondColor : kSecondColor;
|
||||||
|
double rounded = visitAppContext.configuration?.roundedValue?.toDouble() ?? 20.0;
|
||||||
|
|
||||||
|
return Positioned(
|
||||||
|
left: 0,
|
||||||
|
top: _isExpanded ? screenSize.height * 0.11 : screenSize.height / 2 - (75 / 2),
|
||||||
|
child: AnimatedBuilder(
|
||||||
|
animation: _widthAnimation,
|
||||||
|
builder: (context, child) {
|
||||||
|
return Container(
|
||||||
|
width: _widthAnimation.value,
|
||||||
|
height: _isExpanded ? screenSize.height*0.78 : 75,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: _isExpanded ? kBackgroundColor.withValues(alpha: 0.9) : primaryColor.withValues(alpha: 0.8),
|
||||||
|
borderRadius: BorderRadius.only(topRight: Radius.circular(rounded), bottomRight: Radius.circular(rounded)),
|
||||||
|
),
|
||||||
|
child: _showContent ? Padding(
|
||||||
|
padding: const EdgeInsets.all(8.0),
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
IconButton(
|
||||||
|
icon: Icon(Icons.close, color: primaryColor),
|
||||||
|
onPressed: _toggleExpansion,
|
||||||
|
),
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
SizedBox(
|
||||||
|
height: 60,
|
||||||
|
width: (screenSize.width * 0.76),
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.only(left: 10.0, bottom: 8.0, top: 4.0),
|
||||||
|
child: TextField(
|
||||||
|
focusNode: focusNode,
|
||||||
|
controller: _searchController,
|
||||||
|
onChanged: (value) {
|
||||||
|
filterNodes();
|
||||||
|
},
|
||||||
|
cursorColor: Colors.black,
|
||||||
|
style: const TextStyle(color: Colors.black),
|
||||||
|
decoration: InputDecoration(
|
||||||
|
labelText: _searchController.text.isEmpty ? TranslationHelper.getFromLocale("map.search", appContext.getContext()) : "",
|
||||||
|
labelStyle: const TextStyle(
|
||||||
|
color: Colors.black
|
||||||
|
),
|
||||||
|
focusColor: primaryColor,
|
||||||
|
focusedBorder: OutlineInputBorder(
|
||||||
|
borderRadius: BorderRadius.all(Radius.circular(visitAppContext.configuration!.roundedValue?.toDouble() ?? 20.0)),
|
||||||
|
borderSide: BorderSide(color: primaryColor)),
|
||||||
|
//labelStyle: TextStyle(color: primaryColor),
|
||||||
|
suffixIcon: IconButton(
|
||||||
|
icon: _searchController.text.isNotEmpty ? Icon(Icons.close, color: primaryColor) : Icon(Icons.search, color: primaryColor),
|
||||||
|
onPressed: () {
|
||||||
|
if(_searchController.text.isNotEmpty) {
|
||||||
|
_searchController.text = "";
|
||||||
|
// TODO reset view ?
|
||||||
|
}
|
||||||
|
filterNodes();
|
||||||
|
if(_searchController.text.isNotEmpty) {
|
||||||
|
focusNode.unfocus();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
ValueListenableBuilder<String>(
|
||||||
|
valueListenable: _searchTextNotifier,
|
||||||
|
builder: (context, value, _) {
|
||||||
|
return SizedBox(
|
||||||
|
width: screenSize.width * 0.8,
|
||||||
|
height: screenSize.height * 0.63,
|
||||||
|
child: FilterTree(
|
||||||
|
data: _filteredNodes,
|
||||||
|
selectOneToAll: true,
|
||||||
|
textColor: Colors.black,
|
||||||
|
onChecked: (node, checked, commonID) {
|
||||||
|
sendFilteredGeoPoint();
|
||||||
|
},
|
||||||
|
onClicked: (node, commonID) {
|
||||||
|
var selectedNode = widget.geoPoints.firstWhere(
|
||||||
|
(point) {
|
||||||
|
String latitudePart = (point.latitude ?? '')
|
||||||
|
.substring(0, min(point.latitude!.length, 10))
|
||||||
|
.replaceAll(".", "")
|
||||||
|
.replaceAll("-", "");
|
||||||
|
String longitudePart = (point.longitude ?? '')
|
||||||
|
.substring(0, min(point.longitude!.length, 10))
|
||||||
|
.replaceAll(".", "")
|
||||||
|
.replaceAll("-", "");
|
||||||
|
int combinedValue =
|
||||||
|
int.parse(latitudePart + longitudePart);
|
||||||
|
return combinedValue == commonID;
|
||||||
|
},
|
||||||
|
orElse: () => GeoPointDTO(id: -1),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (selectedNode.id != -1) {
|
||||||
|
mapContext.setSelectedPointForNavigate(selectedNode);
|
||||||
|
_toggleExpansion();
|
||||||
|
} else {
|
||||||
|
print('Aucun point correspondant trouvé.');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
checkBoxColor: primaryColor,
|
||||||
|
childrenPadding: const EdgeInsets.only(
|
||||||
|
left: 20, top: 10, right: 0, bottom: 10),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
) : IconButton(
|
||||||
|
icon: const Icon(Icons.search, color: Colors.white),
|
||||||
|
onPressed: _toggleExpansion,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
239
lib/Screens/Sections/Map/google_map_view.dart
Normal file
239
lib/Screens/Sections/Map/google_map_view.dart
Normal file
@ -0,0 +1,239 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:google_maps_flutter/google_maps_flutter.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;
|
||||||
|
|
||||||
|
class GoogleMapView extends StatefulWidget {
|
||||||
|
final MapDTO mapDTO;
|
||||||
|
final List<GeoPointDTO> geoPoints;
|
||||||
|
final List<Map<String, dynamic>> icons;
|
||||||
|
final String? language;
|
||||||
|
const GoogleMapView({
|
||||||
|
Key? key,
|
||||||
|
required this.mapDTO,
|
||||||
|
required this.geoPoints,
|
||||||
|
required this.icons,
|
||||||
|
this.language,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
_GoogleMapViewState createState() => _GoogleMapViewState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _GoogleMapViewState extends State<GoogleMapView> {
|
||||||
|
ConfigurationDTO? configurationDTO;
|
||||||
|
Completer<GoogleMapController> _controller = Completer();
|
||||||
|
GoogleMapController? _GoogleMapcontroller;
|
||||||
|
Set<Marker> markers = {};
|
||||||
|
List<GeoPointDTO>? pointsToShow = [];
|
||||||
|
//List<String>? selectedCategories = [];
|
||||||
|
bool init = false;
|
||||||
|
|
||||||
|
Set<Marker> getMarkers(language, mapContext) {
|
||||||
|
markers = {};
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
pointsToShow!.forEach((point) {
|
||||||
|
var textSansHTML = parse(point.title!.firstWhere((translation) => translation.language == language).value);
|
||||||
|
point.id = i;
|
||||||
|
/*var mapMarker = new MapMarker(
|
||||||
|
id: point.id,
|
||||||
|
title: parse(textSansHTML.body!.text).documentElement!.text,
|
||||||
|
description: point.description!.firstWhere((translation) => translation.language == language).value,
|
||||||
|
longitude: point.longitude,
|
||||||
|
latitude: point.latitude,
|
||||||
|
contents: point.contents
|
||||||
|
);*/
|
||||||
|
if (point.latitude != null && point.longitude != null) {
|
||||||
|
var icon = point.categorieId == null ? BitmapDescriptor.bytes(widget.icons.where((i) => i['id'] == null).first['icon']) : widget.icons.any((i) => i['id'] == point.categorieId) ? BitmapDescriptor.bytes(widget.icons.where((i) => i['id'] == point.categorieId).first['icon']) : BitmapDescriptor.bytes(widget.icons.where((i) => i['id'] == null).first['icon']); //widget.selectedMarkerIcon,;
|
||||||
|
markers.add(Marker(
|
||||||
|
draggable: false,
|
||||||
|
markerId: MarkerId(parse(textSansHTML.body!.text).documentElement!.text + point.latitude! + point.longitude!),
|
||||||
|
position: LatLng(
|
||||||
|
double.tryParse(point.latitude!)!,
|
||||||
|
double.tryParse(point.longitude!)!,
|
||||||
|
),
|
||||||
|
icon: icon, //widget.selectedMarkerIcon,
|
||||||
|
//widget.selectedMarkerIcon != null ? BitmapDescriptor.fromBytes(widget.selectedMarkerIcon!) : BitmapDescriptor.defaultMarker,
|
||||||
|
/*icon: BitmapDescriptor.defaultMarkerWithHue(
|
||||||
|
BitmapDescriptor.hueYellow,
|
||||||
|
),*/
|
||||||
|
onTap: () {
|
||||||
|
//setState(() {
|
||||||
|
mapContext.setSelectedPoint(point);
|
||||||
|
//mapContext.setSelectedPointForNavigate(point);
|
||||||
|
//});
|
||||||
|
},
|
||||||
|
infoWindow: InfoWindow.noText));
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
});
|
||||||
|
return markers;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
//selectedCategories = widget.mapDTO.categories!.map((cat) => cat.label!.firstWhere((element) => element.language == widget.language).value!).toList();
|
||||||
|
super.initState();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
// TODO: implement dispose
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final mapContext = Provider.of<MapContext>(context);
|
||||||
|
final appContext = Provider.of<AppContext>(context);
|
||||||
|
VisitAppContext visitAppContext = appContext.getContext() as VisitAppContext;
|
||||||
|
Size size = MediaQuery.of(context).size;
|
||||||
|
|
||||||
|
pointsToShow = widget.geoPoints;
|
||||||
|
|
||||||
|
/*if(!init) {
|
||||||
|
print("getmarkers in build");*/
|
||||||
|
getMarkers(widget.language, mapContext);
|
||||||
|
/* init = true;
|
||||||
|
}*/
|
||||||
|
//MapTypeApp? mapTypeApp = MapTypeApp.fromJson(widget.mapDTO!.mapType!.value);
|
||||||
|
//print(mapTypeApp.toString());
|
||||||
|
|
||||||
|
MapType type = MapType.hybrid;
|
||||||
|
//if(kIsWeb) {
|
||||||
|
if(widget.mapDTO.mapType != null) {
|
||||||
|
switch(widget.mapDTO.mapType!.value) {
|
||||||
|
case 0:
|
||||||
|
type = MapType.none;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
type = MapType.normal;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
type = MapType.satellite;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
type = MapType.terrain;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
type = MapType.hybrid;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*} else {
|
||||||
|
print("is OTHEER");
|
||||||
|
type = EnumToString.fromString(MapType.values, widget.mapDTO!.mapType.toString()) != null ? EnumToString.fromString(MapType.values, widget.mapDTO!.mapType.toString())! : MapType.hybrid;
|
||||||
|
}*/
|
||||||
|
|
||||||
|
|
||||||
|
//MapType type = EnumToString.fromString(MapType.values, widget.mapDTO!.mapType.toString()) != null ? EnumToString.fromString(MapType.values, widget.mapDTO!.mapType.toString())! : MapType.hybrid;
|
||||||
|
return Stack(
|
||||||
|
children: [
|
||||||
|
Center(
|
||||||
|
child: GoogleMap(
|
||||||
|
mapType: type, // widget.mapDTO!.mapType != null ? EnumToString.fromString(MapType.values, widget.mapDTO!.mapType.toString())!: MapType.hybrid,
|
||||||
|
mapToolbarEnabled: false,
|
||||||
|
indoorViewEnabled: false,
|
||||||
|
initialCameraPosition: CameraPosition(
|
||||||
|
target: widget.mapDTO.longitude != null && widget.mapDTO.latitude != null ? LatLng(double.tryParse(widget.mapDTO.latitude!)!, double.tryParse(widget.mapDTO.longitude!)!) : LatLng(50.465503, 4.865105) , // MDLF 50.416639, 4.879169 / Namur 50.465503, 4.865105
|
||||||
|
zoom: widget.mapDTO.zoom != null ? widget.mapDTO.zoom!.toDouble() : 18,
|
||||||
|
),
|
||||||
|
onMapCreated: (GoogleMapController controller) {
|
||||||
|
if(kIsWeb) {
|
||||||
|
//_controllerWeb.complete(controller);
|
||||||
|
} else {
|
||||||
|
_controller.complete(controller);
|
||||||
|
_GoogleMapcontroller = controller;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
markers: markers,
|
||||||
|
onTap: (LatLng location) {
|
||||||
|
print(location);
|
||||||
|
mapContext.setSelectedPoint(null);
|
||||||
|
mapContext.setSelectedPointForNavigate(null);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
child: Builder(
|
||||||
|
builder: (context) {
|
||||||
|
return Consumer<MapContext>(
|
||||||
|
builder: (context, mapContext, _) {
|
||||||
|
var geopoint = mapContext.getSelectedPointForNavigate() as GeoPointDTO?;
|
||||||
|
if (geopoint != null && _GoogleMapcontroller != null) {
|
||||||
|
print("COUCOU IL FAUT NAVUGATE");
|
||||||
|
// TODO Handle zoomDetail
|
||||||
|
_GoogleMapcontroller!.getZoomLevel().then((actualZoom) {
|
||||||
|
var zoomToNavigate = actualZoom <= 12.0 ? 15.0 : actualZoom;
|
||||||
|
_GoogleMapcontroller!.animateCamera(CameraUpdate.newCameraPosition(
|
||||||
|
CameraPosition(
|
||||||
|
target: LatLng(double.tryParse(geopoint.latitude!)!, double.tryParse(geopoint.longitude!)!),
|
||||||
|
tilt: 0.0,
|
||||||
|
bearing: 0.0,
|
||||||
|
zoom: zoomToNavigate
|
||||||
|
//zoom: widget.mapDTO.zoom != null ? widget.mapDTO.zoom!.toDouble() : 16
|
||||||
|
)
|
||||||
|
));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return SizedBox();
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
),
|
||||||
|
)
|
||||||
|
/*Positioned(
|
||||||
|
left: 5,
|
||||||
|
top: 35,
|
||||||
|
child: SizedBox(
|
||||||
|
width: size.width * 0.3,
|
||||||
|
height: size.height * 0.76,
|
||||||
|
child: GeoPointFilter(
|
||||||
|
language: tabletAppContext.language!,
|
||||||
|
geoPoints: widget.mapDTO!.points!,
|
||||||
|
categories: widget.mapDTO!.categories!,
|
||||||
|
filteredPoints: (filteredPoints) {
|
||||||
|
print("COUCOU FILTERED POINTS");
|
||||||
|
print(filteredPoints);
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Positioned(
|
||||||
|
bottom: 35,
|
||||||
|
left: 10,
|
||||||
|
child: SizedBox(
|
||||||
|
width: size.width * 0.75,
|
||||||
|
child: MultiSelectContainer(
|
||||||
|
label: null,
|
||||||
|
color: kBackgroundGrey,
|
||||||
|
initialValue: selectedCategories!,
|
||||||
|
isMultiple: true,
|
||||||
|
values: widget.mapDTO!.categories!.map((categorie) => categorie.label!.firstWhere((element) => element.language == widget.language).value!).toList(),
|
||||||
|
onChanged: (value) {
|
||||||
|
var tempOutput = new List<String>.from(value);
|
||||||
|
print(tempOutput);
|
||||||
|
if(init) {
|
||||||
|
selectedCategories = tempOutput;
|
||||||
|
pointsToShow = widget.mapDTO!.points!.where((point) => tempOutput.any((tps) => point.categorie?.label?.firstWhere((lab) => lab.language == widget.language).value == tps) || point.categorie == null).toList();
|
||||||
|
setState(() {
|
||||||
|
markers = getMarkers(widget.language, mapContext);
|
||||||
|
mapContext.notifyListeners();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),*/
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
236
lib/Screens/Sections/Map/map_box_view.dart
Normal file
236
lib/Screens/Sections/Map/map_box_view.dart
Normal file
@ -0,0 +1,236 @@
|
|||||||
|
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:google_maps_flutter/google_maps_flutter.dart';
|
||||||
|
import 'package:manager_api_new/api.dart';
|
||||||
|
import 'package:mapbox_maps_flutter/mapbox_maps_flutter.dart' as mapBox;
|
||||||
|
import 'package:mymuseum_visitapp/Models/visitContext.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/app_context.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
import 'package:html/parser.dart' show parse;
|
||||||
|
|
||||||
|
class MapBoxView extends StatefulWidget {
|
||||||
|
final MapDTO? mapDTO;
|
||||||
|
final List<GeoPointDTO> geoPoints;
|
||||||
|
final List<Map<String, dynamic>> icons;
|
||||||
|
final String? language;
|
||||||
|
const MapBoxView({
|
||||||
|
Key? key,
|
||||||
|
this.mapDTO,
|
||||||
|
required this.geoPoints,
|
||||||
|
required this.icons,
|
||||||
|
this.language,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
_MapBoxViewState createState() => _MapBoxViewState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class AnnotationClickListener extends mapBox.OnPointAnnotationClickListener {
|
||||||
|
late List<GeoPointDTO> markersList;
|
||||||
|
late MapContext mapContext;
|
||||||
|
|
||||||
|
AnnotationClickListener({
|
||||||
|
required this.markersList,
|
||||||
|
required this.mapContext,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
void onPointAnnotationClick(mapBox.PointAnnotation annotation) {
|
||||||
|
try{
|
||||||
|
var markerToShow = markersList.firstWhere((ml) => "${parse(ml.title!.first.value).documentElement!.text}${ml.latitude}${ml.longitude}" == annotation.textField);
|
||||||
|
mapContext.setSelectedPoint(markerToShow);
|
||||||
|
//mapContext.setSelectedPointForNavigate(markerToShow);
|
||||||
|
} catch(e) {
|
||||||
|
print("ISSSUE setSelectedMarker");
|
||||||
|
print(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class _MapBoxViewState extends State<MapBoxView> {
|
||||||
|
late mapBox.MapboxMap? mapboxMap;
|
||||||
|
mapBox.PointAnnotationManager? pointAnnotationManager;
|
||||||
|
bool filterZoneSelected = false;
|
||||||
|
|
||||||
|
createPoints() {
|
||||||
|
var options = <mapBox.PointAnnotationOptions>[];
|
||||||
|
int i = 0;
|
||||||
|
markersList = [];
|
||||||
|
pointsToShow!.forEach((point) {
|
||||||
|
if(point.title!.where((translation) => translation.language == widget.language).firstOrNull != null) {
|
||||||
|
var textSansHTML = parse(point.title!.firstWhere((translation) => translation.language == widget.language).value);
|
||||||
|
point.id = i;
|
||||||
|
point.title = point.title!.where((t) => t.language == widget.language).toList();
|
||||||
|
/*var mapMarker = new MapMarker(
|
||||||
|
id: i,
|
||||||
|
title: parse(textSansHTML.body!.text).documentElement!.text,
|
||||||
|
description: point.description!.firstWhere((translation) => translation.language == widget.language).value,
|
||||||
|
longitude: point.longitude,
|
||||||
|
latitude: point.latitude,
|
||||||
|
contents: point.contents
|
||||||
|
);*/
|
||||||
|
markersList.add(point);
|
||||||
|
options.add(mapBox.PointAnnotationOptions(
|
||||||
|
geometry: mapBox.Point(
|
||||||
|
coordinates: mapBox.Position(
|
||||||
|
double.tryParse(point.longitude!)!,
|
||||||
|
double.tryParse(point.latitude!)!,
|
||||||
|
)), // .toJson()
|
||||||
|
iconSize: 1.3,
|
||||||
|
textField: "${parse(textSansHTML.body!.text).documentElement!.text}${point.latitude}${point.longitude}",
|
||||||
|
textOpacity: 0.0,
|
||||||
|
iconOffset: [0.0, 0.0],
|
||||||
|
symbolSortKey: 10,
|
||||||
|
iconColor: 0,
|
||||||
|
iconImage: null,
|
||||||
|
image: point.categorieId == null ? widget.icons.where((i) => i['id'] == null).first['icon'] : widget.icons.any((i) => i['id'] == point.categorieId) ? widget.icons.where((i) => i['id'] == point.categorieId).first['icon'] : widget.icons.where((i) => i['id'] == null).first['icon'], //widget.selectedMarkerIcon,
|
||||||
|
)); // ,
|
||||||
|
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
print(options.length);
|
||||||
|
|
||||||
|
return options;
|
||||||
|
}
|
||||||
|
|
||||||
|
_onMapCreated(mapBox.MapboxMap mapboxMap, MapContext mapContext) {
|
||||||
|
this.mapboxMap = mapboxMap;
|
||||||
|
|
||||||
|
mapboxMap.annotations.createPointAnnotationManager().then((pointAnnotationManager) async {
|
||||||
|
this.pointAnnotationManager = pointAnnotationManager;
|
||||||
|
pointAnnotationManager.createMulti(createPoints());
|
||||||
|
pointAnnotationManager.addOnPointAnnotationClickListener(AnnotationClickListener(mapContext: mapContext, markersList: markersList));
|
||||||
|
init = true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
ConfigurationDTO? configurationDTO;
|
||||||
|
//Completer<GoogleMapController> _controller = Completer();
|
||||||
|
//Set<Marker> markers = {};
|
||||||
|
List<GeoPointDTO>? pointsToShow = [];
|
||||||
|
List<String>? selectedCategories = [];
|
||||||
|
bool init = false;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
pointsToShow = widget.geoPoints;//widget.mapDTO!.points;
|
||||||
|
var nonNullCat = widget.mapDTO!.categories!.where((c) => c.label!.where((element) => element.language == widget.language).firstOrNull != null);
|
||||||
|
selectedCategories = nonNullCat.map((categorie) => categorie.label!.firstWhere((element) => element.language == widget.language).value!).toList();
|
||||||
|
super.initState();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final mapContext = Provider.of<MapContext>(context);
|
||||||
|
|
||||||
|
pointsToShow = widget.geoPoints;//widget.mapDTO!.points;
|
||||||
|
|
||||||
|
if(pointAnnotationManager != null) {
|
||||||
|
pointAnnotationManager!.deleteAll();
|
||||||
|
pointAnnotationManager!.createMulti(createPoints());
|
||||||
|
//mapContext.notifyListeners();
|
||||||
|
}
|
||||||
|
|
||||||
|
final appContext = Provider.of<AppContext>(context);
|
||||||
|
VisitAppContext visitAppContext = appContext.getContext() as VisitAppContext;
|
||||||
|
Size size = MediaQuery.of(context).size;
|
||||||
|
|
||||||
|
var type = mapBox.MapboxStyles.STANDARD;
|
||||||
|
if(widget.mapDTO!.mapTypeMapbox != null) {
|
||||||
|
switch(widget.mapDTO!.mapTypeMapbox!) {
|
||||||
|
case MapTypeMapBox.standard:
|
||||||
|
type = mapBox.MapboxStyles.STANDARD;
|
||||||
|
break;
|
||||||
|
case MapTypeMapBox.streets:
|
||||||
|
type = mapBox.MapboxStyles.MAPBOX_STREETS;
|
||||||
|
break;
|
||||||
|
case MapTypeMapBox.outdoors:
|
||||||
|
type = mapBox.MapboxStyles.OUTDOORS;
|
||||||
|
break;
|
||||||
|
case MapTypeMapBox.light:
|
||||||
|
type = mapBox.MapboxStyles.LIGHT;
|
||||||
|
break;
|
||||||
|
case MapTypeMapBox.dark:
|
||||||
|
type = mapBox.MapboxStyles.DARK;
|
||||||
|
break;
|
||||||
|
case MapTypeMapBox.satellite:
|
||||||
|
type = mapBox.MapboxStyles.SATELLITE;
|
||||||
|
break;
|
||||||
|
case MapTypeMapBox.satellite_streets:
|
||||||
|
type = mapBox.MapboxStyles.SATELLITE_STREETS;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Stack(
|
||||||
|
children: [
|
||||||
|
Center(
|
||||||
|
child: mapBox.MapWidget(
|
||||||
|
key: ValueKey("mapBoxWidget"),
|
||||||
|
styleUri: type,
|
||||||
|
onMapCreated: (maBoxMap) {
|
||||||
|
_onMapCreated(maBoxMap, mapContext);
|
||||||
|
},
|
||||||
|
onTapListener: (listener) {
|
||||||
|
// close on tap
|
||||||
|
mapContext.setSelectedPoint(null);
|
||||||
|
mapContext.setSelectedPointForNavigate(null);
|
||||||
|
},
|
||||||
|
cameraOptions: mapBox.CameraOptions(
|
||||||
|
center: mapBox.Point(coordinates: widget.mapDTO!.longitude != null && widget.mapDTO!.latitude != null ? mapBox.Position(double.tryParse(widget.mapDTO!.longitude!)!, double.tryParse(widget.mapDTO!.latitude!)!) : mapBox.Position(4.865105, 50.465503)), //.toJson()
|
||||||
|
zoom: widget.mapDTO!.zoom != null ? widget.mapDTO!.zoom!.toDouble() : 12),
|
||||||
|
)
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
child: Builder(
|
||||||
|
builder: (context) {
|
||||||
|
return Consumer<MapContext>(
|
||||||
|
builder: (context, mapContext, _) {
|
||||||
|
var geoPoint = mapContext.getSelectedPointForNavigate() as GeoPointDTO?;
|
||||||
|
if (geoPoint != null && mapboxMap != null) {
|
||||||
|
print("COUCOU IL FAUT NAVUGATE MAPBOX");
|
||||||
|
// TODO Handle zoomDetail
|
||||||
|
mapboxMap?.easeTo(
|
||||||
|
mapBox.CameraOptions(
|
||||||
|
center: mapBox.Point(coordinates: mapBox.Position(double.tryParse(geoPoint.longitude!)!, double.tryParse(geoPoint.latitude!)!)), //.toJson()
|
||||||
|
zoom: 16,
|
||||||
|
bearing: 0,
|
||||||
|
pitch: 3),
|
||||||
|
mapBox.MapAnimationOptions(duration: 2000, startDelay: 0));
|
||||||
|
}
|
||||||
|
return SizedBox();
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
),
|
||||||
|
)
|
||||||
|
/*Positioned(
|
||||||
|
left: 5,
|
||||||
|
top: 35,
|
||||||
|
child: SizedBox(
|
||||||
|
width: size.width * 0.3,
|
||||||
|
height: size.height * 0.76,
|
||||||
|
child: GeoPointFilter(
|
||||||
|
language: tabletAppContext.language!,
|
||||||
|
geoPoints: widget.mapDTO!.points!,
|
||||||
|
categories: widget.mapDTO!.categories!,
|
||||||
|
filteredPoints: (filteredPoints) {
|
||||||
|
print("COUCOU FILTERED POINTS");
|
||||||
|
print(filteredPoints);
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
),*/
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
22
lib/Screens/Sections/Map/map_context.dart
Normal file
22
lib/Screens/Sections/Map/map_context.dart
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:manager_api_new/api.dart';
|
||||||
|
|
||||||
|
class MapContext with ChangeNotifier {
|
||||||
|
GeoPointDTO? _selectedPoint;
|
||||||
|
GeoPointDTO? _selectedPointNavigate;
|
||||||
|
|
||||||
|
MapContext(this._selectedPoint);
|
||||||
|
|
||||||
|
getSelectedPoint() => _selectedPoint;
|
||||||
|
setSelectedPoint(GeoPointDTO? selectedPoint) {
|
||||||
|
_selectedPoint = selectedPoint;
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
|
||||||
|
getSelectedPointForNavigate() => _selectedPointNavigate;
|
||||||
|
setSelectedPointForNavigate(GeoPointDTO? selectedPointNavigate) {
|
||||||
|
_selectedPointNavigate = selectedPointNavigate;
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
188
lib/Screens/Sections/Map/map_page.dart
Normal file
188
lib/Screens/Sections/Map/map_page.dart
Normal file
@ -0,0 +1,188 @@
|
|||||||
|
//import 'dart:async';
|
||||||
|
import 'dart:convert';
|
||||||
|
// 'dart:typed_data';
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
// 'package:flutter/services.dart';
|
||||||
|
//import 'package:google_maps_flutter/google_maps_flutter.dart';
|
||||||
|
import 'package:manager_api_new/api.dart';
|
||||||
|
import 'package:mymuseum_visitapp/Models/visitContext.dart';
|
||||||
|
import 'package:mymuseum_visitapp/Screens/Sections/Map/flutter_map_view.dart';
|
||||||
|
import 'package:mymuseum_visitapp/Screens/Sections/Map/geo_point_filter.dart';
|
||||||
|
import 'package:mymuseum_visitapp/Screens/Sections/Map/map_box_view.dart';
|
||||||
|
import 'package:mymuseum_visitapp/Screens/Sections/Map/marker_view.dart';
|
||||||
|
import 'package:mymuseum_visitapp/app_context.dart';
|
||||||
|
import 'package:mymuseum_visitapp/constants.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
/*import 'package:tablet_app/Components/loading.dart';
|
||||||
|
import 'package:tablet_app/Components/loading_common.dart';*/
|
||||||
|
//import 'dart:ui' as ui;
|
||||||
|
import 'package:flutter/widgets.dart';
|
||||||
|
//import 'package:http/http.dart' as http;
|
||||||
|
|
||||||
|
import 'google_map_view.dart';
|
||||||
|
//import 'package:image/image.dart' as IMG;
|
||||||
|
|
||||||
|
//Set<Marker> markers = {};
|
||||||
|
List<GeoPointDTO> markersList = [];
|
||||||
|
|
||||||
|
class MapPage extends StatefulWidget {
|
||||||
|
final MapDTO section;
|
||||||
|
final List<Map<String, dynamic>> icons;
|
||||||
|
MapPage({Key? key, required this.section, required this.icons}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
_MapPage createState() => _MapPage();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _MapPage extends State<MapPage> {
|
||||||
|
MapDTO? mapDTO;
|
||||||
|
//Completer<GoogleMapController> _controller = Completer();
|
||||||
|
//Uint8List? selectedMarkerIcon;
|
||||||
|
late ValueNotifier<List<GeoPointDTO>> _geoPoints = ValueNotifier<List<GeoPointDTO>>([]);
|
||||||
|
|
||||||
|
/*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();
|
||||||
|
}*/
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
//mapDTO = MapDTO.fromJson(jsonDecode(widget.section.data!));
|
||||||
|
mapDTO = widget.section;
|
||||||
|
_geoPoints.value = mapDTO!.points!;
|
||||||
|
super.initState();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
// TODO: implement dispose
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*static final CameraPosition _kLake = CameraPosition(
|
||||||
|
bearing: 192.8334901395799,
|
||||||
|
target: LatLng(37.43296265331129, -122.08832357078792),
|
||||||
|
tilt: 59.440717697143555,
|
||||||
|
zoom: 59.151926040649414);*/
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
//final mapContext = Provider.of<MapContext>(context);
|
||||||
|
final appContext = Provider.of<AppContext>(context);
|
||||||
|
VisitAppContext visitAppContext = appContext.getContext() as VisitAppContext;
|
||||||
|
|
||||||
|
var primaryColor = visitAppContext.configuration != null ? visitAppContext.configuration!.primaryColor != null ? Color(int.parse(visitAppContext.configuration!.primaryColor!.split('(0x')[1].split(')')[0], radix: 16)) : kSecondColor : kSecondColor;
|
||||||
|
|
||||||
|
/*return FutureBuilder(
|
||||||
|
future: getByteIcon(mapDTO!.iconSource),
|
||||||
|
builder: (context, AsyncSnapshot<dynamic> snapshot) {
|
||||||
|
if (snapshot.connectionState == ConnectionState.done) {
|
||||||
|
} else if (snapshot.connectionState == ConnectionState.none) {
|
||||||
|
return Text("No data");
|
||||||
|
} else {
|
||||||
|
return Center(
|
||||||
|
child: Container(
|
||||||
|
child: LoadingCommon()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);*/
|
||||||
|
return MediaQuery.removeViewInsets(
|
||||||
|
context: context,
|
||||||
|
removeBottom: true,
|
||||||
|
child: Stack(
|
||||||
|
fit: StackFit.passthrough,
|
||||||
|
children: <Widget>[
|
||||||
|
ValueListenableBuilder<List<GeoPointDTO>>(
|
||||||
|
valueListenable: _geoPoints,
|
||||||
|
builder: (context, value, _) {
|
||||||
|
switch(mapDTO!.mapProvider) {
|
||||||
|
case MapProvider.Google:
|
||||||
|
return GoogleMapView(language: appContext.getContext().language, geoPoints: value, mapDTO: mapDTO!, icons: widget.icons);
|
||||||
|
case MapProvider.MapBox:
|
||||||
|
return MapBoxView(language: appContext.getContext().language, geoPoints: value, mapDTO: mapDTO, icons: widget.icons);
|
||||||
|
// If mapbox bug as 3.24 flutter, we can test via this new widget
|
||||||
|
return FlutterMapView(language: appContext.getContext().language, geoPoints: value, mapDTO: mapDTO, icons: widget.icons);
|
||||||
|
default:
|
||||||
|
// By default google
|
||||||
|
return GoogleMapView(language: appContext.getContext().language, geoPoints: value, mapDTO: mapDTO!, icons: widget.icons);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
),
|
||||||
|
GeoPointFilter(
|
||||||
|
language: visitAppContext.language!,
|
||||||
|
geoPoints: mapDTO!.points!,
|
||||||
|
categories: mapDTO!.categories!,
|
||||||
|
provider: mapDTO!.mapProvider == null ? MapProvider.Google : mapDTO!.mapProvider!,
|
||||||
|
filteredPoints: (value) {
|
||||||
|
_geoPoints.value = value!;
|
||||||
|
}),
|
||||||
|
MarkerViewWidget(),
|
||||||
|
Positioned(
|
||||||
|
top: 35,
|
||||||
|
left: 10,
|
||||||
|
child: SizedBox(
|
||||||
|
width: 50,
|
||||||
|
height: 50,
|
||||||
|
child: InkWell(
|
||||||
|
onTap: () {
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
},
|
||||||
|
child: Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: primaryColor,
|
||||||
|
shape: BoxShape.circle,
|
||||||
|
),
|
||||||
|
child: const Icon(Icons.arrow_back, size: 23, color: Colors.white)
|
||||||
|
),
|
||||||
|
)
|
||||||
|
),
|
||||||
|
),
|
||||||
|
]
|
||||||
|
/*floatingActionButton: FloatingActionButton.extended(
|
||||||
|
onPressed: _goToTheLake,
|
||||||
|
label: Text('To the lake!'),
|
||||||
|
icon: Icon(Icons.directions_boat),
|
||||||
|
),*/
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*getByteIcon(String? source) async {
|
||||||
|
if(source != null) {
|
||||||
|
if(kIsWeb) {
|
||||||
|
Uint8List fileData = await http.readBytes(Uri.parse(source));
|
||||||
|
selectedMarkerIcon = resizeImage(fileData, 40);
|
||||||
|
} else {
|
||||||
|
final ByteData imageData = await NetworkAssetBundle(Uri.parse(source)).load("");
|
||||||
|
selectedMarkerIcon = await getBytesFromAsset(imageData, 50);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// default icon
|
||||||
|
final ByteData bytes = await rootBundle.load('assets/icons/marker.png');
|
||||||
|
selectedMarkerIcon = await getBytesFromAsset(bytes, 25);
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
|
||||||
|
/*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<void> _goToTheLake() async {
|
||||||
|
final GoogleMapController controller = await _controller.future;
|
||||||
|
controller.animateCamera(CameraUpdate.newCameraPosition(_kLake));
|
||||||
|
}*/
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
692
lib/Screens/Sections/Map/marker_view.dart
Normal file
692
lib/Screens/Sections/Map/marker_view.dart
Normal file
@ -0,0 +1,692 @@
|
|||||||
|
import 'package:auto_size_text/auto_size_text.dart';
|
||||||
|
import 'package:cached_network_image/cached_network_image.dart';
|
||||||
|
import 'package:carousel_slider/carousel_slider.dart';
|
||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_widget_from_html/flutter_widget_from_html.dart';
|
||||||
|
import 'package:manager_api_new/api.dart';
|
||||||
|
import 'package:mymuseum_visitapp/Components/loading_common.dart';
|
||||||
|
import 'package:mymuseum_visitapp/Components/show_element_for_resource.dart';
|
||||||
|
import 'package:mymuseum_visitapp/Helpers/ImageCustomProvider.dart';
|
||||||
|
import 'package:mymuseum_visitapp/Models/visitContext.dart';
|
||||||
|
import 'package:mymuseum_visitapp/app_context.dart';
|
||||||
|
import 'package:photo_view/photo_view.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
import 'package:html/parser.dart' show parse;
|
||||||
|
import 'package:qr_flutter/qr_flutter.dart';
|
||||||
|
|
||||||
|
|
||||||
|
import '../../../constants.dart';
|
||||||
|
import 'map_context.dart';
|
||||||
|
|
||||||
|
class MarkerViewWidget extends StatefulWidget {
|
||||||
|
MarkerViewWidget();
|
||||||
|
|
||||||
|
@override
|
||||||
|
_MarkerInfoWidget createState() => _MarkerInfoWidget();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _MarkerInfoWidget extends State<MarkerViewWidget> {
|
||||||
|
CarouselSliderController? sliderController;
|
||||||
|
ValueNotifier<int> currentIndex = ValueNotifier<int>(1);
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
sliderController = CarouselSliderController();
|
||||||
|
super.initState();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
sliderController = null;
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
int breakPointPrice = 50;
|
||||||
|
|
||||||
|
Size size = MediaQuery.of(context).size;
|
||||||
|
final mapContext = Provider.of<MapContext>(context);
|
||||||
|
final appContext = Provider.of<AppContext>(context);
|
||||||
|
VisitAppContext visitAppContext = appContext.getContext() as VisitAppContext;
|
||||||
|
var language = visitAppContext.language;
|
||||||
|
GeoPointDTO? selectedPoint = mapContext.getSelectedPoint() as GeoPointDTO?;
|
||||||
|
|
||||||
|
ScrollController scrollDescription = new ScrollController();
|
||||||
|
ScrollController scrollPrice = new ScrollController();
|
||||||
|
|
||||||
|
var isPointPrice = selectedPoint != null && selectedPoint.prices != null && selectedPoint.prices!.isNotEmpty && selectedPoint.prices!.any((d) => d.language == language) && selectedPoint.prices!.firstWhere((d) => d.language == language).value != null && selectedPoint.prices!.firstWhere((d) => d.language == language).value!.trim().length > 0;
|
||||||
|
|
||||||
|
Color primaryColor = new Color(int.parse(visitAppContext.configuration!.primaryColor!.split('(0x')[1].split(')')[0], radix: 16));
|
||||||
|
|
||||||
|
Size sizeMarker = Size(size.width * 0.93, size.height * 0.83);
|
||||||
|
return Center(
|
||||||
|
child: Visibility(
|
||||||
|
visible: selectedPoint != null,
|
||||||
|
child: Container(
|
||||||
|
width: sizeMarker.width,
|
||||||
|
height: sizeMarker.height,
|
||||||
|
margin: EdgeInsets.symmetric(vertical: 3, horizontal: 4),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: kBackgroundColor, // Colors.amberAccent //kBackgroundLight,
|
||||||
|
//shape: BoxShape.rectangle,
|
||||||
|
borderRadius: BorderRadius.circular(visitAppContext.configuration!.roundedValue?.toDouble() ?? 10.0),
|
||||||
|
/*boxShadow: [
|
||||||
|
BoxShadow(
|
||||||
|
color: kBackgroundSecondGrey,
|
||||||
|
spreadRadius: 0.5,
|
||||||
|
blurRadius: 1.1,
|
||||||
|
offset: Offset(0, 1.1), // changes position of shadow
|
||||||
|
),
|
||||||
|
],*/
|
||||||
|
),
|
||||||
|
child: Stack(
|
||||||
|
children: <Widget> [
|
||||||
|
Positioned(
|
||||||
|
right: 5,
|
||||||
|
top: 5,
|
||||||
|
child: InkWell(
|
||||||
|
onTap: () {
|
||||||
|
setState(() {
|
||||||
|
mapContext.setSelectedPoint(null);
|
||||||
|
mapContext.setSelectedPointForNavigate(null);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
child: Container(
|
||||||
|
width: 50,
|
||||||
|
height: 50,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: kBackgroundGrey,
|
||||||
|
shape: BoxShape.circle,
|
||||||
|
boxShadow: [
|
||||||
|
BoxShadow(
|
||||||
|
color: kBackgroundGrey,
|
||||||
|
spreadRadius: 0.5,
|
||||||
|
blurRadius: 1.1,
|
||||||
|
offset: Offset(0, 1.1), // changes position of shadow
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
child: Icon(
|
||||||
|
Icons.close,
|
||||||
|
size: 25,
|
||||||
|
color: Colors.white,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if(selectedPoint != null)
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
selectedPoint.imageResourceId != null && selectedPoint.imageUrl != null ? ClipRRect(
|
||||||
|
borderRadius: BorderRadius.only(topLeft: Radius.circular(visitAppContext.configuration!.roundedValue?.toDouble() ?? 20.0), bottomLeft: Radius.circular(visitAppContext.configuration!.roundedValue?.toDouble() ?? 20.0)),
|
||||||
|
child: Container(
|
||||||
|
child: Center(
|
||||||
|
child: Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
border: Border(right: BorderSide(width: 0.05, color: kMainGrey)),
|
||||||
|
color: Colors.grey,
|
||||||
|
),
|
||||||
|
width: size.width * 0.17,
|
||||||
|
height: size.height,
|
||||||
|
child: CachedNetworkImage(
|
||||||
|
imageUrl: selectedPoint.imageUrl!,
|
||||||
|
width: size.width,
|
||||||
|
fit: BoxFit.cover,
|
||||||
|
progressIndicatorBuilder: (context, url, downloadProgress) {
|
||||||
|
return Center(
|
||||||
|
child: SizedBox(
|
||||||
|
width: 50,
|
||||||
|
height: 50,
|
||||||
|
child: LoadingCommon(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
errorWidget: (context, url, error) => Icon(Icons.error),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
),
|
||||||
|
): SizedBox(),
|
||||||
|
Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.only(top: 8.0, left: 15.0),
|
||||||
|
child: Container(
|
||||||
|
//color: Colors.green,
|
||||||
|
height: size.height * 0.06,
|
||||||
|
width: size.width * 0.65,
|
||||||
|
child: HtmlWidget(
|
||||||
|
selectedPoint.title!.firstWhere((t) => t.language == language).value!,
|
||||||
|
textStyle: TextStyle(fontSize: 20.0),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Row(
|
||||||
|
//mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.only(left: 15),
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
height: isPointPrice && selectedPoint.prices!.firstWhere((d) => d.language == language).value!.length > breakPointPrice ? size.height * 0.50 : size.height * 0.7,
|
||||||
|
width: size.width * 0.38,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: kBackgroundLight,
|
||||||
|
borderRadius: BorderRadius.all(Radius.circular(visitAppContext.configuration!.roundedValue?.toDouble() ?? 20.0))
|
||||||
|
),
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.only(left: 20, right: 10, bottom: 10, top: 15),
|
||||||
|
child: Scrollbar(
|
||||||
|
controller: scrollDescription,
|
||||||
|
thumbVisibility: true,
|
||||||
|
thickness: 2.0,
|
||||||
|
child: SingleChildScrollView(
|
||||||
|
controller: scrollDescription,
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(8.0),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
if(selectedPoint.description!.any((d) => d.language == language) && selectedPoint.description!.firstWhere((d) => d.language == language).value != null && selectedPoint.description!.firstWhere((d) => d.language == language).value!.trim().length > 0)
|
||||||
|
HtmlWidget(
|
||||||
|
selectedPoint.description!.firstWhere((d) => d.language == language).value!,
|
||||||
|
customStylesBuilder: (element) {
|
||||||
|
return {'text-align': 'left', 'font-family': "Roboto"};
|
||||||
|
},
|
||||||
|
textStyle: TextStyle(fontSize: kDescriptionSize),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if(isPointPrice && selectedPoint.prices!.firstWhere((d) => d.language == language).value!.length > breakPointPrice)
|
||||||
|
Container(
|
||||||
|
height: size.height * 0.20,
|
||||||
|
width: size.width * 0.38,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: kBackgroundLight,
|
||||||
|
borderRadius: BorderRadius.all(Radius.circular(visitAppContext.configuration!.roundedValue?.toDouble() ?? 20.0))
|
||||||
|
),
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.only(left: 20, right: 10, bottom: 10, top: 15),
|
||||||
|
child: Scrollbar(
|
||||||
|
controller: scrollPrice,
|
||||||
|
thumbVisibility: true,
|
||||||
|
thickness: 2.0,
|
||||||
|
child: SingleChildScrollView(
|
||||||
|
controller: scrollPrice,
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(8.0),
|
||||||
|
child: Column(
|
||||||
|
//crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
//mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
Center(child: Padding(
|
||||||
|
padding: const EdgeInsets.all(5.0),
|
||||||
|
child: Icon(Icons.price_change_outlined, color: primaryColor, size: 25),
|
||||||
|
)),
|
||||||
|
HtmlWidget(
|
||||||
|
selectedPoint.prices!.firstWhere((d) => d.language == language).value!,
|
||||||
|
customStylesBuilder: (element) {
|
||||||
|
return {'text-align': 'left', 'font-family': "Roboto"};
|
||||||
|
},
|
||||||
|
textStyle: TextStyle(fontSize: kDescriptionSize),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
width: size.width * 0.32,
|
||||||
|
height: size.height * 0.7,
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(8.0),
|
||||||
|
child: Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
//color: Colors.green,
|
||||||
|
height: size.height * 0.35,
|
||||||
|
child: CarouselSlider(
|
||||||
|
carouselController: sliderController,
|
||||||
|
options: CarouselOptions(
|
||||||
|
onPageChanged: (int index, CarouselPageChangedReason reason) {
|
||||||
|
currentIndex.value = index + 1;
|
||||||
|
},
|
||||||
|
height: size.height *0.33,
|
||||||
|
enlargeCenterPage: true,
|
||||||
|
pageSnapping: true,
|
||||||
|
reverse: false,
|
||||||
|
),
|
||||||
|
items: selectedPoint.contents!.map<Widget>((ContentDTO i) {
|
||||||
|
return Builder(
|
||||||
|
builder: (BuildContext context) {
|
||||||
|
AppContext appContext = Provider.of<AppContext>(context);
|
||||||
|
var resourcetoShow = getElementForResource(context, appContext, i, true);
|
||||||
|
return resourcetoShow;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}).toList(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
//color: Colors.yellow,
|
||||||
|
height: size.height * 0.33,
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.only(top: 10.0),
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
/*if(isPointPrice && selectedPoint.prices!.firstWhere((d) => d.language == language).value!.length > breakPointPrice)
|
||||||
|
Container(
|
||||||
|
height: size.height * 0.1,
|
||||||
|
width: size.width * 0.38,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: kBackgroundLight,
|
||||||
|
borderRadius: BorderRadius.all(Radius.circular(tabletAppContext.configuration!.roundedValue?.toDouble() ?? 20.0))
|
||||||
|
),
|
||||||
|
child: Padding(
|
||||||
|
padding: EdgeInsets.all(5),
|
||||||
|
child: Scrollbar(
|
||||||
|
thumbVisibility: true,
|
||||||
|
thickness: 2.0,
|
||||||
|
child: SingleChildScrollView(
|
||||||
|
child: Padding(
|
||||||
|
padding: EdgeInsets.all(5.0),
|
||||||
|
child: Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
// todo add width ?
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.all(5.0),
|
||||||
|
child: Icon(Icons.price_change_outlined, color: primaryColor, size: 13),
|
||||||
|
),
|
||||||
|
HtmlWidget(
|
||||||
|
selectedPoint.prices!.firstWhere((d) => d.language == language).value!,
|
||||||
|
customStylesBuilder: (element) {
|
||||||
|
return {'text-align': 'left', 'font-family': "Roboto"};
|
||||||
|
},
|
||||||
|
textStyle: TextStyle(fontSize: 12),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),*/
|
||||||
|
if(isPointPrice && selectedPoint.prices!.firstWhere((d) => d.language == language).value!.length <= breakPointPrice)
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Icon(Icons.price_change_outlined, color: primaryColor, size: 13),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.all(4.0),
|
||||||
|
child: HtmlWidget(
|
||||||
|
selectedPoint.prices!.firstWhere((d) => d.language == language).value!,
|
||||||
|
customStylesBuilder: (element) {
|
||||||
|
return {'text-align': 'left', 'font-family': "Roboto"};
|
||||||
|
},
|
||||||
|
textStyle: TextStyle(fontSize: 12),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
selectedPoint.phone != null && selectedPoint.phone!.isNotEmpty && selectedPoint.phone!.any((d) => d.language == language) && selectedPoint.phone!.firstWhere((d) => d.language == language).value != null && selectedPoint.phone!.firstWhere((d) => d.language == language).value!.trim().length > 0 ? Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Icon(Icons.phone, color: primaryColor, size: 13),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.all(4.0),
|
||||||
|
child: Text(parse(selectedPoint.phone!.firstWhere((p) => p.language == language).value!).documentElement!.text, style: TextStyle(fontSize: 12)),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
): SizedBox(),
|
||||||
|
selectedPoint.email != null && selectedPoint.email!.isNotEmpty && selectedPoint.email!.any((d) => d.language == language) && selectedPoint.email!.firstWhere((d) => d.language == language).value != null && selectedPoint.email!.firstWhere((d) => d.language == language).value!.trim().length > 0 ? Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Icon(Icons.email, color: primaryColor, size: 13),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.all(4.0),
|
||||||
|
child: SizedBox(
|
||||||
|
width: size.width*0.25,
|
||||||
|
child: AutoSizeText(parse(selectedPoint.email!.firstWhere((p) => p.language == language).value!).documentElement!.text, style: TextStyle(fontSize: 12), maxLines: 3)
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
): SizedBox(),
|
||||||
|
selectedPoint.site != null && selectedPoint.site!.isNotEmpty && selectedPoint.site!.any((d) => d.language == language) && selectedPoint.site!.firstWhere((d) => d.language == language).value != null && selectedPoint.site!.firstWhere((d) => d.language == language).value!.trim().length > 0 ? Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Icon(Icons.public, color: primaryColor, size: 13),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.all(4.0),
|
||||||
|
child: SizedBox(
|
||||||
|
width: size.width*0.25,
|
||||||
|
child: AutoSizeText(parse(selectedPoint.site!.firstWhere((p) => p.language == language).value!).documentElement!.text, style: TextStyle(fontSize: 12), maxLines: 3)
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
): SizedBox(),
|
||||||
|
selectedPoint.site != null && selectedPoint.site!.isNotEmpty && selectedPoint.site!.any((d) => d.language == language) && selectedPoint.site!.firstWhere((d) => d.language == language).value != null && selectedPoint.site!.firstWhere((d) => d.language == language).value!.trim().length > 0 ? Expanded(
|
||||||
|
child: Center(
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(8.0),
|
||||||
|
child: Container(
|
||||||
|
width: size.width *0.1,
|
||||||
|
height: 120,
|
||||||
|
child: QrImageView(
|
||||||
|
padding: EdgeInsets.only(left: 5.0, top: 5.0, bottom: 5.0, right: 5.0),
|
||||||
|
data: parse(selectedPoint.site!.firstWhere((p) => p.language == language).value!).documentElement!.text,
|
||||||
|
version: QrVersions.auto,
|
||||||
|
size: 50.0,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
): SizedBox(),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
/*Align(
|
||||||
|
alignment: Alignment.topCenter,
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.only(top: 20),
|
||||||
|
child: HtmlWidget(
|
||||||
|
(mapContext.getSelectedMarker() as MapMarker).title!,
|
||||||
|
customStylesBuilder: (element) {
|
||||||
|
return {'text-align': 'center'};
|
||||||
|
},
|
||||||
|
textStyle: TextStyle(fontWeight: FontWeight.w500, fontSize: kIsWeb ? kWebTitleSize : kTitleSize)
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.only(top: 75),
|
||||||
|
child: Center(
|
||||||
|
child: Stack(
|
||||||
|
children: [
|
||||||
|
Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||||
|
children: [
|
||||||
|
if((mapContext.getSelectedMarker() as MapMarker).contents != null && (mapContext.getSelectedMarker() as MapMarker).contents!.length > 0)
|
||||||
|
Stack(
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
//color: Colors.green,
|
||||||
|
child: CarouselSlider(
|
||||||
|
carouselController: sliderController,
|
||||||
|
options: CarouselOptions(
|
||||||
|
onPageChanged: (int index, CarouselPageChangedReason reason) {
|
||||||
|
currentIndex.value = index + 1;
|
||||||
|
},
|
||||||
|
height: size.height *0.35,
|
||||||
|
enlargeCenterPage: true,
|
||||||
|
pageSnapping: true,
|
||||||
|
reverse: false,
|
||||||
|
),
|
||||||
|
items: (mapContext.getSelectedMarker() as MapMarker).contents!.map<Widget>((ContentGeoPoint i) {
|
||||||
|
return Builder(
|
||||||
|
builder: (BuildContext context) {
|
||||||
|
AppContext appContext = Provider.of<AppContext>(context);
|
||||||
|
var resourcetoShow = getElementForResource(context, appContext, i);
|
||||||
|
return Padding(
|
||||||
|
padding: const EdgeInsets.all(8.0),
|
||||||
|
child: resourcetoShow,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}).toList(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Positioned(
|
||||||
|
bottom: 0,
|
||||||
|
child: Container(
|
||||||
|
//color: Colors.red,
|
||||||
|
height: 25,
|
||||||
|
width: sizeMarker.width,
|
||||||
|
//color: Colors.amber,
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.only(top: 0),
|
||||||
|
child: Align(
|
||||||
|
alignment: Alignment.bottomCenter,
|
||||||
|
child: ValueListenableBuilder<int>(
|
||||||
|
valueListenable: currentIndex,
|
||||||
|
builder: (context, value, _) {
|
||||||
|
return Text(
|
||||||
|
value.toString()+'/'+(mapContext.getSelectedMarker() as MapMarker).contents!.length.toString(),
|
||||||
|
style: TextStyle(fontSize: 15, fontWeight: FontWeight.w500),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
)
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
// Description
|
||||||
|
Container(
|
||||||
|
height: (mapContext.getSelectedMarker() as MapMarker).contents != null && (mapContext.getSelectedMarker() as MapMarker).contents!.length > 0 ? size.height *0.3 : size.height *0.6,
|
||||||
|
width: MediaQuery.of(context).size.width *0.4,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: kBackgroundColor,
|
||||||
|
shape: BoxShape.rectangle,
|
||||||
|
borderRadius: BorderRadius.circular(tabletAppContext.configuration!.roundedValue?.toDouble() ?? 10.0),
|
||||||
|
boxShadow: [
|
||||||
|
BoxShadow(
|
||||||
|
color: kBackgroundSecondGrey,
|
||||||
|
spreadRadius: 0.5,
|
||||||
|
blurRadius: 1.1,
|
||||||
|
offset: Offset(0, 1.1), // changes position of shadow
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
child: SingleChildScrollView(
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(15.0),
|
||||||
|
child: HtmlWidget(
|
||||||
|
(mapContext.getSelectedMarker() as MapMarker).description!,
|
||||||
|
customStylesBuilder: (element) {
|
||||||
|
return {'text-align': 'center'};
|
||||||
|
},
|
||||||
|
textStyle: TextStyle(fontSize: kIsWeb ? kWebDescriptionSize : kDescriptionSize)
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
]
|
||||||
|
),
|
||||||
|
if((mapContext.getSelectedMarker() as MapMarker).contents != null && (mapContext.getSelectedMarker() as MapMarker).contents!.length > 1)
|
||||||
|
Positioned(
|
||||||
|
top: MediaQuery.of(context).size.height * 0.125,
|
||||||
|
right: -10,
|
||||||
|
child: InkWell(
|
||||||
|
onTap: () {
|
||||||
|
if ((mapContext.getSelectedMarker() as MapMarker).contents!.length > 0)
|
||||||
|
sliderController!.nextPage(duration: new Duration(milliseconds: 500), curve: Curves.fastOutSlowIn);
|
||||||
|
},
|
||||||
|
child: Icon(
|
||||||
|
Icons.chevron_right,
|
||||||
|
size: kIsWeb ? 100 : 85,
|
||||||
|
color: kTestSecondColor,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
),
|
||||||
|
if((mapContext.getSelectedMarker() as MapMarker).contents != null && (mapContext.getSelectedMarker() as MapMarker).contents!.length > 1)
|
||||||
|
Positioned(
|
||||||
|
top: MediaQuery.of(context).size.height * 0.125,
|
||||||
|
left: -10,
|
||||||
|
child: InkWell(
|
||||||
|
onTap: () {
|
||||||
|
if ((mapContext.getSelectedMarker() as MapMarker).contents!.length > 0)
|
||||||
|
sliderController!.previousPage(duration: new Duration(milliseconds: 500), curve: Curves.fastOutSlowIn);
|
||||||
|
},
|
||||||
|
child: Icon(
|
||||||
|
Icons.chevron_left,
|
||||||
|
size: kIsWeb ? 100 : 85,
|
||||||
|
color: kTestSecondColor,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),*/
|
||||||
|
])
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getElementForResource(BuildContext context, AppContext appContext, ContentDTO i, bool addFullScreen) {
|
||||||
|
var widgetToInclude;
|
||||||
|
Size size = MediaQuery.of(context).size;
|
||||||
|
VisitAppContext visitAppContext = appContext.getContext() as VisitAppContext;
|
||||||
|
|
||||||
|
switch(i.resource?.type) {
|
||||||
|
case ResourceType.Image:
|
||||||
|
case ResourceType.ImageUrl:
|
||||||
|
widgetToInclude = GestureDetector(
|
||||||
|
onTap: () {
|
||||||
|
if(addFullScreen) {
|
||||||
|
showDialog(
|
||||||
|
context: context,
|
||||||
|
builder: (BuildContext context) {
|
||||||
|
return AlertDialog(
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.all(Radius.circular(visitAppContext.configuration!.roundedValue?.toDouble() ?? 20.0))
|
||||||
|
),
|
||||||
|
contentPadding: EdgeInsets.zero,
|
||||||
|
// title: Text(eventAgenda.name!),
|
||||||
|
content: Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
borderRadius: BorderRadius.all(Radius.circular(visitAppContext.configuration!.roundedValue?.toDouble() ?? 20.0)),
|
||||||
|
color: kBackgroundColor,
|
||||||
|
),
|
||||||
|
height: size.height * 0.8,
|
||||||
|
width: size.width * 0.8,
|
||||||
|
child: Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
//color: Colors.yellow,
|
||||||
|
borderRadius: BorderRadius.all(Radius.circular(visitAppContext.configuration!.roundedValue?.toDouble() ?? 15.0)),
|
||||||
|
),
|
||||||
|
child: PhotoView(
|
||||||
|
imageProvider: ImageCustomProvider.getImageProvider(appContext, i.resourceId!, i.resource!.url!),
|
||||||
|
minScale: PhotoViewComputedScale.contained * 0.8,
|
||||||
|
maxScale: PhotoViewComputedScale.contained * 3.0,
|
||||||
|
backgroundDecoration: BoxDecoration(
|
||||||
|
color: kBackgroundGrey,
|
||||||
|
shape: BoxShape.rectangle,
|
||||||
|
borderRadius: BorderRadius.circular(visitAppContext.configuration!.roundedValue?.toDouble() ?? 15.0),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
child: Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
//color: kBackgroundLight,
|
||||||
|
image: DecorationImage(
|
||||||
|
image: ImageCustomProvider.getImageProvider(appContext, i.resourceId!, i.resource!.url!),
|
||||||
|
fit: BoxFit.cover,
|
||||||
|
),
|
||||||
|
borderRadius: BorderRadius.all(Radius.circular(visitAppContext.configuration!.roundedValue?.toDouble() ?? 15.0)),
|
||||||
|
/*border: Border.all(
|
||||||
|
color: kBackgroundGrey,
|
||||||
|
width: 1.0,
|
||||||
|
),*/
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
case ResourceType.Video:
|
||||||
|
case ResourceType.VideoUrl:
|
||||||
|
case ResourceType.Audio:
|
||||||
|
widgetToInclude = GestureDetector(
|
||||||
|
behavior: HitTestBehavior.translucent,
|
||||||
|
onTap: () {
|
||||||
|
if(addFullScreen && i.resource!.type != ResourceType.Audio) {
|
||||||
|
showDialog(
|
||||||
|
context: context,
|
||||||
|
builder: (BuildContext context) {
|
||||||
|
return AlertDialog(
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.all(Radius.circular(visitAppContext.configuration!.roundedValue?.toDouble() ?? 20.0))
|
||||||
|
),
|
||||||
|
contentPadding: EdgeInsets.zero,
|
||||||
|
// title: Text(eventAgenda.name!),
|
||||||
|
content: Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
borderRadius: BorderRadius.all(Radius.circular(visitAppContext.configuration!.roundedValue?.toDouble() ?? 20.0)),
|
||||||
|
color: kBackgroundColor,
|
||||||
|
),
|
||||||
|
height: size.height * 0.8,
|
||||||
|
width: size.width * 0.8,
|
||||||
|
child: Center(child: showElementForResource(ResourceDTO(id: i.resourceId, url: i.resource?.url, type: i.resource?.type), appContext, false, true)),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
child: IgnorePointer(
|
||||||
|
ignoring: i.resource!.type != ResourceType.Audio,
|
||||||
|
child: Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.yellow,
|
||||||
|
shape: BoxShape.rectangle,
|
||||||
|
borderRadius: BorderRadius.circular(visitAppContext.configuration!.roundedValue?.toDouble() ?? 15.0),
|
||||||
|
),
|
||||||
|
child: showElementForResource(ResourceDTO(id: i.resourceId, url: i.resource?.url, type: i.resource?.type), appContext, false, true),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Center(
|
||||||
|
child: Container(
|
||||||
|
height: MediaQuery.of(context).size.height * 0.6,
|
||||||
|
width: MediaQuery.of(context).size.width * 0.72,
|
||||||
|
child: AspectRatio(
|
||||||
|
aspectRatio: 16 / 9,
|
||||||
|
child: ClipRect(
|
||||||
|
child: widgetToInclude,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
42
lib/Screens/Sections/Map/tree_node.dart
Normal file
42
lib/Screens/Sections/Map/tree_node.dart
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
class TreeNode {
|
||||||
|
bool checked;
|
||||||
|
bool show;
|
||||||
|
int id;
|
||||||
|
int pid;
|
||||||
|
int commonID;
|
||||||
|
String title;
|
||||||
|
List<TreeNode> children;
|
||||||
|
|
||||||
|
TreeNode({
|
||||||
|
required this.checked,
|
||||||
|
required this.show,
|
||||||
|
required this.id,
|
||||||
|
required this.pid,
|
||||||
|
required this.commonID,
|
||||||
|
required this.title,
|
||||||
|
required this.children,
|
||||||
|
});
|
||||||
|
|
||||||
|
factory TreeNode.fromJson(Map<String, dynamic> json) {
|
||||||
|
return TreeNode(
|
||||||
|
checked: json['checked'] ?? false,
|
||||||
|
show: json['show'] ?? false,
|
||||||
|
id: json['id'] ?? 0,
|
||||||
|
pid: json['pid'] ?? 0,
|
||||||
|
commonID: json['commonID'] ?? 0,
|
||||||
|
title: json['title'] ?? '',
|
||||||
|
children: (json['children'] as List<dynamic>)
|
||||||
|
.map((childJson) => TreeNode.fromJson(childJson))
|
||||||
|
.toList(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
List<int> getAllChildrenTitles() {
|
||||||
|
List<int> id = [];
|
||||||
|
for (var child in children) {
|
||||||
|
id.add(child.id);
|
||||||
|
id.addAll(child.getAllChildrenTitles());
|
||||||
|
}
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -55,14 +55,21 @@ class _SliderPage extends State<SliderPage> {
|
|||||||
|
|
||||||
return Stack(
|
return Stack(
|
||||||
children: [
|
children: [
|
||||||
|
Container(
|
||||||
|
height: size.height,
|
||||||
|
width: size.width,
|
||||||
|
color: kBackgroundLight,
|
||||||
|
),
|
||||||
if(sliderDTO.contents != null && sliderDTO.contents!.isNotEmpty)
|
if(sliderDTO.contents != null && sliderDTO.contents!.isNotEmpty)
|
||||||
CarouselSlider(
|
Center(
|
||||||
|
child: CarouselSlider(
|
||||||
carouselController: sliderController,
|
carouselController: sliderController,
|
||||||
options: CarouselOptions(
|
options: CarouselOptions(
|
||||||
onPageChanged: (int index, CarouselPageChangedReason reason) {
|
onPageChanged: (int index, CarouselPageChangedReason reason) {
|
||||||
currentIndex.value = index + 1;
|
currentIndex.value = index + 1;
|
||||||
},
|
},
|
||||||
height: MediaQuery.of(context).size.height * 1.0,
|
enableInfiniteScroll: false,
|
||||||
|
height: MediaQuery.of(context).size.height * 0.92,
|
||||||
enlargeCenterPage: false,
|
enlargeCenterPage: false,
|
||||||
reverse: false,
|
reverse: false,
|
||||||
),
|
),
|
||||||
@ -74,7 +81,7 @@ class _SliderPage extends State<SliderPage> {
|
|||||||
height: MediaQuery.of(context).size.height,
|
height: MediaQuery.of(context).size.height,
|
||||||
margin: const EdgeInsets.symmetric(horizontal: 5.0),
|
margin: const EdgeInsets.symmetric(horizontal: 5.0),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Colors.green,
|
color: kBackgroundGrey,
|
||||||
//color: configurationDTO.imageId == null ? configurationDTO.secondaryColor != null ? new Color(int.parse(configurationDTO.secondaryColor!.split('(0x')[1].split(')')[0], radix: 16)): kBackgroundGrey : null,
|
//color: configurationDTO.imageId == null ? configurationDTO.secondaryColor != null ? new Color(int.parse(configurationDTO.secondaryColor!.split('(0x')[1].split(')')[0], radix: 16)): kBackgroundGrey : null,
|
||||||
borderRadius: BorderRadius.circular(visitAppContex.configuration!.roundedValue?.toDouble() ?? 10.0),
|
borderRadius: BorderRadius.circular(visitAppContex.configuration!.roundedValue?.toDouble() ?? 10.0),
|
||||||
//border: Border.all(width: 0.3, color: kSecondGrey),
|
//border: Border.all(width: 0.3, color: kSecondGrey),
|
||||||
@ -86,7 +93,7 @@ class _SliderPage extends State<SliderPage> {
|
|||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.all(10.0),
|
padding: const EdgeInsets.all(10.0),
|
||||||
child: Container(
|
child: Container(
|
||||||
color: Colors.orange,
|
//color: Colors.orange,
|
||||||
height: MediaQuery.of(context).size.height * 0.6,
|
height: MediaQuery.of(context).size.height * 0.6,
|
||||||
width: MediaQuery.of(context).size.width * 0.72,
|
width: MediaQuery.of(context).size.width * 0.72,
|
||||||
/*decoration: BoxDecoration(
|
/*decoration: BoxDecoration(
|
||||||
@ -133,7 +140,7 @@ class _SliderPage extends State<SliderPage> {
|
|||||||
height: MediaQuery.of(context).size.height *0.25,
|
height: MediaQuery.of(context).size.height *0.25,
|
||||||
width: MediaQuery.of(context).size.width *0.7,
|
width: MediaQuery.of(context).size.width *0.7,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Colors.blue,// kBackgroundLight,
|
color: kBackgroundLight,// kBackgroundLight,
|
||||||
shape: BoxShape.rectangle,
|
shape: BoxShape.rectangle,
|
||||||
borderRadius: BorderRadius.circular(visitAppContex.configuration!.roundedValue?.toDouble() ?? 10.0),
|
borderRadius: BorderRadius.circular(visitAppContex.configuration!.roundedValue?.toDouble() ?? 10.0),
|
||||||
boxShadow: const [
|
boxShadow: const [
|
||||||
@ -167,6 +174,7 @@ class _SliderPage extends State<SliderPage> {
|
|||||||
);
|
);
|
||||||
}).toList(),
|
}).toList(),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
/*if(sliderDTO.contents != null && sliderDTO.contents!.length > 1)
|
/*if(sliderDTO.contents != null && sliderDTO.contents!.length > 1)
|
||||||
Positioned(
|
Positioned(
|
||||||
top: MediaQuery.of(context).size.height * 0.35,
|
top: MediaQuery.of(context).size.height * 0.35,
|
||||||
@ -214,7 +222,7 @@ class _SliderPage extends State<SliderPage> {
|
|||||||
return AnimatedSmoothIndicator(
|
return AnimatedSmoothIndicator(
|
||||||
activeIndex: value -1,
|
activeIndex: value -1,
|
||||||
count: sliderDTO.contents!.length,
|
count: sliderDTO.contents!.length,
|
||||||
effect: const ExpandingDotsEffect(activeDotColor: kMainColor),
|
effect: ExpandingDotsEffect(activeDotColor: primaryColor!),
|
||||||
);
|
);
|
||||||
|
|
||||||
/*Text(
|
/*Text(
|
||||||
@ -287,8 +295,16 @@ class _SliderPage extends State<SliderPage> {
|
|||||||
minScale: PhotoViewComputedScale.contained * 0.8,
|
minScale: PhotoViewComputedScale.contained * 0.8,
|
||||||
maxScale: PhotoViewComputedScale.contained * 3.0,
|
maxScale: PhotoViewComputedScale.contained * 3.0,
|
||||||
backgroundDecoration: BoxDecoration(
|
backgroundDecoration: BoxDecoration(
|
||||||
color: kBackgroundSecondGrey,
|
color: kBackgroundLight,
|
||||||
shape: BoxShape.rectangle,
|
shape: BoxShape.rectangle,
|
||||||
|
boxShadow: const [
|
||||||
|
BoxShadow(
|
||||||
|
color: kBackgroundGrey,
|
||||||
|
spreadRadius: 0.3,
|
||||||
|
blurRadius: 4,
|
||||||
|
offset: Offset(0, 2), // changes position of shadow
|
||||||
|
),
|
||||||
|
],
|
||||||
borderRadius: BorderRadius.circular(visitAppContext.configuration!.roundedValue?.toDouble() ?? 15.0),
|
borderRadius: BorderRadius.circular(visitAppContext.configuration!.roundedValue?.toDouble() ?? 15.0),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@ -299,8 +315,16 @@ class _SliderPage extends State<SliderPage> {
|
|||||||
minScale: PhotoViewComputedScale.contained * 0.8,
|
minScale: PhotoViewComputedScale.contained * 0.8,
|
||||||
maxScale: PhotoViewComputedScale.contained * 3.0,
|
maxScale: PhotoViewComputedScale.contained * 3.0,
|
||||||
backgroundDecoration: BoxDecoration(
|
backgroundDecoration: BoxDecoration(
|
||||||
color: kBackgroundSecondGrey,
|
color: kBackgroundLight,
|
||||||
shape: BoxShape.rectangle,
|
shape: BoxShape.rectangle,
|
||||||
|
boxShadow: const [
|
||||||
|
BoxShadow(
|
||||||
|
color: kBackgroundGrey,
|
||||||
|
spreadRadius: 0.3,
|
||||||
|
blurRadius: 4,
|
||||||
|
offset: Offset(0, 2), // changes position of shadow
|
||||||
|
),
|
||||||
|
],
|
||||||
borderRadius: BorderRadius.circular(visitAppContext.configuration!.roundedValue?.toDouble() ?? 15.0),
|
borderRadius: BorderRadius.circular(visitAppContext.configuration!.roundedValue?.toDouble() ?? 15.0),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@ -310,7 +334,7 @@ class _SliderPage extends State<SliderPage> {
|
|||||||
case ResourceType.Audio:
|
case ResourceType.Audio:
|
||||||
widgetToInclude = Container(
|
widgetToInclude = Container(
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
//color: kBackgroundSecondGrey,
|
color: kBackgroundLight,
|
||||||
//shape: BoxShape.rectangle,
|
//shape: BoxShape.rectangle,
|
||||||
borderRadius: BorderRadius.circular(visitAppContext.configuration!.roundedValue?.toDouble() ?? 15.0),
|
borderRadius: BorderRadius.circular(visitAppContext.configuration!.roundedValue?.toDouble() ?? 15.0),
|
||||||
),
|
),
|
||||||
@ -323,7 +347,6 @@ class _SliderPage extends State<SliderPage> {
|
|||||||
child: Container(
|
child: Container(
|
||||||
height: MediaQuery.of(context).size.height * 0.6,
|
height: MediaQuery.of(context).size.height * 0.6,
|
||||||
width: MediaQuery.of(context).size.width * 0.72,
|
width: MediaQuery.of(context).size.width * 0.72,
|
||||||
color: Colors.yellow,
|
|
||||||
child: AspectRatio(
|
child: AspectRatio(
|
||||||
aspectRatio: 16 / 9,
|
aspectRatio: 16 / 9,
|
||||||
child: ClipRect(
|
child: ClipRect(
|
||||||
@ -256,6 +256,7 @@ class _BodyState extends State<Body> {
|
|||||||
rawSections = jsonDecode(jsonEncode(sectionsDownloaded));
|
rawSections = jsonDecode(jsonEncode(sectionsDownloaded));
|
||||||
var rawToSection = jsonDecode(jsonEncode(rawSections)).map((json) => SectionDTO.fromJson(json)).toList();
|
var rawToSection = jsonDecode(jsonEncode(rawSections)).map((json) => SectionDTO.fromJson(json)).toList();
|
||||||
List<SectionDTO> sectionList = rawToSection.whereType<SectionDTO>().toList();
|
List<SectionDTO> sectionList = rawToSection.whereType<SectionDTO>().toList();
|
||||||
|
visitAppContext.currentSections = rawSections;
|
||||||
|
|
||||||
//print(sectionsDownloaded);
|
//print(sectionsDownloaded);
|
||||||
if(sectionList.isNotEmpty) {
|
if(sectionList.isNotEmpty) {
|
||||||
|
|||||||
@ -78,6 +78,7 @@ class _VisitPageState extends State<VisitPage> with WidgetsBindingObserver {
|
|||||||
final appContext = Provider.of<AppContext>(context, listen: false);
|
final appContext = Provider.of<AppContext>(context, listen: false);
|
||||||
VisitAppContext visitAppContext = appContext.getContext();
|
VisitAppContext visitAppContext = appContext.getContext();
|
||||||
visitAppContext.configuration = widget.configuration;
|
visitAppContext.configuration = widget.configuration;
|
||||||
|
visitAppContext.sectionIds = widget.configuration.sectionIds;
|
||||||
appContext.setContext(visitAppContext);
|
appContext.setContext(visitAppContext);
|
||||||
});
|
});
|
||||||
//listeningState();
|
//listeningState();
|
||||||
|
|||||||
@ -1,10 +1,11 @@
|
|||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
import 'dart:developer';
|
import 'dart:io';
|
||||||
import 'dart:typed_data';
|
import 'dart:typed_data';
|
||||||
|
|
||||||
//import 'package:confetti/confetti.dart';
|
//import 'package:confetti/confetti.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
import 'package:manager_api_new/api.dart';
|
import 'package:manager_api_new/api.dart';
|
||||||
import 'package:mymuseum_visitapp/Components/CustomAppBar.dart';
|
import 'package:mymuseum_visitapp/Components/CustomAppBar.dart';
|
||||||
import 'package:mymuseum_visitapp/Components/loading_common.dart';
|
import 'package:mymuseum_visitapp/Components/loading_common.dart';
|
||||||
@ -14,16 +15,21 @@ import 'package:mymuseum_visitapp/Models/articleRead.dart';
|
|||||||
import 'package:mymuseum_visitapp/Models/resourceModel.dart';
|
import 'package:mymuseum_visitapp/Models/resourceModel.dart';
|
||||||
import 'package:mymuseum_visitapp/Models/visitContext.dart';
|
import 'package:mymuseum_visitapp/Models/visitContext.dart';
|
||||||
import 'package:mymuseum_visitapp/Screens/Sections/Article/article_page.dart';
|
import 'package:mymuseum_visitapp/Screens/Sections/Article/article_page.dart';
|
||||||
import 'package:mymuseum_visitapp/Screens/Sections/PDF/pdf_view.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/Puzzle/puzzle_page.dart';
|
||||||
import 'package:mymuseum_visitapp/Screens/Sections/Quiz/quizz_page.dart';
|
import 'package:mymuseum_visitapp/Screens/Sections/Quiz/quizz_page.dart';
|
||||||
import 'package:mymuseum_visitapp/Screens/Sections/Slider/slider_view.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/Video/video_page.dart';
|
||||||
import 'package:mymuseum_visitapp/Screens/Sections/Web/web_page.dart';
|
import 'package:mymuseum_visitapp/Screens/Sections/Web/web_page.dart';
|
||||||
import 'package:mymuseum_visitapp/app_context.dart';
|
import 'package:mymuseum_visitapp/app_context.dart';
|
||||||
import 'package:mymuseum_visitapp/client.dart';
|
import 'package:mymuseum_visitapp/client.dart';
|
||||||
import 'package:mymuseum_visitapp/constants.dart';
|
|
||||||
import 'package:provider/provider.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 {
|
class SectionPage extends StatefulWidget {
|
||||||
const SectionPage({Key? key, required this.rawSection, required this.visitAppContextIn, required this.configuration, required this.sectionId}) : super(key: key);
|
const SectionPage({Key? key, required this.rawSection, required this.visitAppContextIn, required this.configuration, required this.sectionId}) : super(key: key);
|
||||||
@ -44,6 +50,9 @@ class _SectionPageState extends State<SectionPage> {
|
|||||||
late dynamic rawSectionData;
|
late dynamic rawSectionData;
|
||||||
List<ResourceModel?> resourcesModel = <ResourceModel?>[];
|
List<ResourceModel?> resourcesModel = <ResourceModel?>[];
|
||||||
|
|
||||||
|
late final MapContext mapContext = MapContext(null);
|
||||||
|
List<Map<String, dynamic>>? icons;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
widget.visitAppContextIn.isContentCurrentlyShown = true;
|
widget.visitAppContextIn.isContentCurrentlyShown = true;
|
||||||
@ -66,11 +75,15 @@ class _SectionPageState extends State<SectionPage> {
|
|||||||
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
key: _scaffoldKey,
|
key: _scaffoldKey,
|
||||||
appBar: test!.type != SectionType.Quiz && test.type != SectionType.Article && test.type != SectionType.Web && test.type != SectionType.Pdf && test.type != SectionType.Video && test.type != SectionType.Puzzle && test.type != SectionType.Slider ? CustomAppBar(
|
resizeToAvoidBottomInset: false,
|
||||||
|
appBar: test!.type == SectionType.Menu || test.type == SectionType.Agenda || test.type == SectionType.Weather ? CustomAppBar(
|
||||||
title: sectionDTO != null ? TranslationHelper.get(sectionDTO!.title, visitAppContext) : "",
|
title: sectionDTO != null ? TranslationHelper.get(sectionDTO!.title, visitAppContext) : "",
|
||||||
isHomeButton: false,
|
isHomeButton: false,
|
||||||
) : null,
|
) : null,
|
||||||
body: OrientationBuilder(
|
body: MediaQuery.removeViewInsets(
|
||||||
|
context: context,
|
||||||
|
removeBottom: true,
|
||||||
|
child: OrientationBuilder(
|
||||||
builder: (context, orientation) {
|
builder: (context, orientation) {
|
||||||
return FutureBuilder(
|
return FutureBuilder(
|
||||||
future: getSectionDetail(appContext, visitAppContext.clientAPI, widget.sectionId),
|
future: getSectionDetail(appContext, visitAppContext.clientAPI, widget.sectionId),
|
||||||
@ -99,6 +112,12 @@ class _SectionPageState extends State<SectionPage> {
|
|||||||
case SectionType.Slider:
|
case SectionType.Slider:
|
||||||
SliderDTO sliderDTO = SliderDTO.fromJson(sectionResult)!;
|
SliderDTO sliderDTO = SliderDTO.fromJson(sectionResult)!;
|
||||||
return SliderPage(section: sliderDTO);
|
return SliderPage(section: sliderDTO);
|
||||||
|
case SectionType.Map:
|
||||||
|
MapDTO mapDTO = MapDTO.fromJson(sectionResult)!;
|
||||||
|
return ChangeNotifierProvider<MapContext>.value(
|
||||||
|
value: mapContext,
|
||||||
|
child: MapPage(section: mapDTO, icons: icons ?? []),
|
||||||
|
);
|
||||||
default:
|
default:
|
||||||
return const Center(child: Text("Unsupported type"));
|
return const Center(child: Text("Unsupported type"));
|
||||||
}
|
}
|
||||||
@ -108,6 +127,7 @@ class _SectionPageState extends State<SectionPage> {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
),
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -219,6 +239,10 @@ class _SectionPageState extends State<SectionPage> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case SectionType.Map:
|
||||||
|
MapDTO mapDTO = MapDTO.fromJson(rawSectionData)!;
|
||||||
|
icons = await getByteIcons(visitAppContext, mapDTO);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -232,3 +256,86 @@ class _SectionPageState extends State<SectionPage> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|||||||
308
pubspec.lock
308
pubspec.lock
@ -17,14 +17,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "6.4.1"
|
version: "6.4.1"
|
||||||
ar_flutter_plugin:
|
archive:
|
||||||
dependency: "direct main"
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: ar_flutter_plugin
|
name: archive
|
||||||
sha256: "52b6b2ccec4b624ca3fb8d7cc68128f11126580b412c3da2da82c41ddfd6d6ae"
|
sha256: "2fde1607386ab523f7a36bb3e7edb43bd58e6edaf2ffb29d8a6d578b297fdbbd"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.7.3"
|
version: "4.0.7"
|
||||||
args:
|
args:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -57,6 +57,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.0.0"
|
version: "3.0.0"
|
||||||
|
benchmark:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: benchmark
|
||||||
|
sha256: cb3eeea01e3f054df76ee9775ca680f3afa5f19f39b2bb426ba78ba27654493b
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.3.0"
|
||||||
boolean_selector:
|
boolean_selector:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -241,6 +249,22 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.8"
|
version: "1.0.8"
|
||||||
|
dart_earcut:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: dart_earcut
|
||||||
|
sha256: e485001bfc05dcbc437d7bfb666316182e3522d4c3f9668048e004d0eb2ce43b
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.2.0"
|
||||||
|
dart_sort_queue:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: dart_sort_queue
|
||||||
|
sha256: f3353ba8b4850e072d3368757f62edb79af34a9703c3e3df9c59342721f5f5b1
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.0.2+3"
|
||||||
dart_style:
|
dart_style:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -395,6 +419,14 @@ packages:
|
|||||||
description: flutter
|
description: flutter
|
||||||
source: sdk
|
source: sdk
|
||||||
version: "0.0.0"
|
version: "0.0.0"
|
||||||
|
flutter_map:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: flutter_map
|
||||||
|
sha256: "2ecb34619a4be19df6f40c2f8dce1591675b4eff7a6857bd8f533706977385da"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "7.0.2"
|
||||||
flutter_pdfview:
|
flutter_pdfview:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@ -403,6 +435,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.4.0+1"
|
version: "1.4.0+1"
|
||||||
|
flutter_plugin_android_lifecycle:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: flutter_plugin_android_lifecycle
|
||||||
|
sha256: "1c2b787f99bdca1f3718543f81d38aa1b124817dfeb9fb196201bea85b6134bf"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.0.26"
|
||||||
flutter_staggered_grid_view:
|
flutter_staggered_grid_view:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@ -509,54 +549,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.15.4"
|
version: "0.15.4"
|
||||||
geolocator:
|
geotypes:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: geolocator
|
name: geotypes
|
||||||
sha256: "5c23f3613f50586c0bbb2b8f970240ae66b3bd992088cf60dd5ee2e6f7dde3a8"
|
sha256: "5bedf57de92283133dd221e363812ef50eaaba414f0823b1974ef7d84b86991f"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "9.0.2"
|
version: "0.0.2"
|
||||||
geolocator_android:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: geolocator_android
|
|
||||||
sha256: "7aefc530db47d90d0580b552df3242440a10fe60814496a979aa67aa98b1fd47"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "4.6.1"
|
|
||||||
geolocator_apple:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: geolocator_apple
|
|
||||||
sha256: c4ecead17985ede9634f21500072edfcb3dba0ef7b97f8d7bc556d2d722b3ba3
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "2.3.9"
|
|
||||||
geolocator_platform_interface:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: geolocator_platform_interface
|
|
||||||
sha256: "386ce3d9cce47838355000070b1d0b13efb5bc430f8ecda7e9238c8409ace012"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "4.2.4"
|
|
||||||
geolocator_web:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: geolocator_web
|
|
||||||
sha256: "102e7da05b48ca6bf0a5bda0010f886b171d1a08059f01bfe02addd0175ebece"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "2.2.1"
|
|
||||||
geolocator_windows:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: geolocator_windows
|
|
||||||
sha256: "4f4218f122a6978d0ad655fa3541eea74c67417440b09f0657238810d5af6bdc"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "0.1.3"
|
|
||||||
get:
|
get:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@ -573,6 +573,54 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.2"
|
version: "2.1.2"
|
||||||
|
google_maps:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: google_maps
|
||||||
|
sha256: "4d6e199c561ca06792c964fa24b2bac7197bf4b401c2e1d23e345e5f9939f531"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "8.1.1"
|
||||||
|
google_maps_flutter:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: google_maps_flutter
|
||||||
|
sha256: "621125e35e81ca39ef600e45243d2be93167e61def72bc7207b0c4a635c58506"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.10.1"
|
||||||
|
google_maps_flutter_android:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: google_maps_flutter_android
|
||||||
|
sha256: "721ffae2240e957c04b0de19ffd4b68580adb57a8224496b7fb55fad23aec98a"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.14.13"
|
||||||
|
google_maps_flutter_ios:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: google_maps_flutter_ios
|
||||||
|
sha256: c7433645c4c9b61c587938cb06072f3dad601239e596b090c0f8f206c1f2ade7
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.15.2"
|
||||||
|
google_maps_flutter_platform_interface:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: google_maps_flutter_platform_interface
|
||||||
|
sha256: "970c8f766c02909c7be282dea923c971f83a88adaf07f8871d0aacebc3b07bb2"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.11.1"
|
||||||
|
google_maps_flutter_web:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: google_maps_flutter_web
|
||||||
|
sha256: a45786ea6691cc7cdbe2cf3ce2c2daf4f82a885745666b4a36baada3a4e12897
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.5.12"
|
||||||
graphs:
|
graphs:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -613,6 +661,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.0.2"
|
version: "4.0.2"
|
||||||
|
image:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: image
|
||||||
|
sha256: "4e973fcf4caae1a4be2fa0a13157aa38a8f9cb049db6529aa00b4d71abc4d928"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "4.5.4"
|
||||||
intl:
|
intl:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@ -677,6 +733,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.4.13"
|
version: "0.4.13"
|
||||||
|
latlong2:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: latlong2
|
||||||
|
sha256: "98227922caf49e6056f91b6c56945ea1c7b166f28ffcd5fb8e72fc0b453cc8fe"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.9.1"
|
||||||
leak_tracker:
|
leak_tracker:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -709,6 +773,22 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.1"
|
version: "1.0.1"
|
||||||
|
lists:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: lists
|
||||||
|
sha256: "4ca5c19ae4350de036a7e996cdd1ee39c93ac0a2b840f4915459b7d0a7d4ab27"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.1"
|
||||||
|
logger:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: logger
|
||||||
|
sha256: be4b23575aac7ebf01f225a241eb7f6b5641eeaf43c6a8613510fc2f8cf187d1
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.5.0"
|
||||||
logging:
|
logging:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -724,6 +804,14 @@ packages:
|
|||||||
relative: true
|
relative: true
|
||||||
source: path
|
source: path
|
||||||
version: "1.0.0"
|
version: "1.0.0"
|
||||||
|
mapbox_maps_flutter:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: mapbox_maps_flutter
|
||||||
|
sha256: f3dea7e14e5afc10ad03e16a6d5ece18ec5487ceaf9b2f83a64a2358d29149ba
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.8.0"
|
||||||
matcher:
|
matcher:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -748,6 +836,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.15.0"
|
version: "1.15.0"
|
||||||
|
mgrs_dart:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: mgrs_dart
|
||||||
|
sha256: fb89ae62f05fa0bb90f70c31fc870bcbcfd516c843fb554452ab3396f78586f7
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.0.0"
|
||||||
mime:
|
mime:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -756,6 +852,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.5"
|
version: "1.0.5"
|
||||||
|
mobile_scanner:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: mobile_scanner
|
||||||
|
sha256: "827765afbd4792ff3fd105ad593821ac0f6d8a7d352689013b07ee85be336312"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "4.0.1"
|
||||||
nested:
|
nested:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -956,6 +1060,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.8"
|
version: "2.1.8"
|
||||||
|
polylabel:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: polylabel
|
||||||
|
sha256: "41b9099afb2aa6c1730bdd8a0fab1400d287694ec7615dd8516935fa3144214b"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.1"
|
||||||
pool:
|
pool:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -964,6 +1076,22 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.5.1"
|
version: "1.5.1"
|
||||||
|
posix:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: posix
|
||||||
|
sha256: f0d7856b6ca1887cfa6d1d394056a296ae33489db914e365e2044fdada449e62
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "6.0.2"
|
||||||
|
proj4dart:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: proj4dart
|
||||||
|
sha256: c8a659ac9b6864aa47c171e78d41bbe6f5e1d7bd790a5814249e6b68bc44324e
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.1.0"
|
||||||
provider:
|
provider:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@ -988,14 +1116,30 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.3.0"
|
version: "1.3.0"
|
||||||
qr_code_scanner:
|
qr:
|
||||||
dependency: "direct main"
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: qr_code_scanner
|
name: qr
|
||||||
sha256: f23b68d893505a424f0bd2e324ebea71ed88465d572d26bb8d2e78a4749591fd
|
sha256: "5a1d2586170e172b8a8c8470bbbffd5eb0cd38a66c0d77155ea138d3af3a4445"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.1"
|
version: "3.0.2"
|
||||||
|
qr_flutter:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: qr_flutter
|
||||||
|
sha256: "5095f0fc6e3f71d08adef8feccc8cea4f12eec18a2e31c2e8d82cb6019f4b097"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "4.1.0"
|
||||||
|
rbush:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: rbush
|
||||||
|
sha256: "48b683421b4afb43a642f82c6aa31911e54f3069143d31c7d33cbe329df13403"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.1.1"
|
||||||
rxdart:
|
rxdart:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -1004,6 +1148,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.27.7"
|
version: "0.27.7"
|
||||||
|
sanitize_html:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: sanitize_html
|
||||||
|
sha256: "12669c4a913688a26555323fb9cec373d8f9fbe091f2d01c40c723b33caa8989"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.1.0"
|
||||||
shared_preferences:
|
shared_preferences:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -1161,6 +1313,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.3.0"
|
version: "1.3.0"
|
||||||
|
sweepline_intersections:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: sweepline_intersections
|
||||||
|
sha256: a665c707200a4f07140a4029b41a7c4883beb3f04322cd8e08ebf650f69e1176
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.0.4"
|
||||||
synchronized:
|
synchronized:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -1193,6 +1353,30 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.1"
|
version: "1.0.1"
|
||||||
|
turf:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: turf
|
||||||
|
sha256: "75347c45a5c1de805db7cb182286f05a3770e01546626c4dc292709d15cbe436"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.0.10"
|
||||||
|
turf_equality:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: turf_equality
|
||||||
|
sha256: f0f44ffe389547941358e0d3d4a747db2bd56115b32ff1cede5e5bdf3126a3e2
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.1.0"
|
||||||
|
turf_pip:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: turf_pip
|
||||||
|
sha256: ba4fd414baffd5d7b30880658ad6db82461c49ec023f8ffd0c23d398ad8b14be
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.0.2"
|
||||||
typed_data:
|
typed_data:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -1201,6 +1385,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.3.2"
|
version: "1.3.2"
|
||||||
|
unicode:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: unicode
|
||||||
|
sha256: "0f69e46593d65245774d4f17125c6084d2c20b4e473a983f6e21b7d7762218f1"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.3.1"
|
||||||
url_launcher:
|
url_launcher:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -1441,6 +1633,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "5.5.1"
|
version: "5.5.1"
|
||||||
|
wkt_parser:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: wkt_parser
|
||||||
|
sha256: "8a555fc60de3116c00aad67891bcab20f81a958e4219cc106e3c037aa3937f13"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.0.0"
|
||||||
xdg_directories:
|
xdg_directories:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|||||||
12
pubspec.yaml
12
pubspec.yaml
@ -48,14 +48,16 @@ dependencies:
|
|||||||
diacritic: ^0.1.3
|
diacritic: ^0.1.3
|
||||||
flutter_widget_from_html: ^0.15.2
|
flutter_widget_from_html: ^0.15.2
|
||||||
webview_flutter: ^4.10.0
|
webview_flutter: ^4.10.0
|
||||||
ar_flutter_plugin: ^0.7.3
|
#ar_flutter_plugin: ^0.7.3
|
||||||
|
|
||||||
flutter_pdfview: ^1.4.0+1
|
flutter_pdfview: ^1.4.0+1
|
||||||
youtube_player_flutter: ^9.1.1
|
youtube_player_flutter: ^9.1.1
|
||||||
youtube_player_iframe: ^5.2.1
|
youtube_player_iframe: ^5.2.1
|
||||||
|
|
||||||
# Specific mobile
|
# Specific mobile
|
||||||
qr_code_scanner: ^1.0.1 #not in web
|
#qr_code_scanner: ^1.0.1 #not in web
|
||||||
|
mobile_scanner: ^4.0.0 # that replace qr_code_scanner..
|
||||||
|
|
||||||
sqflite: #not in web
|
sqflite: #not in web
|
||||||
just_audio_cache: ^0.1.2 #not in web
|
just_audio_cache: ^0.1.2 #not in web
|
||||||
flutter_beacon: ^0.5.1 #not in web
|
flutter_beacon: ^0.5.1 #not in web
|
||||||
@ -63,6 +65,12 @@ dependencies:
|
|||||||
|
|
||||||
smooth_page_indicator: ^1.2.1
|
smooth_page_indicator: ^1.2.1
|
||||||
|
|
||||||
|
mapbox_maps_flutter: ^2.0.0 # specific mobile ..
|
||||||
|
google_maps_flutter: ^2.5.3 # Specific mobile and web
|
||||||
|
qr_flutter: ^4.1.0 # multi
|
||||||
|
flutter_map: ^7.0.2 #all
|
||||||
|
image: ^4.1.7
|
||||||
|
|
||||||
manager_api_new:
|
manager_api_new:
|
||||||
path: manager_api_new
|
path: manager_api_new
|
||||||
# The following adds the Cupertino Icons font to your application.
|
# The following adds the Cupertino Icons font to your application.
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user