From 7542d652789786591e623c4a89af82a0af39e9e4 Mon Sep 17 00:00:00 2001 From: Abanoub Zaki Date: Sat, 26 Oct 2024 17:58:46 +0300 Subject: [PATCH] Removed firebase services --- example/ios/Runner.xcodeproj/project.pbxproj | 74 +-- example/lib/examples/cloudanchorexample.dart | 485 -------------- .../externalmodelmanagementexample.dart | 627 ------------------ .../lib/examples/objectgesturesexample.dart | 68 +- .../lib/examples/objectsonplanesexample.dart | 82 ++- example/lib/examples/screenshotexample.dart | 68 +- example/lib/main.dart | 14 - example/pubspec.yaml | 9 +- lib/managers/ar_anchor_manager.dart | 1 - test/ar_flutter_plugin_test.dart | 23 - 10 files changed, 146 insertions(+), 1305 deletions(-) delete mode 100644 example/lib/examples/cloudanchorexample.dart delete mode 100644 example/lib/examples/externalmodelmanagementexample.dart delete mode 100644 test/ar_flutter_plugin_test.dart diff --git a/example/ios/Runner.xcodeproj/project.pbxproj b/example/ios/Runner.xcodeproj/project.pbxproj index 11a7fafa..cdbc4b6c 100644 --- a/example/ios/Runner.xcodeproj/project.pbxproj +++ b/example/ios/Runner.xcodeproj/project.pbxproj @@ -8,6 +8,7 @@ /* Begin PBXBuildFile section */ 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; + 38207A0DBD1CA49BA35F3629 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 652CBA2BB2FB4DCB866FA041 /* Pods_Runner.framework */; }; 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; @@ -15,7 +16,6 @@ 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; EF5AB5D5261C9BD900A60388 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = EF5AB5D4261C9BD900A60388 /* GoogleService-Info.plist */; }; EF5AB736261F5EA600A60388 /* cloudAnchorKey.json in Resources */ = {isa = PBXBuildFile; fileRef = EF5AB735261F5EA600A60388 /* cloudAnchorKey.json */; }; - FC3B1579A1F9BBE343269DEF /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3A1F47AAC378FB2E799B13D8 /* Pods_Runner.framework */; }; /* End PBXBuildFile section */ /* Begin PBXCopyFilesBuildPhase section */ @@ -32,11 +32,11 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ - 0181363DB89EBAFA9858B1A3 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; - 3A1F47AAC378FB2E799B13D8 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 2D4FA9D1F43676E34C407E02 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; + 652CBA2BB2FB4DCB866FA041 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; @@ -47,12 +47,12 @@ 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - D424E5FE727DFB8DCB6BF1D8 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; + A5CE3060566A58B321AC1B5F /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; + E035B9115D71137E4A068CDD /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; EF5AB5D4261C9BD900A60388 /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = ""; }; EF5AB5D6261DA4D800A60388 /* ARCoreCloudAnchors.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ARCoreCloudAnchors.framework; path = Pods/ARCore/CloudAnchors/Frameworks/ARCoreCloudAnchors.framework; sourceTree = ""; }; EF5AB5D8261DA54800A60388 /* ARCore */ = {isa = PBXFileReference; lastKnownFileType = folder; name = ARCore; path = Pods/ARCore; sourceTree = ""; }; EF5AB735261F5EA600A60388 /* cloudAnchorKey.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = cloudAnchorKey.json; sourceTree = ""; }; - F6A0B71292B6059CA94A3F18 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -60,7 +60,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - FC3B1579A1F9BBE343269DEF /* Pods_Runner.framework in Frameworks */, + 38207A0DBD1CA49BA35F3629 /* Pods_Runner.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -72,7 +72,7 @@ children = ( EF5AB5D8261DA54800A60388 /* ARCore */, EF5AB5D6261DA4D800A60388 /* ARCoreCloudAnchors.framework */, - 3A1F47AAC378FB2E799B13D8 /* Pods_Runner.framework */, + 652CBA2BB2FB4DCB866FA041 /* Pods_Runner.framework */, ); name = Frameworks; sourceTree = ""; @@ -127,9 +127,9 @@ 9B7184BFA5C5D8AB5FFB1988 /* Pods */ = { isa = PBXGroup; children = ( - D424E5FE727DFB8DCB6BF1D8 /* Pods-Runner.debug.xcconfig */, - F6A0B71292B6059CA94A3F18 /* Pods-Runner.release.xcconfig */, - 0181363DB89EBAFA9858B1A3 /* Pods-Runner.profile.xcconfig */, + 2D4FA9D1F43676E34C407E02 /* Pods-Runner.debug.xcconfig */, + A5CE3060566A58B321AC1B5F /* Pods-Runner.release.xcconfig */, + E035B9115D71137E4A068CDD /* Pods-Runner.profile.xcconfig */, ); path = Pods; sourceTree = ""; @@ -141,15 +141,15 @@ isa = PBXNativeTarget; buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; buildPhases = ( - B6180CDA50A54DB55045479E /* [CP] Check Pods Manifest.lock */, + 77BF7340D408085286B39364 /* [CP] Check Pods Manifest.lock */, 9740EEB61CF901F6004384FC /* Run Script */, 97C146EA1CF9000F007C117D /* Sources */, 97C146EB1CF9000F007C117D /* Frameworks */, 97C146EC1CF9000F007C117D /* Resources */, 9705A1C41CF9048500538489 /* Embed Frameworks */, 3B06AD1E1E4923F5004D2608 /* Thin Binary */, - 94B0826727C2A055D78A9B66 /* [CP] Embed Pods Frameworks */, - C226EEF590F236CBFE1746B9 /* [CP] Copy Pods Resources */, + 6D0A0D5FAE131291D7A9E5AD /* [CP] Embed Pods Frameworks */, + 080AF987EEAEC1C0E0F91A4A /* [CP] Copy Pods Resources */, ); buildRules = ( ); @@ -210,6 +210,23 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ + 080AF987EEAEC1C0E0F91A4A /* [CP] Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Copy Pods Resources"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; @@ -224,7 +241,7 @@ shellPath = /bin/sh; shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; }; - 94B0826727C2A055D78A9B66 /* [CP] Embed Pods Frameworks */ = { + 6D0A0D5FAE131291D7A9E5AD /* [CP] Embed Pods Frameworks */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( @@ -241,21 +258,7 @@ shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; showEnvVarsInLog = 0; }; - 9740EEB61CF901F6004384FC /* Run Script */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - name = "Run Script"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; - }; - B6180CDA50A54DB55045479E /* [CP] Check Pods Manifest.lock */ = { + 77BF7340D408085286B39364 /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( @@ -277,22 +280,19 @@ shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; showEnvVarsInLog = 0; }; - C226EEF590F236CBFE1746B9 /* [CP] Copy Pods Resources */ = { + 9740EEB61CF901F6004384FC /* Run Script */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); - inputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-input-files.xcfilelist", + inputPaths = ( ); - name = "[CP] Copy Pods Resources"; - outputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-output-files.xcfilelist", + name = "Run Script"; + outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n"; - showEnvVarsInLog = 0; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; }; /* End PBXShellScriptBuildPhase section */ diff --git a/example/lib/examples/cloudanchorexample.dart b/example/lib/examples/cloudanchorexample.dart deleted file mode 100644 index f90032df..00000000 --- a/example/lib/examples/cloudanchorexample.dart +++ /dev/null @@ -1,485 +0,0 @@ -import 'dart:convert'; - -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:flutter/material.dart'; -import 'package:ar_flutter_plugin/ar_flutter_plugin.dart'; -import 'package:ar_flutter_plugin/datatypes/config_planedetection.dart'; -import 'package:ar_flutter_plugin/datatypes/node_types.dart'; -import 'package:ar_flutter_plugin/datatypes/hittest_result_types.dart'; -import 'package:ar_flutter_plugin/models/ar_node.dart'; -import 'package:ar_flutter_plugin/models/ar_hittest_result.dart'; -import 'package:vector_math/vector_math_64.dart'; -import 'package:firebase_core/firebase_core.dart'; -import 'package:cloud_firestore/cloud_firestore.dart'; -import 'package:geoflutterfire/geoflutterfire.dart'; -import 'package:geolocator/geolocator.dart'; - -class CloudAnchorWidget extends StatefulWidget { - CloudAnchorWidget({Key? key}) : super(key: key); - @override - _CloudAnchorWidgetState createState() => _CloudAnchorWidgetState(); -} - -class _CloudAnchorWidgetState extends State { - // Firebase stuff - bool _initialized = false; - bool _error = false; - FirebaseManager firebaseManager = FirebaseManager(); - Map anchorsInDownloadProgress = Map(); - - ARSessionManager? arSessionManager; - ARObjectManager? arObjectManager; - ARAnchorManager? arAnchorManager; - ARLocationManager? arLocationManager; - - List nodes = []; - List anchors = []; - String lastUploadedAnchor = ""; - - bool readyToUpload = false; - bool readyToDownload = true; - - @override - void initState() { - firebaseManager.initializeFlutterFire().then((value) => setState(() { - _initialized = value; - _error = !value; - })); - - super.initState(); - } - - @override - void dispose() { - super.dispose(); - arSessionManager!.dispose(); - } - - @override - Widget build(BuildContext context) { - // Show error message if initialization failed - if (_error) { - return Scaffold( - appBar: AppBar( - title: const Text('Cloud Anchors'), - ), - body: Container( - child: Center( - child: Column( - children: [ - Text("Firebase initialization failed"), - ElevatedButton( - child: Text("Retry"), onPressed: () => {initState()}) - ], - )))); - } - - // Show a loader until FlutterFire is initialized - if (!_initialized) { - return Scaffold( - appBar: AppBar( - title: const Text('Cloud Anchors'), - ), - body: Container( - child: Center( - child: Column(children: [ - CircularProgressIndicator(), - Text("Initializing Firebase") - ])))); - } - - return Scaffold( - appBar: AppBar( - title: const Text('Cloud Anchors'), - ), - body: Container( - child: Stack(children: [ - ARView( - onARViewCreated: onARViewCreated, - planeDetectionConfig: PlaneDetectionConfig.horizontalAndVertical, - ), - Align( - alignment: FractionalOffset.bottomCenter, - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - ElevatedButton( - onPressed: onRemoveEverything, - child: Text("Remove Everything")), - ]), - ), - Align( - alignment: FractionalOffset.topCenter, - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - Visibility( - visible: readyToUpload, - child: ElevatedButton( - onPressed: onUploadButtonPressed, - child: Text("Upload"))), - Visibility( - visible: readyToDownload, - child: ElevatedButton( - onPressed: onDownloadButtonPressed, - child: Text("Download"))), - ]), - ) - ]))); - } - - void onARViewCreated( - ARSessionManager arSessionManager, - ARObjectManager arObjectManager, - ARAnchorManager arAnchorManager, - ARLocationManager arLocationManager) { - this.arSessionManager = arSessionManager; - this.arObjectManager = arObjectManager; - this.arAnchorManager = arAnchorManager; - this.arLocationManager = arLocationManager; - - this.arSessionManager!.onInitialize( - showFeaturePoints: false, - showPlanes: true, - customPlaneTexturePath: "Images/triangle.png", - showWorldOrigin: true, - ); - this.arObjectManager!.onInitialize(); - this.arAnchorManager!.initGoogleCloudAnchorMode(); - - this.arSessionManager!.onPlaneOrPointTap = onPlaneOrPointTapped; - this.arObjectManager!.onNodeTap = onNodeTapped; - this.arAnchorManager!.onAnchorUploaded = onAnchorUploaded; - this.arAnchorManager!.onAnchorDownloaded = onAnchorDownloaded; - - this - .arLocationManager - !.startLocationUpdates() - .then((value) => null) - .onError((error, stackTrace) { - switch (error.toString()) { - case 'Location services disabled': - { - showAlertDialog( - context, - "Action Required", - "To use cloud anchor functionality, please enable your location services", - "Settings", - this.arLocationManager!.openLocationServicesSettings, - "Cancel"); - break; - } - - case 'Location permissions denied': - { - showAlertDialog( - context, - "Action Required", - "To use cloud anchor functionality, please allow the app to access your device's location", - "Retry", - this.arLocationManager!.startLocationUpdates, - "Cancel"); - break; - } - - case 'Location permissions permanently denied': - { - showAlertDialog( - context, - "Action Required", - "To use cloud anchor functionality, please allow the app to access your device's location", - "Settings", - this.arLocationManager!.openAppPermissionSettings, - "Cancel"); - break; - } - - default: - { - this.arSessionManager!.onError(error.toString()); - break; - } - } - this.arSessionManager!.onError(error.toString()); - }); - } - - Future onRemoveEverything() async { - anchors.forEach((anchor) { - this.arAnchorManager!.removeAnchor(anchor); - }); - anchors = []; - if (lastUploadedAnchor != "") { - setState(() { - readyToDownload = true; - readyToUpload = false; - }); - } else { - setState(() { - readyToDownload = true; - readyToUpload = false; - }); - } - } - - Future onNodeTapped(List nodeNames) async { - var foregroundNode = - nodes.firstWhere((element) => element.name == nodeNames.first); - this.arSessionManager!.onError(foregroundNode.data!["onTapText"]); - } - - Future onPlaneOrPointTapped( - List hitTestResults) async { - var singleHitTestResult = hitTestResults.firstWhere( - (hitTestResult) => hitTestResult.type == ARHitTestResultType.plane); - if (singleHitTestResult != null) { - var newAnchor = ARPlaneAnchor( - transformation: singleHitTestResult.worldTransform, ttl: 2); - bool? didAddAnchor = await this.arAnchorManager!.addAnchor(newAnchor); - if (didAddAnchor ?? false) { - this.anchors.add(newAnchor); - // Add note to anchor - var newNode = ARNode( - type: NodeType.webGLB, - uri: "https://github.com/KhronosGroup/glTF-Sample-Models/raw/master/2.0/Duck/glTF-Binary/Duck.glb", - scale: Vector3(0.2, 0.2, 0.2), - position: Vector3(0.0, 0.0, 0.0), - rotation: Vector4(1.0, 0.0, 0.0, 0.0), - data: {"onTapText": "Ouch, that hurt!"}); - bool? didAddNodeToAnchor = - await this.arObjectManager!.addNode(newNode, planeAnchor: newAnchor); - if (didAddNodeToAnchor ?? false) { - this.nodes.add(newNode); - setState(() { - readyToUpload = true; - }); - } else { - this.arSessionManager!.onError("Adding Node to Anchor failed"); - } - } else { - this.arSessionManager!.onError("Adding Anchor failed"); - } - } - } - - Future onUploadButtonPressed() async { - this.arAnchorManager!.uploadAnchor(this.anchors.last); - setState(() { - readyToUpload = false; - }); - } - - onAnchorUploaded(ARAnchor anchor) { - // Upload anchor information to firebase - firebaseManager.uploadAnchor(anchor, - currentLocation: this.arLocationManager!.currentLocation); - // Upload child nodes to firebase - if (anchor is ARPlaneAnchor) { - anchor.childNodes.forEach((nodeName) => firebaseManager.uploadObject( - nodes.firstWhere((element) => element.name == nodeName))); - } - setState(() { - readyToDownload = true; - readyToUpload = false; - }); - this.arSessionManager!.onError("Upload successful"); - } - - ARAnchor onAnchorDownloaded(MapserializedAnchor) { - final anchor = ARPlaneAnchor.fromJson(anchorsInDownloadProgress[serializedAnchor["cloudanchorid"]] as Map); - anchorsInDownloadProgress.remove(anchor.cloudanchorid); - this.anchors.add(anchor); - - // Download nodes attached to this anchor - firebaseManager.getObjectsFromAnchor(anchor, (snapshot) { - snapshot.docs.forEach((objectDoc) { - ARNode object = ARNode.fromMap(objectDoc.data() as Map); - arObjectManager!.addNode(object, planeAnchor: anchor); - this.nodes.add(object); - }); - }); - - return anchor; - } - - Future onDownloadButtonPressed() async { - //this.arAnchorManager.downloadAnchor(lastUploadedAnchor); - //firebaseManager.downloadLatestAnchor((snapshot) { - // final cloudAnchorId = snapshot.docs.first.get("cloudanchorid"); - // anchorsInDownloadProgress[cloudAnchorId] = snapshot.docs.first.data(); - // arAnchorManager.downloadAnchor(cloudAnchorId); - //}); - - // Get anchors within a radius of 100m of the current device's location - if (this.arLocationManager!.currentLocation != null) { - firebaseManager.downloadAnchorsByLocation((snapshot) { - final cloudAnchorId = snapshot.get("cloudanchorid"); - anchorsInDownloadProgress[cloudAnchorId] = snapshot.data() as Map; - arAnchorManager!.downloadAnchor(cloudAnchorId); - }, this.arLocationManager!.currentLocation, 0.1); - setState(() { - readyToDownload = false; - }); - } else { - this - .arSessionManager! - .onError("Location updates not running, can't download anchors"); - } - } - - void showAlertDialog(BuildContext context, String title, String content, - String buttonText, Function buttonFunction, String cancelButtonText) { - // set up the buttons - Widget cancelButton = ElevatedButton( - child: Text(cancelButtonText), - onPressed: () { - Navigator.of(context).pop(); - }, - ); - Widget actionButton = ElevatedButton( - child: Text(buttonText), - onPressed: () { - buttonFunction(); - Navigator.of(context).pop(); - }, - ); - - // set up the AlertDialog - AlertDialog alert = AlertDialog( - title: Text(title), - content: Text(content), - actions: [ - cancelButton, - actionButton, - ], - ); - - // show the dialog - showDialog( - context: context, - builder: (BuildContext context) { - return alert; - }, - ); - } -} - -// Class for managing interaction with Firebase (in your own app, this can be put in a separate file to keep everything clean and tidy) -typedef FirebaseListener = void Function(QuerySnapshot snapshot); -typedef FirebaseDocumentStreamListener = void Function( - DocumentSnapshot snapshot); - -class FirebaseManager { - FirebaseFirestore? firestore; - Geoflutterfire? geo; - CollectionReference? anchorCollection; - CollectionReference? objectCollection; - - // Firebase initialization function - Future initializeFlutterFire() async { - try { - // Wait for Firebase to initialize - await Firebase.initializeApp(); - geo = Geoflutterfire(); - firestore = FirebaseFirestore.instance; - anchorCollection = FirebaseFirestore.instance.collection('anchors'); - objectCollection = FirebaseFirestore.instance.collection('objects'); - return true; - } catch (e) { - return false; - } - } - - void uploadAnchor(ARAnchor anchor, {Position? currentLocation}) { - if (firestore == null) return; - - var serializedAnchor = anchor.toJson(); - var expirationTime = DateTime.now().millisecondsSinceEpoch / 1000 + - serializedAnchor["ttl"] * 24 * 60 * 60; - serializedAnchor["expirationTime"] = expirationTime; - // Add location - if (currentLocation != null) { - GeoFirePoint myLocation = geo!.point( - latitude: currentLocation.latitude, - longitude: currentLocation.longitude); - serializedAnchor["position"] = myLocation.data; - } - - anchorCollection! - .add(serializedAnchor) - .then((value) => - print("Successfully added anchor: " + serializedAnchor["name"])) - .catchError((error) => print("Failed to add anchor: $error")); - } - - void uploadObject(ARNode node) { - if (firestore == null) return; - - var serializedNode = node.toMap(); - - objectCollection! - .add(serializedNode) - .then((value) => - print("Successfully added object: " + serializedNode["name"])) - .catchError((error) => print("Failed to add object: $error")); - } - - void downloadLatestAnchor(FirebaseListener listener) { - anchorCollection! - .orderBy("expirationTime", descending: false) - .limitToLast(1) - .get() - .then((value) => listener(value)) - .catchError( - (error) => (error) => print("Failed to download anchor: $error")); - } - - void downloadAnchorsByLocation(FirebaseDocumentStreamListener listener, - Position location, double radius) { - GeoFirePoint center = - geo!.point(latitude: location.latitude, longitude: location.longitude); - - Stream> stream = geo! - .collection(collectionRef: anchorCollection!) - .within(center: center, radius: radius, field: 'position'); - - stream.listen((List documentList) { - documentList.forEach((element) { - listener(element); - }); - }); - } - - void downloadAnchorsByChannel() {} - - void getObjectsFromAnchor(ARPlaneAnchor anchor, FirebaseListener listener) { - objectCollection! - .where("name", whereIn: anchor.childNodes) - .get() - .then((value) => listener(value)) - .catchError((error) => print("Failed to download objects: $error")); - } - - void deleteExpiredDatabaseEntries() { - WriteBatch batch = FirebaseFirestore.instance.batch(); - anchorCollection! - .where("expirationTime", - isLessThan: DateTime.now().millisecondsSinceEpoch / 1000) - .get() - .then((anchorSnapshot) => anchorSnapshot.docs.forEach((anchorDoc) { - // Delete all objects attached to the expired anchor - objectCollection! - .where("name", arrayContainsAny: anchorDoc.get("childNodes")) - .get() - .then((objectSnapshot) => objectSnapshot.docs.forEach( - (objectDoc) => batch.delete(objectDoc.reference))); - // Delete the expired anchor - batch.delete(anchorDoc.reference); - })); - batch.commit(); - } -} diff --git a/example/lib/examples/externalmodelmanagementexample.dart b/example/lib/examples/externalmodelmanagementexample.dart deleted file mode 100644 index 85e8cbe0..00000000 --- a/example/lib/examples/externalmodelmanagementexample.dart +++ /dev/null @@ -1,627 +0,0 @@ -import 'dart:convert'; - -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:flutter/material.dart'; -import 'package:ar_flutter_plugin/ar_flutter_plugin.dart'; -import 'package:ar_flutter_plugin/datatypes/config_planedetection.dart'; -import 'package:ar_flutter_plugin/datatypes/node_types.dart'; -import 'package:ar_flutter_plugin/datatypes/hittest_result_types.dart'; -import 'package:ar_flutter_plugin/models/ar_node.dart'; -import 'package:ar_flutter_plugin/models/ar_hittest_result.dart'; -import 'package:vector_math/vector_math_64.dart' as VectorMath; -import 'package:firebase_core/firebase_core.dart'; -import 'package:cloud_firestore/cloud_firestore.dart'; -import 'package:geoflutterfire/geoflutterfire.dart'; -import 'package:geolocator/geolocator.dart'; - -class ExternalModelManagementWidget extends StatefulWidget { - ExternalModelManagementWidget({Key? key}) : super(key: key); - @override - _ExternalModelManagementWidgetState createState() => - _ExternalModelManagementWidgetState(); -} - -class _ExternalModelManagementWidgetState - extends State { - // Firebase stuff - bool _initialized = false; - bool _error = false; - FirebaseManager firebaseManager = FirebaseManager(); - Map anchorsInDownloadProgress = Map(); - - ARSessionManager? arSessionManager; - ARObjectManager? arObjectManager; - ARAnchorManager? arAnchorManager; - ARLocationManager? arLocationManager; - - List nodes = []; - List anchors = []; - String lastUploadedAnchor = ""; - AvailableModel selectedModel = AvailableModel( - "Duck", - "https://github.com/KhronosGroup/glTF-Sample-Models/raw/master/2.0/Duck/glTF-Binary/Duck.glb", - ""); - - bool readyToUpload = false; - bool readyToDownload = true; - bool modelChoiceActive = false; - - @override - void initState() { - firebaseManager.initializeFlutterFire().then((value) => setState(() { - _initialized = value; - _error = !value; - })); - - super.initState(); - } - - @override - void dispose() { - super.dispose(); - arSessionManager!.dispose(); - } - - @override - Widget build(BuildContext context) { - // Show error message if initialization failed - if (_error) { - return Scaffold( - appBar: AppBar( - title: const Text('External Model Management'), - ), - body: Container( - child: Center( - child: Column( - children: [ - Text("Firebase initialization failed"), - ElevatedButton( - child: Text("Retry"), onPressed: () => {initState()}) - ], - )))); - } - - // Show a loader until FlutterFire is initialized - if (!_initialized) { - return Scaffold( - appBar: AppBar( - title: const Text('External Model Management'), - ), - body: Container( - child: Center( - child: Column(children: [ - CircularProgressIndicator(), - Text("Initializing Firebase") - ])))); - } - - return Scaffold( - appBar: AppBar( - title: const Text('External Model Management'), - actions: [ - IconButton( - icon: Icon(Icons.pets), - onPressed: () { - setState(() { - modelChoiceActive = !modelChoiceActive; - }); - }, - ), - ]), - body: Container( - child: Stack(children: [ - ARView( - onARViewCreated: onARViewCreated, - planeDetectionConfig: PlaneDetectionConfig.horizontalAndVertical, - ), - Align( - alignment: FractionalOffset.bottomCenter, - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - ElevatedButton( - onPressed: onRemoveEverything, - child: Text("Remove Everything")), - ]), - ), - Align( - alignment: FractionalOffset.topCenter, - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - Visibility( - visible: readyToUpload, - child: ElevatedButton( - onPressed: onUploadButtonPressed, - child: Text("Upload"))), - Visibility( - visible: readyToDownload, - child: ElevatedButton( - onPressed: onDownloadButtonPressed, - child: Text("Download"))), - ]), - ), - Align( - alignment: FractionalOffset.centerLeft, - child: Visibility( - visible: modelChoiceActive, - child: ModelSelectionWidget( - onTap: onModelSelected, - firebaseManager: this.firebaseManager))) - ]))); - } - - void onARViewCreated( - ARSessionManager arSessionManager, - ARObjectManager arObjectManager, - ARAnchorManager arAnchorManager, - ARLocationManager arLocationManager) { - this.arSessionManager = arSessionManager; - this.arObjectManager = arObjectManager; - this.arAnchorManager = arAnchorManager; - this.arLocationManager = arLocationManager; - - this.arSessionManager!.onInitialize( - showFeaturePoints: false, - showPlanes: true, - customPlaneTexturePath: "Images/triangle.png", - showWorldOrigin: true, - ); - this.arObjectManager!.onInitialize(); - this.arAnchorManager!.initGoogleCloudAnchorMode(); - - this.arSessionManager!.onPlaneOrPointTap = onPlaneOrPointTapped; - this.arObjectManager!.onNodeTap = onNodeTapped; - this.arAnchorManager!.onAnchorUploaded = onAnchorUploaded; - this.arAnchorManager!.onAnchorDownloaded = onAnchorDownloaded; - - this - .arLocationManager! - .startLocationUpdates() - .then((value) => null) - .onError((error, stackTrace) { - switch (error.toString()) { - case 'Location services disabled': - { - showAlertDialog( - context, - "Action Required", - "To use cloud anchor functionality, please enable your location services", - "Settings", - this.arLocationManager!.openLocationServicesSettings, - "Cancel"); - break; - } - - case 'Location permissions denied': - { - showAlertDialog( - context, - "Action Required", - "To use cloud anchor functionality, please allow the app to access your device's location", - "Retry", - this.arLocationManager!.startLocationUpdates, - "Cancel"); - break; - } - - case 'Location permissions permanently denied': - { - showAlertDialog( - context, - "Action Required", - "To use cloud anchor functionality, please allow the app to access your device's location", - "Settings", - this.arLocationManager!.openAppPermissionSettings, - "Cancel"); - break; - } - - default: - { - this.arSessionManager!.onError(error.toString()); - break; - } - } - this.arSessionManager!.onError(error.toString()); - }); - } - - void onModelSelected(AvailableModel model) { - this.selectedModel = model; - this.arSessionManager!.onError(model.name + " selected"); - setState(() { - modelChoiceActive = false; - }); - } - - Future onRemoveEverything() async { - anchors.forEach((anchor) { - this.arAnchorManager!.removeAnchor(anchor); - }); - anchors = []; - if (lastUploadedAnchor != "") { - setState(() { - readyToDownload = true; - readyToUpload = false; - }); - } else { - setState(() { - readyToDownload = true; - readyToUpload = false; - }); - } - } - - Future onNodeTapped(List nodeNames) async { - var foregroundNode = nodes.firstWhere((element) => element.name == nodeNames.first); - this.arSessionManager!.onError(foregroundNode.data!["onTapText"]); - } - - Future onPlaneOrPointTapped( - List hitTestResults) async { - var singleHitTestResult = hitTestResults.firstWhere( - (hitTestResult) => hitTestResult.type == ARHitTestResultType.plane); - if (singleHitTestResult != null) { - var newAnchor = ARPlaneAnchor( - transformation: singleHitTestResult.worldTransform, ttl: 2); - bool? didAddAnchor = await this.arAnchorManager!.addAnchor(newAnchor); - if (didAddAnchor!) { - this.anchors.add(newAnchor); - // Add note to anchor - var newNode = ARNode( - type: NodeType.webGLB, - uri: this.selectedModel.uri, - scale: VectorMath.Vector3(0.2, 0.2, 0.2), - position: VectorMath.Vector3(0.0, 0.0, 0.0), - rotation: VectorMath.Vector4(1.0, 0.0, 0.0, 0.0), - data: {"onTapText": "I am a " + this.selectedModel.name}); - bool? didAddNodeToAnchor = - await this.arObjectManager!.addNode(newNode, planeAnchor: newAnchor); - if (didAddNodeToAnchor!) { - this.nodes.add(newNode); - setState(() { - readyToUpload = true; - }); - } else { - this.arSessionManager!.onError("Adding Node to Anchor failed"); - } - } else { - this.arSessionManager!.onError("Adding Anchor failed"); - } - } - } - - Future onUploadButtonPressed() async { - this.arAnchorManager!.uploadAnchor(this.anchors.last); - setState(() { - readyToUpload = false; - }); - } - - onAnchorUploaded(ARAnchor anchor) { - // Upload anchor information to firebase - firebaseManager.uploadAnchor(anchor, - currentLocation: this.arLocationManager!.currentLocation); - // Upload child nodes to firebase - if (anchor is ARPlaneAnchor) { - anchor.childNodes.forEach((nodeName) => firebaseManager.uploadObject( - nodes.firstWhere((element) => element.name == nodeName))); - } - setState(() { - readyToDownload = true; - readyToUpload = false; - }); - this.arSessionManager!.onError("Upload successful"); - } - - ARAnchor onAnchorDownloaded(Map serializedAnchor) { - final anchor = ARPlaneAnchor.fromJson(anchorsInDownloadProgress[serializedAnchor["cloudanchorid"]] as Map); - anchorsInDownloadProgress.remove(anchor.cloudanchorid); - this.anchors.add(anchor); - - // Download nodes attached to this anchor - firebaseManager.getObjectsFromAnchor(anchor, (snapshot) { - snapshot.docs.forEach((objectDoc) { - ARNode object = ARNode.fromMap(objectDoc.data() as Map); - arObjectManager!.addNode(object, planeAnchor: anchor); - this.nodes.add(object); - }); - }); - - return anchor; - } - - Future onDownloadButtonPressed() async { - //this.arAnchorManager.downloadAnchor(lastUploadedAnchor); - //firebaseManager.downloadLatestAnchor((snapshot) { - // final cloudAnchorId = snapshot.docs.first.get("cloudanchorid"); - // anchorsInDownloadProgress[cloudAnchorId] = snapshot.docs.first.data(); - // arAnchorManager.downloadAnchor(cloudAnchorId); - //}); - - // Get anchors within a radius of 100m of the current device's location - if (this.arLocationManager!.currentLocation != null) { - firebaseManager.downloadAnchorsByLocation((snapshot) { - final cloudAnchorId = snapshot.get("cloudanchorid"); - anchorsInDownloadProgress[cloudAnchorId] = snapshot.data() as Map; - arAnchorManager!.downloadAnchor(cloudAnchorId); - }, this.arLocationManager!.currentLocation, 0.1); - setState(() { - readyToDownload = false; - }); - } else { - this - .arSessionManager! - .onError("Location updates not running, can't download anchors"); - } - } - - void showAlertDialog(BuildContext context, String title, String content, - String buttonText, Function buttonFunction, String cancelButtonText) { - // set up the buttons - Widget cancelButton = ElevatedButton( - child: Text(cancelButtonText), - onPressed: () { - Navigator.of(context).pop(); - }, - ); - Widget actionButton = ElevatedButton( - child: Text(buttonText), - onPressed: () { - buttonFunction(); - Navigator.of(context).pop(); - }, - ); - - // set up the AlertDialog - AlertDialog alert = AlertDialog( - title: Text(title), - content: Text(content), - actions: [ - cancelButton, - actionButton, - ], - ); - - // show the dialog - showDialog( - context: context, - builder: (BuildContext context) { - return alert; - }, - ); - } -} - -// Class for managing interaction with Firebase (in your own app, this can be put in a separate file to keep everything clean and tidy) -typedef FirebaseListener = void Function(QuerySnapshot snapshot); -typedef FirebaseDocumentStreamListener = void Function( - DocumentSnapshot snapshot); - -class FirebaseManager { - FirebaseFirestore? firestore; - Geoflutterfire? geo; - CollectionReference? anchorCollection; - CollectionReference? objectCollection; - CollectionReference? modelCollection; - - // Firebase initialization function - Future initializeFlutterFire() async { - try { - // Wait for Firebase to initialize - await Firebase.initializeApp(); - geo = Geoflutterfire(); - firestore = FirebaseFirestore.instance; - anchorCollection = FirebaseFirestore.instance.collection('anchors'); - objectCollection = FirebaseFirestore.instance.collection('objects'); - modelCollection = FirebaseFirestore.instance.collection('models'); - return true; - } catch (e) { - return false; - } - } - - void uploadAnchor(ARAnchor anchor, {Position? currentLocation}) { - if (firestore == null) return; - - var serializedAnchor = anchor.toJson(); - var expirationTime = DateTime.now().millisecondsSinceEpoch / 1000 + - serializedAnchor["ttl"] * 24 * 60 * 60; - serializedAnchor["expirationTime"] = expirationTime; - // Add location - if (currentLocation != null) { - GeoFirePoint myLocation = geo!.point( - latitude: currentLocation.latitude, - longitude: currentLocation.longitude); - serializedAnchor["position"] = myLocation.data; - } - - anchorCollection! - .add(serializedAnchor) - .then((value) => - print("Successfully added anchor: " + serializedAnchor["name"])) - .catchError((error) => print("Failed to add anchor: $error")); - } - - void uploadObject(ARNode node) { - if (firestore == null) return; - - var serializedNode = node.toMap(); - - objectCollection! - .add(serializedNode) - .then((value) => - print("Successfully added object: " + serializedNode["name"])) - .catchError((error) => print("Failed to add object: $error")); - } - - void downloadLatestAnchor(FirebaseListener listener) { - anchorCollection! - .orderBy("expirationTime", descending: false) - .limitToLast(1) - .get() - .then((value) => listener(value)) - .catchError( - (error) => (error) => print("Failed to download anchor: $error")); - } - - void downloadAnchorsByLocation(FirebaseDocumentStreamListener listener, - Position location, double radius) { - GeoFirePoint center = - geo!.point(latitude: location.latitude, longitude: location.longitude); - - Stream> stream = geo! - .collection(collectionRef: anchorCollection!) - .within(center: center, radius: radius, field: 'position'); - - stream.listen((List documentList) { - documentList.forEach((element) { - listener(element); - }); - }); - } - - void downloadAnchorsByChannel() {} - - void getObjectsFromAnchor(ARPlaneAnchor anchor, FirebaseListener listener) { - objectCollection! - .where("name", whereIn: anchor.childNodes) - .get() - .then((value) => listener(value)) - .catchError((error) => print("Failed to download objects: $error")); - } - - void deleteExpiredDatabaseEntries() { - WriteBatch batch = FirebaseFirestore.instance.batch(); - anchorCollection! - .where("expirationTime", - isLessThan: DateTime.now().millisecondsSinceEpoch / 1000) - .get() - .then((anchorSnapshot) => anchorSnapshot.docs.forEach((anchorDoc) { - // Delete all objects attached to the expired anchor - objectCollection! - .where("name", arrayContainsAny: anchorDoc.get("childNodes")) - .get() - .then((objectSnapshot) => objectSnapshot.docs.forEach( - (objectDoc) => batch.delete(objectDoc.reference))); - // Delete the expired anchor - batch.delete(anchorDoc.reference); - })); - batch.commit(); - } - - void downloadAvailableModels(FirebaseListener listener) { - modelCollection! - .get() - .then((value) => listener(value)) - .catchError((error) => print("Failed to download objects: $error")); - } -} - -class AvailableModel { - String name; - String uri; - String image; - AvailableModel(this.name, this.uri, this.image); -} - -class ModelSelectionWidget extends StatefulWidget { - final Function onTap; - final FirebaseManager firebaseManager; - - ModelSelectionWidget({required this.onTap, required this.firebaseManager}); - - @override - _ModelSelectionWidgetState createState() => _ModelSelectionWidgetState(); -} - -class _ModelSelectionWidgetState extends State { - List models = []; - - String? selected; - - @override - void initState() { - super.initState(); - widget.firebaseManager.downloadAvailableModels((snapshot) { - snapshot.docs.forEach((element) { - setState(() { - models.add(AvailableModel(element.get("name"), element.get("uri"), - element.get("image").first["downloadURL"])); - }); - }); - }); - } - - @override - Widget build(BuildContext context) { - return Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - DecoratedBox( - decoration: BoxDecoration( - color: Colors.white, - border: Border.all( - color: Colors.white, - style: BorderStyle.solid, - width: 4.0, - ), - borderRadius: BorderRadius.all(Radius.circular(5)), - shape: BoxShape.rectangle, - boxShadow: const [ - BoxShadow( - color: Color(0x66000000), - blurRadius: 10.0, - spreadRadius: 4.0, - ) - ], - ), - child: Text('Choose a Model', - style: DefaultTextStyle.of(context) - .style - .apply(fontSizeFactor: 2.0)), - ), - Container( - height: MediaQuery.of(context).size.width * 0.65, - child: ListView.builder( - itemCount: models.length, - scrollDirection: Axis.horizontal, - itemBuilder: (context, index) { - return GestureDetector( - onTap: () { - widget.onTap(models[index]); - }, - child: Card( - elevation: 4.0, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.all( - Radius.circular(5), - ), - ), - child: Column( - children: [ - Padding( - padding: EdgeInsets.all(20), - child: Image.network(models[index].image)), - Text( - models[index].name, - style: DefaultTextStyle.of(context) - .style - .apply(fontSizeFactor: 2.0), - ) - ], - ), - ), - ); - }, - ), - ) - ]); - } -} diff --git a/example/lib/examples/objectgesturesexample.dart b/example/lib/examples/objectgesturesexample.dart index 6d9f42ae..96408966 100644 --- a/example/lib/examples/objectgesturesexample.dart +++ b/example/lib/examples/objectgesturesexample.dart @@ -1,18 +1,16 @@ -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:flutter/material.dart'; import 'package:ar_flutter_plugin/ar_flutter_plugin.dart'; import 'package:ar_flutter_plugin/datatypes/config_planedetection.dart'; -import 'package:ar_flutter_plugin/datatypes/node_types.dart'; import 'package:ar_flutter_plugin/datatypes/hittest_result_types.dart'; -import 'package:ar_flutter_plugin/models/ar_node.dart'; +import 'package:ar_flutter_plugin/datatypes/node_types.dart'; +import 'package:ar_flutter_plugin/managers/ar_anchor_manager.dart'; +import 'package:ar_flutter_plugin/managers/ar_location_manager.dart'; +import 'package:ar_flutter_plugin/managers/ar_object_manager.dart'; +import 'package:ar_flutter_plugin/managers/ar_session_manager.dart'; +import 'package:ar_flutter_plugin/models/ar_anchor.dart'; import 'package:ar_flutter_plugin/models/ar_hittest_result.dart'; -import 'package:flutter/services.dart'; +import 'package:ar_flutter_plugin/models/ar_node.dart'; +import 'package:flutter/material.dart'; import 'package:vector_math/vector_math_64.dart'; -import 'dart:math'; class ObjectGesturesWidget extends StatefulWidget { ObjectGesturesWidget({Key? key}) : super(key: key); @@ -101,32 +99,30 @@ class _ObjectGesturesWidgetState extends State { List hitTestResults) async { var singleHitTestResult = hitTestResults.firstWhere( (hitTestResult) => hitTestResult.type == ARHitTestResultType.plane); - if (singleHitTestResult != null) { - var newAnchor = - ARPlaneAnchor(transformation: singleHitTestResult.worldTransform); - bool? didAddAnchor = await this.arAnchorManager!.addAnchor(newAnchor); - if (didAddAnchor!) { - this.anchors.add(newAnchor); - // Add note to anchor - var newNode = ARNode( - type: NodeType.webGLB, - uri: - "https://github.com/KhronosGroup/glTF-Sample-Models/raw/master/2.0/Duck/glTF-Binary/Duck.glb", - scale: Vector3(0.2, 0.2, 0.2), - position: Vector3(0.0, 0.0, 0.0), - rotation: Vector4(1.0, 0.0, 0.0, 0.0)); - bool? didAddNodeToAnchor = - await this.arObjectManager!.addNode(newNode, planeAnchor: newAnchor); - if (didAddNodeToAnchor!) { - this.nodes.add(newNode); - } else { - this.arSessionManager!.onError("Adding Node to Anchor failed"); - } + var newAnchor = + ARPlaneAnchor(transformation: singleHitTestResult.worldTransform); + bool? didAddAnchor = await this.arAnchorManager!.addAnchor(newAnchor); + if (didAddAnchor!) { + this.anchors.add(newAnchor); + // Add note to anchor + var newNode = ARNode( + type: NodeType.webGLB, + uri: + "https://github.com/KhronosGroup/glTF-Sample-Models/raw/master/2.0/Duck/glTF-Binary/Duck.glb", + scale: Vector3(0.2, 0.2, 0.2), + position: Vector3(0.0, 0.0, 0.0), + rotation: Vector4(1.0, 0.0, 0.0, 0.0)); + bool? didAddNodeToAnchor = + await this.arObjectManager!.addNode(newNode, planeAnchor: newAnchor); + if (didAddNodeToAnchor!) { + this.nodes.add(newNode); } else { - this.arSessionManager!.onError("Adding Anchor failed"); + this.arSessionManager!.onError("Adding Node to Anchor failed"); } + } else { + this.arSessionManager!.onError("Adding Anchor failed"); + } } - } onPanStarted(String nodeName) { print("Started panning node " + nodeName); @@ -138,8 +134,7 @@ class _ObjectGesturesWidgetState extends State { onPanEnded(String nodeName, Matrix4 newTransform) { print("Ended panning node " + nodeName); - final pannedNode = - this.nodes.firstWhere((element) => element.name == nodeName); + this.nodes.firstWhere((element) => element.name == nodeName); /* * Uncomment the following command if you want to keep the transformations of the Flutter representations of the nodes up to date @@ -158,8 +153,7 @@ class _ObjectGesturesWidgetState extends State { onRotationEnded(String nodeName, Matrix4 newTransform) { print("Ended rotating node " + nodeName); - final rotatedNode = - this.nodes.firstWhere((element) => element.name == nodeName); + this.nodes.firstWhere((element) => element.name == nodeName); /* * Uncomment the following command if you want to keep the transformations of the Flutter representations of the nodes up to date diff --git a/example/lib/examples/objectsonplanesexample.dart b/example/lib/examples/objectsonplanesexample.dart index e23e427d..26df7ee1 100644 --- a/example/lib/examples/objectsonplanesexample.dart +++ b/example/lib/examples/objectsonplanesexample.dart @@ -1,18 +1,16 @@ -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:flutter/material.dart'; import 'package:ar_flutter_plugin/ar_flutter_plugin.dart'; import 'package:ar_flutter_plugin/datatypes/config_planedetection.dart'; -import 'package:ar_flutter_plugin/datatypes/node_types.dart'; import 'package:ar_flutter_plugin/datatypes/hittest_result_types.dart'; -import 'package:ar_flutter_plugin/models/ar_node.dart'; +import 'package:ar_flutter_plugin/datatypes/node_types.dart'; +import 'package:ar_flutter_plugin/managers/ar_anchor_manager.dart'; +import 'package:ar_flutter_plugin/managers/ar_location_manager.dart'; +import 'package:ar_flutter_plugin/managers/ar_object_manager.dart'; +import 'package:ar_flutter_plugin/managers/ar_session_manager.dart'; +import 'package:ar_flutter_plugin/models/ar_anchor.dart'; import 'package:ar_flutter_plugin/models/ar_hittest_result.dart'; -import 'package:flutter/services.dart'; +import 'package:ar_flutter_plugin/models/ar_node.dart'; +import 'package:flutter/material.dart'; import 'package:vector_math/vector_math_64.dart'; -import 'dart:math'; class ObjectsOnPlanesWidget extends StatefulWidget { ObjectsOnPlanesWidget({Key? key}) : super(key: key); @@ -99,41 +97,39 @@ class _ObjectsOnPlanesWidgetState extends State { List hitTestResults) async { var singleHitTestResult = hitTestResults.firstWhere( (hitTestResult) => hitTestResult.type == ARHitTestResultType.plane); - if (singleHitTestResult != null) { - var newAnchor = - ARPlaneAnchor(transformation: singleHitTestResult.worldTransform); - bool? didAddAnchor = await this.arAnchorManager!.addAnchor(newAnchor); - if (didAddAnchor!) { - this.anchors.add(newAnchor); - // Add note to anchor - var newNode = ARNode( - type: NodeType.webGLB, - uri: - "https://github.com/KhronosGroup/glTF-Sample-Models/raw/master/2.0/Duck/glTF-Binary/Duck.glb", - scale: Vector3(0.2, 0.2, 0.2), - position: Vector3(0.0, 0.0, 0.0), - rotation: Vector4(1.0, 0.0, 0.0, 0.0)); - bool? didAddNodeToAnchor = - await this.arObjectManager!.addNode(newNode, planeAnchor: newAnchor); - if (didAddNodeToAnchor!) { - this.nodes.add(newNode); - } else { - this.arSessionManager!.onError("Adding Node to Anchor failed"); - } - } else { - this.arSessionManager!.onError("Adding Anchor failed"); - } - /* - // To add a node to the tapped position without creating an anchor, use the following code (Please mind: the function onRemoveEverything has to be adapted accordingly!): + var newAnchor = + ARPlaneAnchor(transformation: singleHitTestResult.worldTransform); + bool? didAddAnchor = await this.arAnchorManager!.addAnchor(newAnchor); + if (didAddAnchor!) { + this.anchors.add(newAnchor); + // Add note to anchor var newNode = ARNode( - type: NodeType.localGLTF2, - uri: "Models/Chicken_01/Chicken_01.gltf", + type: NodeType.webGLB, + uri: + "https://github.com/KhronosGroup/glTF-Sample-Models/raw/master/2.0/Duck/glTF-Binary/Duck.glb", scale: Vector3(0.2, 0.2, 0.2), - transformation: singleHitTestResult.worldTransform); - bool didAddWebNode = await this.arObjectManager.addNode(newNode); - if (didAddWebNode) { + position: Vector3(0.0, 0.0, 0.0), + rotation: Vector4(1.0, 0.0, 0.0, 0.0)); + bool? didAddNodeToAnchor = + await this.arObjectManager!.addNode(newNode, planeAnchor: newAnchor); + if (didAddNodeToAnchor!) { this.nodes.add(newNode); - }*/ + } else { + this.arSessionManager!.onError("Adding Node to Anchor failed"); + } + } else { + this.arSessionManager!.onError("Adding Anchor failed"); + } + /* + // To add a node to the tapped position without creating an anchor, use the following code (Please mind: the function onRemoveEverything has to be adapted accordingly!): + var newNode = ARNode( + type: NodeType.localGLTF2, + uri: "Models/Chicken_01/Chicken_01.gltf", + scale: Vector3(0.2, 0.2, 0.2), + transformation: singleHitTestResult.worldTransform); + bool didAddWebNode = await this.arObjectManager.addNode(newNode); + if (didAddWebNode) { + this.nodes.add(newNode); + }*/ } - } } diff --git a/example/lib/examples/screenshotexample.dart b/example/lib/examples/screenshotexample.dart index dd3cfb5a..91b220c3 100644 --- a/example/lib/examples/screenshotexample.dart +++ b/example/lib/examples/screenshotexample.dart @@ -116,42 +116,40 @@ class _ScreenshotWidgetState extends State { List 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 != null && didAddAnchor) { - anchors.add(newAnchor); - // Add note to anchor - var newNode = ARNode( - type: NodeType.webGLB, - uri: - "https://github.com/KhronosGroup/glTF-Sample-Models/raw/master/2.0/Duck/glTF-Binary/Duck.glb", - scale: Vector3(0.2, 0.2, 0.2), - 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 != null && didAddNodeToAnchor) { - nodes.add(newNode); - } else { - arSessionManager!.onError("Adding Node to Anchor failed"); - } - } else { - arSessionManager!.onError("Adding Anchor failed"); - } - /* - // To add a node to the tapped position without creating an anchor, use the following code (Please mind: the function onRemoveEverything has to be adapted accordingly!): + var newAnchor = + ARPlaneAnchor(transformation: singleHitTestResult.worldTransform); + bool? didAddAnchor = await arAnchorManager!.addAnchor(newAnchor); + if (didAddAnchor != null && didAddAnchor) { + anchors.add(newAnchor); + // Add note to anchor var newNode = ARNode( - type: NodeType.localGLTF2, - uri: "Models/Chicken_01/Chicken_01.gltf", + type: NodeType.webGLB, + uri: + "https://github.com/KhronosGroup/glTF-Sample-Models/raw/master/2.0/Duck/glTF-Binary/Duck.glb", scale: Vector3(0.2, 0.2, 0.2), - transformation: singleHitTestResult.worldTransform); - bool didAddWebNode = await this.arObjectManager.addNode(newNode); - if (didAddWebNode) { - this.nodes.add(newNode); - }*/ + 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 != null && didAddNodeToAnchor) { + nodes.add(newNode); + } else { + arSessionManager!.onError("Adding Node to Anchor failed"); + } + } else { + arSessionManager!.onError("Adding Anchor failed"); + } + /* + // To add a node to the tapped position without creating an anchor, use the following code (Please mind: the function onRemoveEverything has to be adapted accordingly!): + var newNode = ARNode( + type: NodeType.localGLTF2, + uri: "Models/Chicken_01/Chicken_01.gltf", + scale: Vector3(0.2, 0.2, 0.2), + transformation: singleHitTestResult.worldTransform); + bool didAddWebNode = await this.arObjectManager.addNode(newNode); + if (didAddWebNode) { + this.nodes.add(newNode); + }*/ } - } } \ No newline at end of file diff --git a/example/lib/main.dart b/example/lib/main.dart index ed0fef53..b2890dd7 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -1,4 +1,3 @@ -import 'package:ar_flutter_plugin_example/examples/externalmodelmanagementexample.dart'; import 'package:ar_flutter_plugin_example/examples/objectsonplanesexample.dart'; import 'package:flutter/material.dart'; import 'dart:async'; @@ -6,7 +5,6 @@ import 'dart:async'; import 'package:flutter/services.dart'; import 'package:ar_flutter_plugin/ar_flutter_plugin.dart'; -import 'package:ar_flutter_plugin_example/examples/cloudanchorexample.dart'; import 'package:ar_flutter_plugin_example/examples/localandwebobjectsexample.dart'; import 'package:ar_flutter_plugin_example/examples/debugoptionsexample.dart'; @@ -106,18 +104,6 @@ class ExampleList extends StatelessWidget { 'Place 3D objects on planes and take screenshots', () => Navigator.push(context, MaterialPageRoute(builder: (context) => ScreenshotWidget()))), - Example( - 'Cloud Anchors', - 'Place and retrieve 3D objects using the Google Cloud Anchor API', - () => Navigator.push(context, - MaterialPageRoute(builder: (context) => CloudAnchorWidget()))), - Example( - 'External Model Management', - 'Similar to Cloud Anchors example, but uses external database to choose from available 3D models', - () => Navigator.push( - context, - MaterialPageRoute( - builder: (context) => ExternalModelManagementWidget()))) ]; return ListView( children: diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 77861910..1382f022 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -25,9 +25,9 @@ dependencies: cupertino_icons: ^1.0.2 # Firebase dependencies to shared and manage cloud anchor IDs and related content - firebase_core: "^1.6.0" - cloud_firestore: "^2.5.3" - geoflutterfire: "^3.0.1" + # firebase_core: "^1.6.0" + # cloud_firestore: "^2.5.3" + # geoflutterfire: "^3.0.1" path_provider: ^2.0.3 flutter_archive: ^4.0.1 @@ -35,6 +35,9 @@ dev_dependencies: flutter_test: sdk: flutter +dependency_overrides: + firebase_core_platform_interface: 4.5.1 + # For information on the generic Dart part of this file, see the # following page: https://dart.dev/tools/pub/pubspec diff --git a/lib/managers/ar_anchor_manager.dart b/lib/managers/ar_anchor_manager.dart index 817bc27e..ba574bb4 100644 --- a/lib/managers/ar_anchor_manager.dart +++ b/lib/managers/ar_anchor_manager.dart @@ -1,6 +1,5 @@ import 'package:ar_flutter_plugin/models/ar_anchor.dart'; import 'package:flutter/services.dart'; -import 'package:flutter/material.dart'; // Type definitions to enforce a consistent use of the API typedef AnchorUploadedHandler = void Function(ARAnchor arAnchor); diff --git a/test/ar_flutter_plugin_test.dart b/test/ar_flutter_plugin_test.dart deleted file mode 100644 index 24c3d933..00000000 --- a/test/ar_flutter_plugin_test.dart +++ /dev/null @@ -1,23 +0,0 @@ -import 'package:flutter/services.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:ar_flutter_plugin/ar_flutter_plugin.dart'; - -void main() { - const MethodChannel channel = MethodChannel('ar_flutter_plugin'); - - TestWidgetsFlutterBinding.ensureInitialized(); - - setUp(() { - channel.setMockMethodCallHandler((MethodCall methodCall) async { - return '42'; - }); - }); - - tearDown(() { - channel.setMockMethodCallHandler(null); - }); - - test('getPlatformVersion', () async { - expect(await ArFlutterPlugin.platformVersion, '42'); - }); -}