import 'dart:async';
import 'dart:isolate';
import 'package:ar_flutter_plugin/datatypes/hittest_result_types.dart';
import 'package:ar_flutter_plugin/managers/ar_location_manager.dart';
import 'package:ar_flutter_plugin/managers/ar_session_manager.dart';
import 'package:ar_flutter_plugin/managers/ar_object_manager.dart';
import 'package:ar_flutter_plugin/managers/ar_anchor_manager.dart';
import 'package:ar_flutter_plugin/models/ar_anchor.dart';
import 'package:ar_flutter_plugin/models/ar_hittest_result.dart';
import 'package:flutter/foundation.dart';
import 'package:ar_flutter_plugin/datatypes/node_types.dart';
import 'package:ar_flutter_plugin/models/ar_node.dart';
import 'package:flutter/material.dart';
import 'package:image_gallery_saver/image_gallery_saver.dart';
import '../../models/database_helper.dart';
import '../../models/sub_category.dart';
import '../../models/object.dart';
import 'package:vector_math/vector_math_64.dart';
class ARViewModel extends ChangeNotifier {
List<String> subCategoriesList = [];
Map<String, List<ThreeDObject>> objects = {};
String? _categoryTitle;
String? get categoryTitle => _categoryTitle;
List<ThreeDObject> listObject = [];
String? objectTitle;
ARSessionManager? arSessionManager;
ARObjectManager? arObjectManager;
ARAnchorManager? arAnchorManager;
ARNode? fileSystemNode;
List<ARNode> nodes = [];
List<ARAnchor> anchors = [];
final List<double> values = [
1.0,
10.0,
20.0,
50.0,
60.0,
100.0,
200.0,
600.0
];
late double initialObjectScale;
int selectedValueIndex = 3;
String? selectedNodeName;
String? selectedObjectName; // Propriété pour stocker le nom de l'objet
sélectionné
Map<String, String> nodeTitles = {}; // Map pour stocker l'association node ID ->
objectTitle
late BuildContext contextArView;
ARViewModel() {
objectTitle = (listObject.isEmpty) ? "" : listObject.first.name;
initialObjectScale = values[selectedValueIndex];
}
Future<void> genListSubCategory(String categoryTitle) async {
try {
if (objects.isEmpty) {
var databaseHelper = DatabaseHelper();
var results = await Future.wait([
databaseHelper.getSubCategories(),
databaseHelper.getObjects(),
]);
var subCategories = results[0] as List<SubCategories>;
var threeDObjects = results[1] as List<ThreeDObject>;
subCategories
.where((s) => s.category.title == categoryTitle)
.forEach((s) {
subCategoriesList.add(s.name);
});
debugPrint('AR View Sub List : $subCategoriesList');
threeDObjects.forEach((o) {
if (o.subCategory.category.title == categoryTitle) {
String subcategoryName = o.subCategory.name;
objects.putIfAbsent(subcategoryName, () => []).add(o);
}
});
debugPrint('AR View Object : $objects');
notifyListeners();
}
} catch (e) {
debugPrint('Error in genListSubCategory: $e');
}
}
void setContext(BuildContext context) {
contextArView = context;
}
void updateObjectsList(List<ThreeDObject> objects) {
listObject = objects;
}
void setCategoryTitle(String? title) {
_categoryTitle = title;
}
void setOjectTitle(String? title) {
objectTitle = title;
notifyListeners();
}
void onARViewCreated(
ARSessionManager arSessionManager,
ARObjectManager arObjectManager,
ARAnchorManager arAnchorManager,
ARLocationManager arLocationManager) {
this.arSessionManager = arSessionManager;
this.arObjectManager = arObjectManager;
this.arAnchorManager = arAnchorManager;
this.arSessionManager!.onInitialize(
showFeaturePoints: false,
showPlanes: true,
customPlaneTexturePath: "assets/Images/triangle.png",
showWorldOrigin: false,
handlePans: true,
handleRotation: true,
showAnimatedGuide: true);
this.arObjectManager!.onInitialize();
this.arSessionManager!.onPlaneOrPointTap = onPlaneOrPointTapped;
this.arObjectManager!.onPanStart = onPanStarted;
this.arObjectManager!.onPanChange = onPanChanged;
this.arObjectManager!.onPanEnd = onPanEnded;
this.arObjectManager!.onRotationStart = onRotationStarted;
this.arObjectManager!.onRotationChange = onRotationChanged;
this.arObjectManager!.onRotationEnd = onRotationEnded;
this.arObjectManager!.onNodeTap = onNodeTap;
}
Future<void> onTakeScreenshot() async {
var image = await arSessionManager!.snapshot();
await showDialog(
context: contextArView,
builder: (_) => Dialog(
child: Container(
height: MediaQuery.of(contextArView).size.height - 200,
decoration: BoxDecoration(
image: DecorationImage(image: image, fit: BoxFit.cover),
),
),
),
);
await ImageGallerySaver.saveImage((image as MemoryImage).bytes);
debugPrint('Image saved to gallery!');
}
Future<void> onPlaneOrPointTapped(List<ARHitTestResult> hitTestResults) async {
var singleHitTestResult = hitTestResults.firstWhere(
(hitTestResult) => hitTestResult.type == ARHitTestResultType.plane);
if (singleHitTestResult != null) {
var newAnchor = ARPlaneAnchor(transformation:
singleHitTestResult.worldTransform);
bool? didAddAnchor = await arAnchorManager!.addAnchor(newAnchor);
if (didAddAnchor!) {
anchors.add(newAnchor);
var newNode = ARNode(
type: NodeType.fileSystemAppFolderGLB,
uri: "$objectTitle.glb",
scale: Vector3(
initialObjectScale, initialObjectScale, initialObjectScale),
position: Vector3(0.0, 0.0, 0.0),
rotation: Vector4(1.0, 0.0, 0.0, 0.0));
bool? didAddNodeToAnchor =
await arObjectManager!.addNode(newNode, planeAnchor: newAnchor);
if (didAddNodeToAnchor!) {
nodes.add(newNode);
nodeTitles[newNode.name] = objectTitle!; // Associer le node à son titre
} else {
arSessionManager!.onError("Adding Node to Anchor failed");
}
} else {
arSessionManager!.onError("Adding Anchor failed");
}
}
notifyListeners();
}
void onNodeTap(List<String> nodes) {
selectedNodeName = nodes.first;
selectedObjectName = nodeTitles[selectedNodeName]; // Utiliser objectTitle
debugPrint('$selectedObjectName');
notifyListeners();
}
void onPanStarted(String nodeName) {
debugPrint("Started panning node $nodeName");
}
void onPanChanged(String nodeName) {
debugPrint("Continued panning node $nodeName");
}
void onPanEnded(String nodeName, Matrix4 newTransform) {
debugPrint("Ended panning node $nodeName");
}
void onRotationStarted(String nodeName) {
debugPrint("Started rotating node $nodeName");
}
void onRotationChanged(String nodeName) {
debugPrint("Continued rotating node $nodeName");
}
void onRotationEnded(String nodeName, Matrix4 newTransform) {
debugPrint("Ended rotating node $nodeName");
}
Future<Map<String, dynamic>> handleARPlacement(ARParams params) async {
// Effectuer les opérations lourdes ici si nécessaire
var newAnchor = ARPlaneAnchor(transformation:
params.hitTestResult.worldTransform);
return {
'anchor': newAnchor,
};
}
}
class ARParams {
final ARHitTestResult hitTestResult;
final String objectTitle;
final double initialObjectScale;
ARParams(this.hitTestResult, this.objectTitle, this.initialObjectScale);
}