diff --git a/analysis_options.yaml b/analysis_options.yaml new file mode 100644 index 00000000..61b6c4de --- /dev/null +++ b/analysis_options.yaml @@ -0,0 +1,29 @@ +# This file configures the analyzer, which statically analyzes Dart code to +# check for errors, warnings, and lints. +# +# The issues identified by the analyzer are surfaced in the UI of Dart-enabled +# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be +# invoked from the command line by running `flutter analyze`. + +# The following line activates a set of recommended lints for Flutter apps, +# packages, and plugins designed to encourage good coding practices. +include: package:flutter_lints/flutter.yaml + +linter: + # The lint rules applied to this project can be customized in the + # section below to disable rules from the `package:flutter_lints/flutter.yaml` + # included above or to enable additional rules. A list of all available lints + # and their documentation is published at + # https://dart-lang.github.io/linter/lints/index.html. + # + # Instead of disabling a lint rule for the entire project in the + # section below, it can also be suppressed for a single line of code + # or a specific dart file by using the `// ignore: name_of_lint` and + # `// ignore_for_file: name_of_lint` syntax on the line or in the file + # producing the lint. + rules: + # avoid_print: false # Uncomment to disable the `avoid_print` rule + # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule + +# Additional information about this file can be found at +# https://dart.dev/guides/language/analysis-options diff --git a/example/analysis_options.yaml b/example/analysis_options.yaml new file mode 100644 index 00000000..61b6c4de --- /dev/null +++ b/example/analysis_options.yaml @@ -0,0 +1,29 @@ +# This file configures the analyzer, which statically analyzes Dart code to +# check for errors, warnings, and lints. +# +# The issues identified by the analyzer are surfaced in the UI of Dart-enabled +# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be +# invoked from the command line by running `flutter analyze`. + +# The following line activates a set of recommended lints for Flutter apps, +# packages, and plugins designed to encourage good coding practices. +include: package:flutter_lints/flutter.yaml + +linter: + # The lint rules applied to this project can be customized in the + # section below to disable rules from the `package:flutter_lints/flutter.yaml` + # included above or to enable additional rules. A list of all available lints + # and their documentation is published at + # https://dart-lang.github.io/linter/lints/index.html. + # + # Instead of disabling a lint rule for the entire project in the + # section below, it can also be suppressed for a single line of code + # or a specific dart file by using the `// ignore: name_of_lint` and + # `// ignore_for_file: name_of_lint` syntax on the line or in the file + # producing the lint. + rules: + # avoid_print: false # Uncomment to disable the `avoid_print` rule + # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule + +# Additional information about this file can be found at +# https://dart.dev/guides/language/analysis-options diff --git a/example/lib/examples/cloudanchorexample.dart b/example/lib/examples/cloudanchorexample.dart index f90032df..d2b09834 100644 --- a/example/lib/examples/cloudanchorexample.dart +++ b/example/lib/examples/cloudanchorexample.dart @@ -1,25 +1,23 @@ -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/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:vector_math/vector_math_64.dart'; -import 'package:firebase_core/firebase_core.dart'; +import 'package:ar_flutter_plugin/models/ar_node.dart'; import 'package:cloud_firestore/cloud_firestore.dart'; +import 'package:firebase_core/firebase_core.dart'; +import 'package:flutter/material.dart'; import 'package:geoflutterfire/geoflutterfire.dart'; import 'package:geolocator/geolocator.dart'; +import 'package:vector_math/vector_math_64.dart'; class CloudAnchorWidget extends StatefulWidget { - CloudAnchorWidget({Key? key}) : super(key: key); + const CloudAnchorWidget({Key? key}) : super(key: key); @override _CloudAnchorWidgetState createState() => _CloudAnchorWidgetState(); } @@ -29,7 +27,7 @@ class _CloudAnchorWidgetState extends State { bool _initialized = false; bool _error = false; FirebaseManager firebaseManager = FirebaseManager(); - Map anchorsInDownloadProgress = Map(); + Map anchorsInDownloadProgress = {}; ARSessionManager? arSessionManager; ARObjectManager? arObjectManager; @@ -67,15 +65,14 @@ class _CloudAnchorWidgetState extends State { appBar: AppBar( title: const Text('Cloud Anchors'), ), - body: Container( - child: Center( - child: Column( + body: Center( + child: Column( children: [ - Text("Firebase initialization failed"), + const Text("Firebase initialization failed"), ElevatedButton( - child: Text("Retry"), onPressed: () => {initState()}) + child: const Text("Retry"), onPressed: () => {initState()}) ], - )))); + ))); } // Show a loader until FlutterFire is initialized @@ -84,20 +81,18 @@ class _CloudAnchorWidgetState extends State { appBar: AppBar( title: const Text('Cloud Anchors'), ), - body: Container( - child: Center( - child: Column(children: [ + body: Center( + child: Column(children: const [ CircularProgressIndicator(), Text("Initializing Firebase") - ])))); + ]))); } return Scaffold( appBar: AppBar( title: const Text('Cloud Anchors'), ), - body: Container( - child: Stack(children: [ + body: Stack(children: [ ARView( onARViewCreated: onARViewCreated, planeDetectionConfig: PlaneDetectionConfig.horizontalAndVertical, @@ -109,7 +104,7 @@ class _CloudAnchorWidgetState extends State { children: [ ElevatedButton( onPressed: onRemoveEverything, - child: Text("Remove Everything")), + child: const Text("Remove Everything")), ]), ), Align( @@ -121,15 +116,15 @@ class _CloudAnchorWidgetState extends State { visible: readyToUpload, child: ElevatedButton( onPressed: onUploadButtonPressed, - child: Text("Upload"))), + child: const Text("Upload"))), Visibility( visible: readyToDownload, child: ElevatedButton( onPressed: onDownloadButtonPressed, - child: Text("Download"))), + child: const Text("Download"))), ]), ) - ]))); + ])); } void onARViewCreated( @@ -157,8 +152,8 @@ class _CloudAnchorWidgetState extends State { this.arAnchorManager!.onAnchorDownloaded = onAnchorDownloaded; this - .arLocationManager - !.startLocationUpdates() + .arLocationManager! + .startLocationUpdates() .then((value) => null) .onError((error, stackTrace) { switch (error.toString()) { @@ -209,9 +204,9 @@ class _CloudAnchorWidgetState extends State { } Future onRemoveEverything() async { - anchors.forEach((anchor) { - this.arAnchorManager!.removeAnchor(anchor); - }); + for (var anchor in anchors) { + arAnchorManager!.removeAnchor(anchor); + } anchors = []; if (lastUploadedAnchor != "") { setState(() { @@ -229,45 +224,44 @@ class _CloudAnchorWidgetState extends State { Future onNodeTapped(List nodeNames) async { var foregroundNode = nodes.firstWhere((element) => element.name == nodeNames.first); - this.arSessionManager!.onError(foregroundNode.data!["onTapText"]); + 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"); - } + var newAnchor = ARPlaneAnchor( + transformation: singleHitTestResult.worldTransform, ttl: 2); + bool? didAddAnchor = await arAnchorManager!.addAnchor(newAnchor); + if (didAddAnchor ?? false) { + 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 arObjectManager!.addNode(newNode, planeAnchor: newAnchor); + if (didAddNodeToAnchor ?? false) { + nodes.add(newNode); + setState(() { + readyToUpload = true; + }); } else { - this.arSessionManager!.onError("Adding Anchor failed"); + arSessionManager!.onError("Adding Node to Anchor failed"); } + } else { + arSessionManager!.onError("Adding Anchor failed"); } } Future onUploadButtonPressed() async { - this.arAnchorManager!.uploadAnchor(this.anchors.last); + arAnchorManager!.uploadAnchor(anchors.last); setState(() { readyToUpload = false; }); @@ -276,31 +270,36 @@ class _CloudAnchorWidgetState extends State { onAnchorUploaded(ARAnchor anchor) { // Upload anchor information to firebase firebaseManager.uploadAnchor(anchor, - currentLocation: this.arLocationManager!.currentLocation); + currentLocation: arLocationManager!.currentLocation); // Upload child nodes to firebase if (anchor is ARPlaneAnchor) { - anchor.childNodes.forEach((nodeName) => firebaseManager.uploadObject( - nodes.firstWhere((element) => element.name == nodeName))); + for (var nodeName in anchor.childNodes) { + firebaseManager.uploadObject( + nodes.firstWhere((element) => element.name == nodeName)); + } } setState(() { readyToDownload = true; readyToUpload = false; }); - this.arSessionManager!.onError("Upload successful"); + arSessionManager!.onError("Upload successful"); } - ARAnchor onAnchorDownloaded(MapserializedAnchor) { - final anchor = ARPlaneAnchor.fromJson(anchorsInDownloadProgress[serializedAnchor["cloudanchorid"]] as Map); + ARAnchor onAnchorDownloaded(Map serializedAnchor) { + final anchor = ARPlaneAnchor.fromJson( + anchorsInDownloadProgress[serializedAnchor["cloudanchorid"]] + as Map); anchorsInDownloadProgress.remove(anchor.cloudanchorid); - this.anchors.add(anchor); + 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); + for (var objectDoc in snapshot.docs) { + ARNode object = + ARNode.fromMap(objectDoc.data() as Map); arObjectManager!.addNode(object, planeAnchor: anchor); - this.nodes.add(object); - }); + nodes.add(object); + } }); return anchor; @@ -315,18 +314,18 @@ class _CloudAnchorWidgetState extends State { //}); // Get anchors within a radius of 100m of the current device's location - if (this.arLocationManager!.currentLocation != null) { + if (arLocationManager != null) { firebaseManager.downloadAnchorsByLocation((snapshot) { final cloudAnchorId = snapshot.get("cloudanchorid"); - anchorsInDownloadProgress[cloudAnchorId] = snapshot.data() as Map; + anchorsInDownloadProgress[cloudAnchorId] = + snapshot.data() as Map; arAnchorManager!.downloadAnchor(cloudAnchorId); - }, this.arLocationManager!.currentLocation, 0.1); + }, arLocationManager!.currentLocation, 0.1); setState(() { readyToDownload = false; }); } else { - this - .arSessionManager! + arSessionManager! .onError("Location updates not running, can't download anchors"); } } @@ -411,9 +410,9 @@ class FirebaseManager { anchorCollection! .add(serializedAnchor) - .then((value) => - print("Successfully added anchor: " + serializedAnchor["name"])) - .catchError((error) => print("Failed to add anchor: $error")); + .then((value) => debugPrint( + "Successfully added anchor: " + serializedAnchor["name"])) + .catchError((error) => debugPrint("Failed to add anchor: $error")); } void uploadObject(ARNode node) { @@ -424,8 +423,8 @@ class FirebaseManager { objectCollection! .add(serializedNode) .then((value) => - print("Successfully added object: " + serializedNode["name"])) - .catchError((error) => print("Failed to add object: $error")); + debugPrint("Successfully added object: " + serializedNode["name"])) + .catchError((error) => debugPrint("Failed to add object: $error")); } void downloadLatestAnchor(FirebaseListener listener) { @@ -434,8 +433,8 @@ class FirebaseManager { .limitToLast(1) .get() .then((value) => listener(value)) - .catchError( - (error) => (error) => print("Failed to download anchor: $error")); + .catchError((error) => + (error) => debugPrint("Failed to download anchor: $error")); } void downloadAnchorsByLocation(FirebaseDocumentStreamListener listener, @@ -448,9 +447,9 @@ class FirebaseManager { .within(center: center, radius: radius, field: 'position'); stream.listen((List documentList) { - documentList.forEach((element) { + for (var element in documentList) { listener(element); - }); + } }); } @@ -461,7 +460,8 @@ class FirebaseManager { .where("name", whereIn: anchor.childNodes) .get() .then((value) => listener(value)) - .catchError((error) => print("Failed to download objects: $error")); + .catchError( + (error) => debugPrint("Failed to download objects: $error")); } void deleteExpiredDatabaseEntries() { diff --git a/example/lib/examples/debugoptionsexample.dart b/example/lib/examples/debugoptionsexample.dart index 6232864b..d653796b 100644 --- a/example/lib/examples/debugoptionsexample.dart +++ b/example/lib/examples/debugoptionsexample.dart @@ -1,13 +1,13 @@ +import 'package:ar_flutter_plugin/ar_flutter_plugin.dart'; +import 'package:ar_flutter_plugin/datatypes/config_planedetection.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_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/managers/ar_session_manager.dart'; import 'package:flutter/material.dart'; -import 'package:ar_flutter_plugin/ar_flutter_plugin.dart'; -import 'package:ar_flutter_plugin/datatypes/config_planedetection.dart'; class DebugOptionsWidget extends StatefulWidget { - DebugOptionsWidget({Key? key}) : super(key: key); + const DebugOptionsWidget({Key? key}) : super(key: key); @override _DebugOptionsWidgetState createState() => _DebugOptionsWidgetState(); } @@ -18,9 +18,9 @@ class _DebugOptionsWidgetState extends State { bool _showFeaturePoints = false; bool _showPlanes = false; bool _showWorldOrigin = false; - bool _showAnimatedGuide = true; - String _planeTexturePath = "Images/triangle.png"; - bool _handleTaps = false; + final bool _showAnimatedGuide = true; + final String _planeTexturePath = "Images/triangle.png"; + final bool _handleTaps = false; @override void dispose() { @@ -34,8 +34,7 @@ class _DebugOptionsWidgetState extends State { appBar: AppBar( title: const Text('Debug Options'), ), - body: Container( - child: Stack(children: [ + body: Stack(children: [ ARView( onARViewCreated: onARViewCreated, planeDetectionConfig: PlaneDetectionConfig.horizontalAndVertical, @@ -45,7 +44,7 @@ class _DebugOptionsWidgetState extends State { alignment: FractionalOffset.bottomRight, child: Container( width: MediaQuery.of(context).size.width * 0.5, - color: Color(0xFFFFFFF).withOpacity(0.5), + color: const Color(0x0fffffff).withOpacity(0.5), child: Column( crossAxisAlignment: CrossAxisAlignment.end, mainAxisSize: MainAxisSize.min, @@ -84,7 +83,7 @@ class _DebugOptionsWidgetState extends State { ), ), ), - ]))); + ])); } void onARViewCreated( @@ -107,11 +106,11 @@ class _DebugOptionsWidgetState extends State { } void updateSessionSettings() { - this.arSessionManager!.onInitialize( - showFeaturePoints: _showFeaturePoints, - showPlanes: _showPlanes, - customPlaneTexturePath: _planeTexturePath, - showWorldOrigin: _showWorldOrigin, - ); + arSessionManager!.onInitialize( + showFeaturePoints: _showFeaturePoints, + showPlanes: _showPlanes, + customPlaneTexturePath: _planeTexturePath, + showWorldOrigin: _showWorldOrigin, + ); } } diff --git a/example/lib/examples/externalmodelmanagementexample.dart b/example/lib/examples/externalmodelmanagementexample.dart index 85e8cbe0..94fc1c68 100644 --- a/example/lib/examples/externalmodelmanagementexample.dart +++ b/example/lib/examples/externalmodelmanagementexample.dart @@ -1,25 +1,23 @@ -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/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:vector_math/vector_math_64.dart' as VectorMath; -import 'package:firebase_core/firebase_core.dart'; +import 'package:ar_flutter_plugin/models/ar_node.dart'; import 'package:cloud_firestore/cloud_firestore.dart'; +import 'package:firebase_core/firebase_core.dart'; +import 'package:flutter/material.dart'; import 'package:geoflutterfire/geoflutterfire.dart'; import 'package:geolocator/geolocator.dart'; +import 'package:vector_math/vector_math_64.dart' as vector_math; class ExternalModelManagementWidget extends StatefulWidget { - ExternalModelManagementWidget({Key? key}) : super(key: key); + const ExternalModelManagementWidget({Key? key}) : super(key: key); @override _ExternalModelManagementWidgetState createState() => _ExternalModelManagementWidgetState(); @@ -31,7 +29,7 @@ class _ExternalModelManagementWidgetState bool _initialized = false; bool _error = false; FirebaseManager firebaseManager = FirebaseManager(); - Map anchorsInDownloadProgress = Map(); + Map anchorsInDownloadProgress = {}; ARSessionManager? arSessionManager; ARObjectManager? arObjectManager; @@ -74,15 +72,14 @@ class _ExternalModelManagementWidgetState appBar: AppBar( title: const Text('External Model Management'), ), - body: Container( - child: Center( - child: Column( + body: Center( + child: Column( children: [ - Text("Firebase initialization failed"), + const Text("Firebase initialization failed"), ElevatedButton( - child: Text("Retry"), onPressed: () => {initState()}) + child: const Text("Retry"), onPressed: () => {initState()}) ], - )))); + ))); } // Show a loader until FlutterFire is initialized @@ -91,12 +88,11 @@ class _ExternalModelManagementWidgetState appBar: AppBar( title: const Text('External Model Management'), ), - body: Container( - child: Center( - child: Column(children: [ + body: Center( + child: Column(children: const [ CircularProgressIndicator(), Text("Initializing Firebase") - ])))); + ]))); } return Scaffold( @@ -104,7 +100,7 @@ class _ExternalModelManagementWidgetState title: const Text('External Model Management'), actions: [ IconButton( - icon: Icon(Icons.pets), + icon: const Icon(Icons.pets), onPressed: () { setState(() { modelChoiceActive = !modelChoiceActive; @@ -112,8 +108,7 @@ class _ExternalModelManagementWidgetState }, ), ]), - body: Container( - child: Stack(children: [ + body: Stack(children: [ ARView( onARViewCreated: onARViewCreated, planeDetectionConfig: PlaneDetectionConfig.horizontalAndVertical, @@ -125,7 +120,7 @@ class _ExternalModelManagementWidgetState children: [ ElevatedButton( onPressed: onRemoveEverything, - child: Text("Remove Everything")), + child: const Text("Remove Everything")), ]), ), Align( @@ -137,12 +132,12 @@ class _ExternalModelManagementWidgetState visible: readyToUpload, child: ElevatedButton( onPressed: onUploadButtonPressed, - child: Text("Upload"))), + child: const Text("Upload"))), Visibility( visible: readyToDownload, child: ElevatedButton( onPressed: onDownloadButtonPressed, - child: Text("Download"))), + child: const Text("Download"))), ]), ), Align( @@ -151,8 +146,8 @@ class _ExternalModelManagementWidgetState visible: modelChoiceActive, child: ModelSelectionWidget( onTap: onModelSelected, - firebaseManager: this.firebaseManager))) - ]))); + firebaseManager: firebaseManager))) + ])); } void onARViewCreated( @@ -232,17 +227,17 @@ class _ExternalModelManagementWidgetState } void onModelSelected(AvailableModel model) { - this.selectedModel = model; - this.arSessionManager!.onError(model.name + " selected"); + selectedModel = model; + arSessionManager!.onError(model.name + " selected"); setState(() { modelChoiceActive = false; }); } Future onRemoveEverything() async { - anchors.forEach((anchor) { - this.arAnchorManager!.removeAnchor(anchor); - }); + for (var anchor in anchors) { + arAnchorManager!.removeAnchor(anchor); + } anchors = []; if (lastUploadedAnchor != "") { setState(() { @@ -258,46 +253,45 @@ class _ExternalModelManagementWidgetState } Future onNodeTapped(List nodeNames) async { - var foregroundNode = nodes.firstWhere((element) => element.name == nodeNames.first); - this.arSessionManager!.onError(foregroundNode.data!["onTapText"]); + var foregroundNode = + nodes.firstWhere((element) => element.name == nodeNames.first); + 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"); - } + var newAnchor = ARPlaneAnchor( + transformation: singleHitTestResult.worldTransform, ttl: 2); + bool? didAddAnchor = await arAnchorManager!.addAnchor(newAnchor); + if (didAddAnchor!) { + anchors.add(newAnchor); + // Add note to anchor + var newNode = ARNode( + type: NodeType.webGLB, + uri: selectedModel.uri, + scale: vector_math.Vector3(0.2, 0.2, 0.2), + position: vector_math.Vector3(0.0, 0.0, 0.0), + rotation: vector_math.Vector4(1.0, 0.0, 0.0, 0.0), + data: {"onTapText": "I am a " + selectedModel.name}); + bool? didAddNodeToAnchor = + await arObjectManager!.addNode(newNode, planeAnchor: newAnchor); + if (didAddNodeToAnchor!) { + nodes.add(newNode); + setState(() { + readyToUpload = true; + }); } else { - this.arSessionManager!.onError("Adding Anchor failed"); + arSessionManager!.onError("Adding Node to Anchor failed"); } + } else { + arSessionManager!.onError("Adding Anchor failed"); } } Future onUploadButtonPressed() async { - this.arAnchorManager!.uploadAnchor(this.anchors.last); + arAnchorManager!.uploadAnchor(anchors.last); setState(() { readyToUpload = false; }); @@ -306,31 +300,36 @@ class _ExternalModelManagementWidgetState onAnchorUploaded(ARAnchor anchor) { // Upload anchor information to firebase firebaseManager.uploadAnchor(anchor, - currentLocation: this.arLocationManager!.currentLocation); + currentLocation: arLocationManager!.currentLocation); // Upload child nodes to firebase if (anchor is ARPlaneAnchor) { - anchor.childNodes.forEach((nodeName) => firebaseManager.uploadObject( - nodes.firstWhere((element) => element.name == nodeName))); + for (var nodeName in anchor.childNodes) { + firebaseManager.uploadObject( + nodes.firstWhere((element) => element.name == nodeName)); + } } setState(() { readyToDownload = true; readyToUpload = false; }); - this.arSessionManager!.onError("Upload successful"); + arSessionManager!.onError("Upload successful"); } - ARAnchor onAnchorDownloaded(Map serializedAnchor) { - final anchor = ARPlaneAnchor.fromJson(anchorsInDownloadProgress[serializedAnchor["cloudanchorid"]] as Map); + ARAnchor onAnchorDownloaded(Map serializedAnchor) { + final anchor = ARPlaneAnchor.fromJson( + anchorsInDownloadProgress[serializedAnchor["cloudanchorid"]] + as Map); anchorsInDownloadProgress.remove(anchor.cloudanchorid); - this.anchors.add(anchor); + 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); + for (var objectDoc in snapshot.docs) { + ARNode object = + ARNode.fromMap(objectDoc.data() as Map); arObjectManager!.addNode(object, planeAnchor: anchor); - this.nodes.add(object); - }); + nodes.add(object); + } }); return anchor; @@ -345,18 +344,18 @@ class _ExternalModelManagementWidgetState //}); // Get anchors within a radius of 100m of the current device's location - if (this.arLocationManager!.currentLocation != null) { + if (arLocationManager != null) { firebaseManager.downloadAnchorsByLocation((snapshot) { final cloudAnchorId = snapshot.get("cloudanchorid"); - anchorsInDownloadProgress[cloudAnchorId] = snapshot.data() as Map; + anchorsInDownloadProgress[cloudAnchorId] = + snapshot.data() as Map; arAnchorManager!.downloadAnchor(cloudAnchorId); - }, this.arLocationManager!.currentLocation, 0.1); + }, arLocationManager!.currentLocation, 0.1); setState(() { readyToDownload = false; }); } else { - this - .arSessionManager! + arSessionManager! .onError("Location updates not running, can't download anchors"); } } @@ -443,9 +442,9 @@ class FirebaseManager { anchorCollection! .add(serializedAnchor) - .then((value) => - print("Successfully added anchor: " + serializedAnchor["name"])) - .catchError((error) => print("Failed to add anchor: $error")); + .then((value) => debugPrint( + "Successfully added anchor: " + serializedAnchor["name"])) + .catchError((error) => debugPrint("Failed to add anchor: $error")); } void uploadObject(ARNode node) { @@ -456,8 +455,8 @@ class FirebaseManager { objectCollection! .add(serializedNode) .then((value) => - print("Successfully added object: " + serializedNode["name"])) - .catchError((error) => print("Failed to add object: $error")); + debugPrint("Successfully added object: " + serializedNode["name"])) + .catchError((error) => debugPrint("Failed to add object: $error")); } void downloadLatestAnchor(FirebaseListener listener) { @@ -466,8 +465,8 @@ class FirebaseManager { .limitToLast(1) .get() .then((value) => listener(value)) - .catchError( - (error) => (error) => print("Failed to download anchor: $error")); + .catchError((error) => + (error) => debugPrint("Failed to download anchor: $error")); } void downloadAnchorsByLocation(FirebaseDocumentStreamListener listener, @@ -480,9 +479,9 @@ class FirebaseManager { .within(center: center, radius: radius, field: 'position'); stream.listen((List documentList) { - documentList.forEach((element) { + for (var element in documentList) { listener(element); - }); + } }); } @@ -493,7 +492,8 @@ class FirebaseManager { .where("name", whereIn: anchor.childNodes) .get() .then((value) => listener(value)) - .catchError((error) => print("Failed to download objects: $error")); + .catchError( + (error) => debugPrint("Failed to download objects: $error")); } void deleteExpiredDatabaseEntries() { @@ -516,10 +516,8 @@ class FirebaseManager { } void downloadAvailableModels(FirebaseListener listener) { - modelCollection! - .get() - .then((value) => listener(value)) - .catchError((error) => print("Failed to download objects: $error")); + modelCollection!.get().then((value) => listener(value)).catchError( + (error) => debugPrint("Failed to download objects: $error")); } } @@ -534,7 +532,9 @@ class ModelSelectionWidget extends StatefulWidget { final Function onTap; final FirebaseManager firebaseManager; - ModelSelectionWidget({required this.onTap, required this.firebaseManager}); + const ModelSelectionWidget( + {Key? key, required this.onTap, required this.firebaseManager}) + : super(key: key); @override _ModelSelectionWidgetState createState() => _ModelSelectionWidgetState(); @@ -549,12 +549,12 @@ class _ModelSelectionWidgetState extends State { void initState() { super.initState(); widget.firebaseManager.downloadAvailableModels((snapshot) { - snapshot.docs.forEach((element) { + for (var element in snapshot.docs) { setState(() { models.add(AvailableModel(element.get("name"), element.get("uri"), element.get("image").first["downloadURL"])); }); - }); + } }); } @@ -572,7 +572,7 @@ class _ModelSelectionWidgetState extends State { style: BorderStyle.solid, width: 4.0, ), - borderRadius: BorderRadius.all(Radius.circular(5)), + borderRadius: const BorderRadius.all(Radius.circular(5)), shape: BoxShape.rectangle, boxShadow: const [ BoxShadow( @@ -587,7 +587,7 @@ class _ModelSelectionWidgetState extends State { .style .apply(fontSizeFactor: 2.0)), ), - Container( + SizedBox( height: MediaQuery.of(context).size.width * 0.65, child: ListView.builder( itemCount: models.length, @@ -599,7 +599,7 @@ class _ModelSelectionWidgetState extends State { }, child: Card( elevation: 4.0, - shape: RoundedRectangleBorder( + shape: const RoundedRectangleBorder( borderRadius: BorderRadius.all( Radius.circular(5), ), @@ -607,7 +607,7 @@ class _ModelSelectionWidgetState extends State { child: Column( children: [ Padding( - padding: EdgeInsets.all(20), + padding: const EdgeInsets.all(20), child: Image.network(models[index].image)), Text( models[index].name, diff --git a/example/lib/examples/localandwebobjectsexample.dart b/example/lib/examples/localandwebobjectsexample.dart index 5d2af4c2..e54df668 100644 --- a/example/lib/examples/localandwebobjectsexample.dart +++ b/example/lib/examples/localandwebobjectsexample.dart @@ -1,23 +1,22 @@ import 'dart:io'; +import 'dart:math'; -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:flutter/foundation.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/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_node.dart'; -import 'package:flutter/services.dart'; -import 'package:vector_math/vector_math_64.dart'; -import 'dart:math'; -import 'package:path_provider/path_provider.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; import 'package:flutter_archive/flutter_archive.dart'; +import 'package:path_provider/path_provider.dart'; +import 'package:vector_math/vector_math_64.dart'; class LocalAndWebObjectsWidget extends StatefulWidget { - LocalAndWebObjectsWidget({Key? key}) : super(key: key); + const LocalAndWebObjectsWidget({Key? key}) : super(key: key); @override _LocalAndWebObjectsWidgetState createState() => _LocalAndWebObjectsWidgetState(); @@ -45,8 +44,7 @@ class _LocalAndWebObjectsWidgetState extends State { appBar: AppBar( title: const Text('Local & Web Objects'), ), - body: Container( - child: Stack(children: [ + body: Stack(children: [ ARView( onARViewCreated: onARViewCreated, planeDetectionConfig: PlaneDetectionConfig.horizontalAndVertical, @@ -60,7 +58,8 @@ class _LocalAndWebObjectsWidgetState extends State { children: [ ElevatedButton( onPressed: onFileSystemObjectAtOriginButtonPressed, - child: Text("Add/Remove Filesystem\nObject at Origin")), + child: const Text( + "Add/Remove Filesystem\nObject at Origin")), ], ), Row( @@ -68,10 +67,11 @@ class _LocalAndWebObjectsWidgetState extends State { children: [ ElevatedButton( onPressed: onLocalObjectAtOriginButtonPressed, - child: Text("Add/Remove Local\nObject at Origin")), + child: + const Text("Add/Remove Local\nObject at Origin")), ElevatedButton( onPressed: onWebObjectAtOriginButtonPressed, - child: Text("Add/Remove Web\nObject at Origin")), + child: const Text("Add/Remove Web\nObject at Origin")), ], ), Row( @@ -79,14 +79,14 @@ class _LocalAndWebObjectsWidgetState extends State { children: [ ElevatedButton( onPressed: onLocalObjectShuffleButtonPressed, - child: Text("Shuffle Local\nobject at Origin")), + child: const Text("Shuffle Local\nobject at Origin")), ElevatedButton( onPressed: onWebObjectShuffleButtonPressed, - child: Text("Shuffle Web\nObject at Origin")), + child: const Text("Shuffle Web\nObject at Origin")), ], ) ])) - ]))); + ])); } void onARViewCreated( @@ -107,7 +107,7 @@ class _LocalAndWebObjectsWidgetState extends State { this.arObjectManager!.onInitialize(); //Download model to file system - httpClient = new HttpClient(); + httpClient = HttpClient(); _downloadFile( "https://github.com/KhronosGroup/glTF-Sample-Models/raw/master/2.0/Duck/glTF-Binary/Duck.glb", "LocalDuck.glb"); @@ -122,9 +122,9 @@ class _LocalAndWebObjectsWidgetState extends State { var response = await request.close(); var bytes = await consolidateHttpClientResponseBytes(response); String dir = (await getApplicationDocumentsDirectory()).path; - File file = new File('$dir/$filename'); + File file = File('$dir/$filename'); await file.writeAsBytes(bytes); - print("Downloading finished, path: " + '$dir/$filename'); + debugPrint("Downloading finished, path: " '$dir/$filename'); return file; } @@ -133,24 +133,24 @@ class _LocalAndWebObjectsWidgetState extends State { var response = await request.close(); var bytes = await consolidateHttpClientResponseBytes(response); String dir = (await getApplicationDocumentsDirectory()).path; - File file = new File('$dir/$filename'); + File file = File('$dir/$filename'); await file.writeAsBytes(bytes); - print("Downloading finished, path: " + '$dir/$filename'); + debugPrint("Downloading finished, path: " '$dir/$filename'); - // To print all files in the directory: print(Directory(dir).listSync()); + // To print all files in the directory: debugPrint(Directory(dir).listSync()); try { await ZipFile.extractToDirectory( zipFile: File('$dir/$filename'), destinationDir: Directory(dir)); - print("Unzipping successful"); + debugPrint("Unzipping successful"); } catch (e) { - print("Unzipping failed: " + e.toString()); + debugPrint("Unzipping failed: " + e.toString()); } } Future onLocalObjectAtOriginButtonPressed() async { - if (this.localObjectNode != null) { - this.arObjectManager!.removeNode(this.localObjectNode!); - this.localObjectNode = null; + if (localObjectNode != null) { + arObjectManager!.removeNode(localObjectNode!); + localObjectNode = null; } else { var newNode = ARNode( type: NodeType.localGLTF2, @@ -158,30 +158,30 @@ class _LocalAndWebObjectsWidgetState extends State { 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? didAddLocalNode = await this.arObjectManager!.addNode(newNode); - this.localObjectNode = (didAddLocalNode!) ? newNode : null; + bool? didAddLocalNode = await arObjectManager!.addNode(newNode); + localObjectNode = (didAddLocalNode!) ? newNode : null; } } Future onWebObjectAtOriginButtonPressed() async { - if (this.webObjectNode != null) { - this.arObjectManager!.removeNode(this.webObjectNode!); - this.webObjectNode = null; + if (webObjectNode != null) { + arObjectManager!.removeNode(webObjectNode!); + webObjectNode = null; } else { 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)); - bool? didAddWebNode = await this.arObjectManager!.addNode(newNode); - this.webObjectNode = (didAddWebNode!) ? newNode : null; + bool? didAddWebNode = await arObjectManager!.addNode(newNode); + webObjectNode = (didAddWebNode!) ? newNode : null; } } Future onFileSystemObjectAtOriginButtonPressed() async { - if (this.fileSystemNode != null) { - this.arObjectManager!.removeNode(this.fileSystemNode!); - this.fileSystemNode = null; + if (fileSystemNode != null) { + arObjectManager!.removeNode(fileSystemNode!); + fileSystemNode = null; } else { var newNode = ARNode( type: NodeType.fileSystemAppFolderGLB, @@ -192,13 +192,13 @@ class _LocalAndWebObjectsWidgetState extends State { // type: NodeType.fileSystemAppFolderGLTF2, // uri: "Chicken_01.gltf", // scale: Vector3(0.2, 0.2, 0.2)); - bool? didAddFileSystemNode = await this.arObjectManager!.addNode(newNode); - this.fileSystemNode = (didAddFileSystemNode!) ? newNode : null; + bool? didAddFileSystemNode = await arObjectManager!.addNode(newNode); + fileSystemNode = (didAddFileSystemNode!) ? newNode : null; } } Future onLocalObjectShuffleButtonPressed() async { - if (this.localObjectNode != null) { + if (localObjectNode != null) { var newScale = Random().nextDouble() / 3; var newTranslationAxis = Random().nextInt(3); var newTranslationAmount = Random().nextDouble() / 3; @@ -215,12 +215,12 @@ class _LocalAndWebObjectsWidgetState extends State { newTransform.rotate(newRotationAxis, newRotationAmount); newTransform.scale(newScale); - this.localObjectNode!.transform = newTransform; + localObjectNode!.transform = newTransform; } } Future onWebObjectShuffleButtonPressed() async { - if (this.webObjectNode != null) { + if (webObjectNode != null) { var newScale = Random().nextDouble() / 3; var newTranslationAxis = Random().nextInt(3); var newTranslationAmount = Random().nextDouble() / 3; @@ -237,7 +237,7 @@ class _LocalAndWebObjectsWidgetState extends State { newTransform.rotate(newRotationAxis, newRotationAmount); newTransform.scale(newScale); - this.webObjectNode!.transform = newTransform; + webObjectNode!.transform = newTransform; } } } diff --git a/example/lib/examples/objectgesturesexample.dart b/example/lib/examples/objectgesturesexample.dart index 6d9f42ae..eadaf40f 100644 --- a/example/lib/examples/objectgesturesexample.dart +++ b/example/lib/examples/objectgesturesexample.dart @@ -1,21 +1,19 @@ -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); + const ObjectGesturesWidget({Key? key}) : super(key: key); @override _ObjectGesturesWidgetState createState() => _ObjectGesturesWidgetState(); } @@ -40,8 +38,7 @@ class _ObjectGesturesWidgetState extends State { appBar: AppBar( title: const Text('Object Transformation Gestures'), ), - body: Container( - child: Stack(children: [ + body: Stack(children: [ ARView( onARViewCreated: onARViewCreated, planeDetectionConfig: PlaneDetectionConfig.horizontalAndVertical, @@ -53,10 +50,10 @@ class _ObjectGesturesWidgetState extends State { children: [ ElevatedButton( onPressed: onRemoveEverything, - child: Text("Remove Everything")), + child: const Text("Remove Everything")), ]), ) - ]))); + ])); } void onARViewCreated( @@ -91,9 +88,9 @@ class _ObjectGesturesWidgetState extends State { /*nodes.forEach((node) { this.arObjectManager.removeNode(node); });*/ - anchors.forEach((anchor) { - this.arAnchorManager!.removeAnchor(anchor); - }); + for (var anchor in anchors) { + arAnchorManager!.removeAnchor(anchor); + } anchors = []; } @@ -101,70 +98,68 @@ 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 arAnchorManager!.addAnchor(newAnchor); + if (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!) { + nodes.add(newNode); } else { - this.arSessionManager!.onError("Adding Anchor failed"); + arSessionManager!.onError("Adding Node to Anchor failed"); } + } else { + arSessionManager!.onError("Adding Anchor failed"); } } onPanStarted(String nodeName) { - print("Started panning node " + nodeName); + debugPrint("Started panning node " + nodeName); } onPanChanged(String nodeName) { - print("Continued panning node " + nodeName); + debugPrint("Continued panning node " + nodeName); } onPanEnded(String nodeName, Matrix4 newTransform) { - print("Ended panning node " + nodeName); - final pannedNode = - this.nodes.firstWhere((element) => element.name == nodeName); + debugPrint("Ended panning node " + nodeName); /* * Uncomment the following command if you want to keep the transformations of the Flutter representations of the nodes up to date * (e.g. if you intend to share the nodes through the cloud) */ + // final pannedNode = + // this.nodes.firstWhere((element) => element.name == nodeName); //pannedNode.transform = newTransform; } onRotationStarted(String nodeName) { - print("Started rotating node " + nodeName); + debugPrint("Started rotating node " + nodeName); } onRotationChanged(String nodeName) { - print("Continued rotating node " + nodeName); + debugPrint("Continued rotating node " + nodeName); } onRotationEnded(String nodeName, Matrix4 newTransform) { - print("Ended rotating node " + nodeName); - final rotatedNode = - this.nodes.firstWhere((element) => element.name == nodeName); + debugPrint("Ended rotating node " + nodeName); /* * Uncomment the following command if you want to keep the transformations of the Flutter representations of the nodes up to date * (e.g. if you intend to share the nodes through the cloud) */ + // final rotatedNode = + // this.nodes.firstWhere((element) => element.name == nodeName); //rotatedNode.transform = newTransform; } } diff --git a/example/lib/examples/objectsonplanesexample.dart b/example/lib/examples/objectsonplanesexample.dart index e23e427d..964664e3 100644 --- a/example/lib/examples/objectsonplanesexample.dart +++ b/example/lib/examples/objectsonplanesexample.dart @@ -1,21 +1,19 @@ -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); + const ObjectsOnPlanesWidget({Key? key}) : super(key: key); @override _ObjectsOnPlanesWidgetState createState() => _ObjectsOnPlanesWidgetState(); } @@ -40,8 +38,7 @@ class _ObjectsOnPlanesWidgetState extends State { appBar: AppBar( title: const Text('Anchors & Objects on Planes'), ), - body: Container( - child: Stack(children: [ + body: Stack(children: [ ARView( onARViewCreated: onARViewCreated, planeDetectionConfig: PlaneDetectionConfig.horizontalAndVertical, @@ -53,10 +50,10 @@ class _ObjectsOnPlanesWidgetState extends State { children: [ ElevatedButton( onPressed: onRemoveEverything, - child: Text("Remove Everything")), + child: const Text("Remove Everything")), ]), ) - ]))); + ])); } void onARViewCreated( @@ -84,56 +81,43 @@ class _ObjectsOnPlanesWidgetState extends State { /*nodes.forEach((node) { this.arObjectManager.removeNode(node); });*/ - anchors.forEach((anchor) { - this.arAnchorManager!.removeAnchor(anchor); - }); + for (var anchor in anchors) { + arAnchorManager!.removeAnchor(anchor); + } anchors = []; } Future onNodeTapped(List nodes) async { var number = nodes.length; - this.arSessionManager!.onError("Tapped $number node(s)"); + arSessionManager!.onError("Tapped $number node(s)"); } Future onPlaneOrPointTapped( 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 arAnchorManager!.addAnchor(newAnchor); + if (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!) { + nodes.add(newNode); + } else { + arSessionManager!.onError("Adding Node to Anchor failed"); + } + } else { + arSessionManager!.onError("Adding Anchor failed"); } } } diff --git a/example/lib/examples/screenshotexample.dart b/example/lib/examples/screenshotexample.dart index dd3cfb5a..61fb0c90 100644 --- a/example/lib/examples/screenshotexample.dart +++ b/example/lib/examples/screenshotexample.dart @@ -1,15 +1,15 @@ -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:ar_flutter_plugin/models/ar_node.dart'; +import 'package:flutter/material.dart'; import 'package:vector_math/vector_math_64.dart'; class ScreenshotWidget extends StatefulWidget { @@ -38,10 +38,7 @@ class _ScreenshotWidgetState extends State { appBar: AppBar( title: const Text('Screenshots'), ), - body: - Container( - child: - Stack(children: [ + body: Stack(children: [ ARView( onARViewCreated: onARViewCreated, planeDetectionConfig: PlaneDetectionConfig.horizontalAndVertical, @@ -59,7 +56,7 @@ class _ScreenshotWidgetState extends State { child: const Text("Take Screenshot")), ]), ) - ]))); + ])); } void onARViewCreated( @@ -88,10 +85,9 @@ class _ScreenshotWidgetState extends State { this.arObjectManager.removeNode(node); });*/ // anchors.forEach((anchor) - for (var anchor in anchors) - { + for (var anchor in anchors) { arAnchorManager!.removeAnchor(anchor); - }; + } anchors = []; } @@ -116,32 +112,32 @@ 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"); - } + + 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 Anchor failed"); + 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, @@ -152,6 +148,5 @@ class _ScreenshotWidgetState extends State { 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..302dc0b5 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -1,24 +1,25 @@ -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'; -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'; +import 'package:ar_flutter_plugin_example/examples/externalmodelmanagementexample.dart'; +import 'package:ar_flutter_plugin_example/examples/localandwebobjectsexample.dart'; +import 'package:ar_flutter_plugin_example/examples/objectsonplanesexample.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; import 'examples/objectgesturesexample.dart'; import 'examples/screenshotexample.dart'; void main() { WidgetsFlutterBinding.ensureInitialized(); - runApp(MyApp()); + runApp(const MyApp()); } class MyApp extends StatefulWidget { + const MyApp({Key? key}) : super(key: key); + @override _MyAppState createState() => _MyAppState(); } @@ -62,7 +63,7 @@ class _MyAppState extends State { ), body: Column(children: [ Text('Running on: $_platformVersion\n'), - Expanded( + const Expanded( child: ExampleList(), ), ]), @@ -72,7 +73,7 @@ class _MyAppState extends State { } class ExampleList extends StatelessWidget { - ExampleList({Key? key}) : super(key: key); + const ExampleList({Key? key}) : super(key: key); @override Widget build(BuildContext context) { @@ -80,44 +81,52 @@ class ExampleList extends StatelessWidget { Example( 'Debug Options', 'Visualize feature points, planes and world coordinate system', - () => Navigator.push(context, - MaterialPageRoute(builder: (context) => DebugOptionsWidget()))), + () => Navigator.push( + context, + MaterialPageRoute( + builder: (context) => const DebugOptionsWidget()))), Example( 'Local & Online Objects', 'Place 3D objects from Flutter assets and the web into the scene', () => Navigator.push( context, MaterialPageRoute( - builder: (context) => LocalAndWebObjectsWidget()))), + builder: (context) => const LocalAndWebObjectsWidget()))), Example( 'Anchors & Objects on Planes', 'Place 3D objects on detected planes using anchors', () => Navigator.push( context, MaterialPageRoute( - builder: (context) => ObjectsOnPlanesWidget()))), + builder: (context) => const ObjectsOnPlanesWidget()))), Example( 'Object Transformation Gestures', 'Rotate and Pan Objects', - () => Navigator.push(context, - MaterialPageRoute(builder: (context) => ObjectGesturesWidget()))), + () => Navigator.push( + context, + MaterialPageRoute( + builder: (context) => const ObjectGesturesWidget()))), Example( 'Screenshots', 'Place 3D objects on planes and take screenshots', - () => Navigator.push(context, - MaterialPageRoute(builder: (context) => ScreenshotWidget()))), + () => Navigator.push( + context, + MaterialPageRoute( + builder: (context) => const ScreenshotWidget()))), Example( 'Cloud Anchors', 'Place and retrieve 3D objects using the Google Cloud Anchor API', - () => Navigator.push(context, - MaterialPageRoute(builder: (context) => CloudAnchorWidget()))), + () => Navigator.push( + context, + MaterialPageRoute( + builder: (context) => const 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()))) + builder: (context) => const ExternalModelManagementWidget()))) ]; return ListView( children: @@ -127,7 +136,7 @@ class ExampleList extends StatelessWidget { } class ExampleCard extends StatelessWidget { - ExampleCard({Key? key, required this.example}) : super(key: key); + const ExampleCard({Key? key, required this.example}) : super(key: key); final Example example; @override diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 77861910..f9235ab4 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -3,7 +3,7 @@ description: Demonstrates how to use the ar_flutter_plugin plugin. # The following line prevents the package from being accidentally published to # pub.dev using `pub publish`. This is preferred for private packages. -publish_to: 'none' # Remove this line if you wish to publish to pub.dev +publish_to: "none" # Remove this line if you wish to publish to pub.dev environment: sdk: ">=2.16.1 <3.0.0" @@ -34,13 +34,13 @@ dependencies: dev_dependencies: flutter_test: sdk: flutter + flutter_lints: ^1.0.4 # For information on the generic Dart part of this file, see the # following page: https://dart.dev/tools/pub/pubspec # The following section is specific to Flutter. flutter: - # The following line ensures that the Material Icons font is # included with your application, so that you can use the icons in # the material Icons class. diff --git a/example/test/widget_test.dart b/example/test/widget_test.dart index fb96cd69..ff7be932 100644 --- a/example/test/widget_test.dart +++ b/example/test/widget_test.dart @@ -5,21 +5,20 @@ // gestures. You can also use WidgetTester to find child widgets in the widget // tree, read text, and verify that the values of widget properties are correct. +import 'package:ar_flutter_plugin_example/main.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; -import 'package:ar_flutter_plugin_example/main.dart'; - void main() { testWidgets('Verify Platform version', (WidgetTester tester) async { // Build our app and trigger a frame. - await tester.pumpWidget(MyApp()); + await tester.pumpWidget(const MyApp()); // Verify that platform version is retrieved. expect( find.byWidgetPredicate( - (Widget widget) => widget is Text && - widget.data!.startsWith('Running on:'), + (Widget widget) => + widget is Text && widget.data!.startsWith('Running on:'), ), findsOneWidget, ); diff --git a/ios/Classes/ArModelBuilder.swift b/ios/Classes/ArModelBuilder.swift index bae8f496..f11dbf58 100644 --- a/ios/Classes/ArModelBuilder.swift +++ b/ios/Classes/ArModelBuilder.swift @@ -81,7 +81,7 @@ class ArModelBuilder: NSObject { return node } catch { - print("\(error.localizedDescription)") + debugPrint("\(error.localizedDescription)") return nil } } @@ -110,7 +110,7 @@ class ArModelBuilder: NSObject { return node } catch { - print("\(error.localizedDescription)") + debugPrint("\(error.localizedDescription)") return nil } } @@ -139,7 +139,7 @@ class ArModelBuilder: NSObject { return node } catch { - print("\(error.localizedDescription)") + debugPrint("\(error.localizedDescription)") return nil } } @@ -153,7 +153,7 @@ class ArModelBuilder: NSObject { let handler: (URL?, URLResponse?, Error?) -> Void = {(url: URL?, urlResponse: URLResponse?, error: Error?) -> Void in // If response code is not 200, link was invalid, so return if ((urlResponse as? HTTPURLResponse)?.statusCode != 200) { - print("makeNodeFromWebGltf received non-200 response code") + debugPrint("makeNodeFromWebGltf received non-200 response code") node = nil promise(.success(node)) } else { @@ -186,7 +186,7 @@ class ArModelBuilder: NSObject { node?.worldOrientation = worldRotation*/ } catch { - print("\(error.localizedDescription)") + debugPrint("\(error.localizedDescription)") node = nil } diff --git a/ios/Classes/CloudAnchorHandler.swift b/ios/Classes/CloudAnchorHandler.swift index 343371b0..ddc7b0f9 100644 --- a/ios/Classes/CloudAnchorHandler.swift +++ b/ios/Classes/CloudAnchorHandler.swift @@ -22,7 +22,7 @@ class CloudAnchorHandler: NSObject, GARSessionDelegate { // Register listener so it is invoked when the operation finishes pendingAnchors[newAnchor] = (anchorName, listener) } catch { - print(error) + debugPrint(error) } } @@ -32,7 +32,7 @@ class CloudAnchorHandler: NSObject, GARSessionDelegate { // Register listener so it is invoked when the operation finishes pendingAnchors[newAnchor] = (anchorName, listener) } catch { - print(error) + debugPrint(error) } } @@ -42,7 +42,7 @@ class CloudAnchorHandler: NSObject, GARSessionDelegate { // Register listener so it is invoked when the operation finishes pendingAnchors[newAnchor] = (nil, listener) } catch { - print(error) + debugPrint(error) } } diff --git a/ios/Classes/IosARView.swift b/ios/Classes/IosARView.swift index 49b239fc..5a9a9abf 100644 --- a/ios/Classes/IosARView.swift +++ b/ios/Classes/IosARView.swift @@ -206,7 +206,7 @@ class IosARView: NSObject, FlutterPlatformView, ARSCNViewDelegate, UIGestureReco break case "uploadAnchor": if let anchorName = arguments!["name"] as? String, let anchor = anchorCollection[anchorName] { - print("---------------- HOSTING INITIATED ------------------") + debugPrint("---------------- HOSTING INITIATED ------------------") if let ttl = arguments!["ttl"] as? Int { cloudAnchorHandler?.hostCloudAnchorWithTtl(anchorName: anchorName, anchor: anchor, listener: cloudAnchorUploadedListener(parent: self), ttl: ttl) } else { @@ -217,7 +217,7 @@ class IosARView: NSObject, FlutterPlatformView, ARSCNViewDelegate, UIGestureReco break case "downloadAnchor": if let anchorId = arguments!["cloudanchorid"] as? String { - print("---------------- RESOLVING INITIATED ------------------") + debugPrint("---------------- RESOLVING INITIATED ------------------") cloudAnchorHandler?.resolveCloudAnchor(anchorId: anchorId, listener: cloudAnchorDownloadedListener(parent: self)) } break @@ -368,7 +368,7 @@ class IosARView: NSObject, FlutterPlatformView, ARSCNViewDelegate, UIGestureReco do { try arcoreSession!.update(frame) } catch { - print(error) + debugPrint(error) } } } @@ -412,7 +412,7 @@ class IosARView: NSObject, FlutterPlatformView, ARSCNViewDelegate, UIGestureReco // Add object to scene self.modelBuilder.makeNodeFromWebGlb(name: dict_node["name"] as! String, modelURL: dict_node["uri"] as! String, transformation: dict_node["transformation"] as? Array) .sink(receiveCompletion: { - completion in print("Async Model Downloading Task completed: ", completion) + completion in debugPrint("Async Model Downloading Task completed: ", completion) }, receiveValue: { val in if let node: SCNNode = val { if let anchorName = dict_anchor?["name"] as? String, let anchorType = dict_anchor?["type"] as? Int { @@ -723,7 +723,7 @@ class IosARView: NSObject, FlutterPlatformView, ARSCNViewDelegate, UIGestureReco args["cloudanchorid"] = anchor?.cloudIdentifier parent.anchorManagerChannel.invokeMethod("onCloudAnchorUploaded", arguments: args) } else { - print("Error uploading anchor, state: \(parent.decodeCloudAnchorState(state: cloudState))") + debugPrint("Error uploading anchor, state: \(parent.decodeCloudAnchorState(state: cloudState))") parent.sessionManagerChannel.invokeMethod("onError", arguments: ["Error uploading anchor, state: \(parent.decodeCloudAnchorState(state: cloudState))"]) return } @@ -753,7 +753,7 @@ class IosARView: NSObject, FlutterPlatformView, ARSCNViewDelegate, UIGestureReco }) } else { - print("Error downloading anchor, state \(cloudState)") + debugPrint("Error downloading anchor, state \(cloudState)") parent.sessionManagerChannel.invokeMethod("onError", arguments: ["Error downloading anchor, state \(cloudState)"]) return } diff --git a/ios/Classes/JWTGenerator.swift b/ios/Classes/JWTGenerator.swift index f5c509b4..34d59c72 100644 --- a/ios/Classes/JWTGenerator.swift +++ b/ios/Classes/JWTGenerator.swift @@ -49,7 +49,7 @@ class JWTGenerator { } } catch { - print("Error generating JWT") + debugPrint("Error generating JWT") } } return nil diff --git a/lib/ar_flutter_plugin.dart b/lib/ar_flutter_plugin.dart index 1dbf5183..92486e5c 100644 --- a/lib/ar_flutter_plugin.dart +++ b/lib/ar_flutter_plugin.dart @@ -1,12 +1,11 @@ -export 'package:ar_flutter_plugin/widgets/ar_view.dart'; - import 'dart:async'; import 'package:flutter/services.dart'; +export 'package:ar_flutter_plugin/widgets/ar_view.dart'; + class ArFlutterPlugin { - static const MethodChannel _channel = - const MethodChannel('ar_flutter_plugin'); + static const MethodChannel _channel = MethodChannel('ar_flutter_plugin'); /// Private constructor to prevent accidental instantiation of the Plugin using the implicit default constructor ArFlutterPlugin._(); diff --git a/lib/managers/ar_anchor_manager.dart b/lib/managers/ar_anchor_manager.dart index 817bc27e..417f3de8 100644 --- a/lib/managers/ar_anchor_manager.dart +++ b/lib/managers/ar_anchor_manager.dart @@ -1,6 +1,6 @@ import 'package:ar_flutter_plugin/models/ar_anchor.dart'; -import 'package:flutter/services.dart'; import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; // Type definitions to enforce a consistent use of the API typedef AnchorUploadedHandler = void Function(ARAnchor arAnchor); @@ -27,9 +27,8 @@ class ARAnchorManager { ARAnchorManager(int id, {this.debug = false}) { _channel = MethodChannel('aranchors_$id'); _channel.setMethodCallHandler(_platformCallHandler); - if (debug) { - print("ARAnchorManager initialized"); - } + + debugPrint("ARAnchorManager initialized"); } /// Activates collaborative AR mode (using Google Cloud Anchors) @@ -38,18 +37,17 @@ class ARAnchorManager { } Future _platformCallHandler(MethodCall call) async { - if (debug) { - print('_platformCallHandler call ${call.method} ${call.arguments}'); - } + debugPrint('_platformCallHandler call ${call.method} ${call.arguments}'); + try { switch (call.method) { case 'onError': - print(call.arguments); + debugPrint(call.arguments); break; case 'onCloudAnchorUploaded': final name = call.arguments["name"]; final cloudanchorid = call.arguments["cloudanchorid"]; - print( + debugPrint( "UPLOADED ANCHOR WITH ID: " + cloudanchorid + ", NAME: " + name); final currentAnchor = pendingAnchors.where((element) => element.name == name).first; @@ -72,12 +70,10 @@ class ARAnchorManager { return serializedAnchor["name"]; } default: - if (debug) { - print('Unimplemented method ${call.method} '); - } + debugPrint('Unimplemented method ${call.method} '); } } catch (e) { - print('Error caught: ' + e.toString()); + debugPrint('Error caught: ' + e.toString()); } return Future.value(); } @@ -86,7 +82,7 @@ class ARAnchorManager { Future addAnchor(ARAnchor anchor) async { try { return await _channel.invokeMethod('addAnchor', anchor.toJson()); - } on PlatformException catch (e) { + } on PlatformException { return false; } } @@ -103,15 +99,16 @@ class ARAnchorManager { await _channel.invokeMethod('uploadAnchor', anchor.toJson()); pendingAnchors.add(anchor); return response; - } on PlatformException catch (e) { + } on PlatformException { return false; } } /// Try to download anchor with the given ID from the Google Cloud Anchor API and add it to the scene Future downloadAnchor(String cloudanchorid) async { - print("TRYING TO DOWNLOAD ANCHOR WITH ID " + cloudanchorid); + debugPrint("TRYING TO DOWNLOAD ANCHOR WITH ID " + cloudanchorid); _channel .invokeMethod('downloadAnchor', {"cloudanchorid": cloudanchorid}); + return null; } } diff --git a/lib/managers/ar_location_manager.dart b/lib/managers/ar_location_manager.dart index c6384079..b4cbd256 100644 --- a/lib/managers/ar_location_manager.dart +++ b/lib/managers/ar_location_manager.dart @@ -1,4 +1,5 @@ import 'dart:async'; + import 'package:geolocator/geolocator.dart'; /// Can be used to get the current location of the device, update it and handle location permissions @@ -77,9 +78,10 @@ class ARLocationManager { // When we reach here, permissions are granted and we can // continue accessing the position of the device. - locationStream = - Geolocator.getPositionStream(locationSettings: LocationSettings(accuracy: LocationAccuracy.high)) - .listen((Position position) { + locationStream = Geolocator.getPositionStream( + locationSettings: + const LocationSettings(accuracy: LocationAccuracy.high)) + .listen((Position position) { //print(position.latitude.toString() + ', ' + position.longitude.toString()); currentLocation = position; }); diff --git a/lib/managers/ar_object_manager.dart b/lib/managers/ar_object_manager.dart index d5e72d33..b42d2a93 100644 --- a/lib/managers/ar_object_manager.dart +++ b/lib/managers/ar_object_manager.dart @@ -1,10 +1,8 @@ -import 'dart:typed_data'; - import 'package:ar_flutter_plugin/models/ar_anchor.dart'; import 'package:ar_flutter_plugin/models/ar_node.dart'; import 'package:ar_flutter_plugin/utils/json_converters.dart'; +import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; -import 'package:vector_math/vector_math_64.dart'; // Type definitions to enforce a consistent use of the API typedef NodeTapResultHandler = void Function(List nodes); @@ -35,19 +33,17 @@ class ARObjectManager { ARObjectManager(int id, {this.debug = false}) { _channel = MethodChannel('arobjects_$id'); _channel.setMethodCallHandler(_platformCallHandler); - if (debug) { - print("ARObjectManager initialized"); - } + + debugPrint("ARObjectManager initialized"); } Future _platformCallHandler(MethodCall call) { - if (debug) { - print('_platformCallHandler call ${call.method} ${call.arguments}'); - } + debugPrint('_platformCallHandler call ${call.method} ${call.arguments}'); + try { switch (call.method) { case 'onError': - print(call.arguments); + debugPrint(call.arguments); break; case 'onNodeTap': if (onNodeTap != null) { @@ -74,8 +70,8 @@ class ARObjectManager { case 'onPanEnd': if (onPanEnd != null) { final tappedNodeName = call.arguments["name"] as String; - final transform = - MatrixConverter().fromJson(call.arguments['transform'] as List); + final transform = const MatrixConverter() + .fromJson(call.arguments['transform'] as List); // Notify callback onPanEnd!(tappedNodeName, transform); @@ -96,20 +92,18 @@ class ARObjectManager { case 'onRotationEnd': if (onRotationEnd != null) { final tappedNodeName = call.arguments["name"] as String; - final transform = - MatrixConverter().fromJson(call.arguments['transform'] as List); + final transform = const MatrixConverter() + .fromJson(call.arguments['transform'] as List); // Notify callback onRotationEnd!(tappedNodeName, transform); } break; default: - if (debug) { - print('Unimplemented method ${call.method} '); - } + debugPrint('Unimplemented method ${call.method} '); } } catch (e) { - print('Error caught: ' + e.toString()); + debugPrint('Error caught: ' + e.toString()); } return Future.value(); } @@ -125,8 +119,8 @@ class ARObjectManager { node.transformNotifier.addListener(() { _channel.invokeMethod('transformationChanged', { 'name': node.name, - 'transformation': - MatrixValueNotifierConverter().toJson(node.transformNotifier) + 'transformation': const MatrixValueNotifierConverter() + .toJson(node.transformNotifier) }); }); if (planeAnchor != null) { @@ -136,7 +130,7 @@ class ARObjectManager { } else { return await _channel.invokeMethod('addNode', node.toMap()); } - } on PlatformException catch (e) { + } on PlatformException { return false; } } diff --git a/lib/managers/ar_session_manager.dart b/lib/managers/ar_session_manager.dart index 20d3b83a..233a1cf0 100644 --- a/lib/managers/ar_session_manager.dart +++ b/lib/managers/ar_session_manager.dart @@ -33,9 +33,8 @@ class ARSessionManager { {this.debug = false}) { _channel = MethodChannel('arsession_$id'); _channel.setMethodCallHandler(_platformCallHandler); - if (debug) { - print("ARSessionManager initialized"); - } + + debugPrint("ARSessionManager initialized"); } /// Returns the camera pose in Matrix4 format with respect to the world coordinate system of the [ARView] @@ -43,9 +42,9 @@ class ARSessionManager { try { final serializedCameraPose = await _channel.invokeMethod>('getCameraPose', {}); - return MatrixConverter().fromJson(serializedCameraPose!); + return const MatrixConverter().fromJson(serializedCameraPose!); } catch (e) { - print('Error caught: ' + e.toString()); + debugPrint('Error caught: ' + e.toString()); return null; } } @@ -60,9 +59,9 @@ class ARSessionManager { await _channel.invokeMethod>('getAnchorPose', { "anchorId": anchor.name, }); - return MatrixConverter().fromJson(serializedCameraPose!); + return const MatrixConverter().fromJson(serializedCameraPose!); } catch (e) { - print('Error caught: ' + e.toString()); + debugPrint('Error caught: ' + e.toString()); return null; } } @@ -104,40 +103,32 @@ class ARSessionManager { } Future _platformCallHandler(MethodCall call) { - if (debug) { - print('_platformCallHandler call ${call.method} ${call.arguments}'); - } + debugPrint('_platformCallHandler call ${call.method} ${call.arguments}'); + try { switch (call.method) { case 'onError': - if (onError != null) { - onError(call.arguments[0]); - print(call.arguments); - } + onError(call.arguments[0]); + debugPrint(call.arguments); break; case 'onPlaneOrPointTap': - if (onPlaneOrPointTap != null) { - final rawHitTestResults = call.arguments as List; - final serializedHitTestResults = rawHitTestResults - .map( - (hitTestResult) => Map.from(hitTestResult)) - .toList(); - final hitTestResults = serializedHitTestResults.map((e) { - return ARHitTestResult.fromJson(e); - }).toList(); - onPlaneOrPointTap(hitTestResults); - } + final rawHitTestResults = call.arguments as List; + final serializedHitTestResults = rawHitTestResults + .map((hitTestResult) => Map.from(hitTestResult)) + .toList(); + final hitTestResults = serializedHitTestResults.map((e) { + return ARHitTestResult.fromJson(e); + }).toList(); + onPlaneOrPointTap(hitTestResults); break; case 'dispose': _channel.invokeMethod("dispose"); break; default: - if (debug) { - print('Unimplemented method ${call.method} '); - } + debugPrint('Unimplemented method ${call.method} '); } } catch (e) { - print('Error caught: ' + e.toString()); + debugPrint('Error caught: ' + e.toString()); } return Future.value(); } @@ -184,7 +175,7 @@ class ARSessionManager { try { await _channel.invokeMethod("dispose"); } catch (e) { - print(e); + debugPrint(e.toString()); } } diff --git a/lib/models/ar_anchor.dart b/lib/models/ar_anchor.dart index 4ab87e84..55efe382 100644 --- a/lib/models/ar_anchor.dart +++ b/lib/models/ar_anchor.dart @@ -1,7 +1,5 @@ import 'package:ar_flutter_plugin/datatypes/anchor_types.dart'; -import 'package:ar_flutter_plugin/models/ar_node.dart'; import 'package:ar_flutter_plugin/utils/json_converters.dart'; -import 'package:vector_math/vector_math_64.dart'; import 'package:flutter/widgets.dart'; /// Object attached to a tracked physical entity of the AR environment (can be initialized with a world transformation) @@ -42,10 +40,9 @@ class ARPlaneAnchor extends ARAnchor { required Matrix4 transformation, String? name, List? childNodes, - String? cloudanchorid, + cloudanchorid, int? ttl, }) : childNodes = childNodes ?? [], - cloudanchorid = cloudanchorid ?? null, ttl = ttl ?? 1, super( type: AnchorType.plane, transformation: transformation, name: name); @@ -85,7 +82,7 @@ ARPlaneAnchor aRPlaneAnchorFromJson(Map json) { Map aRPlaneAnchorToJson(ARPlaneAnchor instance) { return { 'type': instance.type.index, - 'transformation': MatrixConverter().toJson(instance.transformation), + 'transformation': const MatrixConverter().toJson(instance.transformation), 'name': instance.name, 'childNodes': instance.childNodes, 'cloudanchorid': instance.cloudanchorid, @@ -118,7 +115,7 @@ ARUnkownAnchor aRUnkownAnchorFromJson(Map json) { Map aRUnkownAnchorToJson(ARUnkownAnchor instance) { return { 'type': instance.type.index, - 'transformation': MatrixConverter().toJson(instance.transformation), + 'transformation': const MatrixConverter().toJson(instance.transformation), 'name': instance.name, }; } diff --git a/lib/models/ar_node.dart b/lib/models/ar_node.dart index 7320b8a4..ee3a7887 100644 --- a/lib/models/ar_node.dart +++ b/lib/models/ar_node.dart @@ -1,11 +1,12 @@ // The code in this file is adapted from Oleksandr Leuschenko' ARKit Flutter Plugin (https://github.com/olexale/arkit_flutter_plugin) +import 'dart:math' as math; + +import 'package:ar_flutter_plugin/datatypes/node_types.dart'; import 'package:ar_flutter_plugin/utils/json_converters.dart'; import 'package:flutter/widgets.dart'; -import 'package:vector_math/vector_math_64.dart'; import 'package:json_annotation/json_annotation.dart'; -import 'dart:math' as math; -import 'package:ar_flutter_plugin/datatypes/node_types.dart'; +import 'package:vector_math/vector_math_64.dart'; /// ARNode is the model class for node-tree objects. /// It encapsulates the position, rotations, and other transforms of a node, which define a coordinate system. @@ -20,11 +21,10 @@ class ARNode { Vector4? rotation, Vector3? eulerAngles, Matrix4? transformation, - Map? data, + data, }) : name = name ?? UniqueKey().toString(), transformNotifier = ValueNotifier(createTransformMatrix( - transformation, position, scale, rotation, eulerAngles)), - data = data ?? null; + transformation, position, scale, rotation, eulerAngles)); /// Specifies the receiver's [NodeType] NodeType type; @@ -110,7 +110,7 @@ class ARNode { type: NodeType.values[map["type"]], uri: map["uri"] as String, name: map["name"] as String, - transformation: MatrixConverter().fromJson(map["transformation"]), + transformation: const MatrixConverter().fromJson(map["transformation"]), data: Map.from(map["data"])); } } diff --git a/lib/widgets/ar_view.dart b/lib/widgets/ar_view.dart index 8a8844db..a1ef8edf 100644 --- a/lib/widgets/ar_view.dart +++ b/lib/widgets/ar_view.dart @@ -1,11 +1,11 @@ +import 'package:ar_flutter_plugin/datatypes/config_planedetection.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:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:permission_handler/permission_handler.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/datatypes/config_planedetection.dart'; // Type definitions to enforce a consistent use of the API typedef ARViewCreatedCallback = void Function( @@ -60,7 +60,7 @@ class AndroidARView implements PlatformARView { @override void onPlatformViewCreated(int id) { - print("Android platform view created!"); + debugPrint("Android platform view created!"); createManagers(id, _context, _arViewCreatedCallback, _planeDetectionConfig); } @@ -73,7 +73,7 @@ class AndroidARView implements PlatformARView { _arViewCreatedCallback = arViewCreatedCallback; _planeDetectionConfig = planeDetectionConfig; // This is used in the platform side to register the view. - final String viewType = 'ar_flutter_plugin'; + const String viewType = 'ar_flutter_plugin'; // Pass parameters to the platform side. final Map creationParams = {}; @@ -95,7 +95,7 @@ class IosARView implements PlatformARView { @override void onPlatformViewCreated(int id) { - print("iOS platform view created!"); + debugPrint("iOS platform view created!"); createManagers(id, _context, _arViewCreatedCallback, _planeDetectionConfig); } @@ -108,7 +108,7 @@ class IosARView implements PlatformARView { _arViewCreatedCallback = arViewCreatedCallback; _planeDetectionConfig = planeDetectionConfig; // This is used in the platform side to register the view. - final String viewType = 'ar_flutter_plugin'; + const String viewType = 'ar_flutter_plugin'; // Pass parameters to the platform side. final Map creationParams = {}; @@ -142,7 +142,7 @@ class ARView extends StatefulWidget { /// Configures whether or not to display the device's platform type above the AR view. Defaults to false final bool showPlatformType; - ARView( + const ARView( {Key? key, required this.onARViewCreated, this.planeDetectionConfig = PlaneDetectionConfig.none, @@ -154,30 +154,25 @@ class ARView extends StatefulWidget { "Camera permission is restriced by the OS, please check parental control settings"}) : super(key: key); @override - _ARViewState createState() => _ARViewState( - showPlatformType: this.showPlatformType, - permissionPromptDescription: this.permissionPromptDescription, - permissionPromptButtonText: this.permissionPromptButtonText, - permissionPromptParentalRestriction: - this.permissionPromptParentalRestriction); + _ARViewState createState() => _ARViewState(); } class _ARViewState extends State { PermissionStatus _cameraPermission = PermissionStatus.denied; - bool showPlatformType; - String permissionPromptDescription; - String permissionPromptButtonText; - String permissionPromptParentalRestriction; - - _ARViewState( - {required this.showPlatformType, - required this.permissionPromptDescription, - required this.permissionPromptButtonText, - required this.permissionPromptParentalRestriction}); + late bool showPlatformType; + late String permissionPromptDescription; + late String permissionPromptButtonText; + late String permissionPromptParentalRestriction; @override void initState() { super.initState(); + showPlatformType = widget.showPlatformType; + permissionPromptDescription = widget.permissionPromptDescription; + permissionPromptButtonText = widget.permissionPromptButtonText; + permissionPromptParentalRestriction = + widget.permissionPromptParentalRestriction; + initCameraPermission(); } @@ -250,7 +245,7 @@ class _ARViewState extends State { return Center(child: Text(permissionPromptParentalRestriction)); } default: - return Text('something went wrong'); + return const Text('something went wrong'); } } } diff --git a/pubspec.yaml b/pubspec.yaml index 8a25261f..deefe1bc 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -11,14 +11,15 @@ environment: dependencies: flutter: sdk: flutter - permission_handler: ^10.1.0 - vector_math: ^2.1.1 - json_annotation: ^4.5.0 - geolocator: ^9.0.0 + permission_handler: ^10.3.0 + vector_math: ^2.1.2 + json_annotation: ^4.7.0 + geolocator: ^9.0.2 dev_dependencies: flutter_test: sdk: flutter + flutter_lints: ^1.0.4 # For information on the generic Dart part of this file, see the # following page: https://dart.dev/tools/pub/pubspec