From c20e1db7ccec00eb6f3cc63fefe6e0bbe8796298 Mon Sep 17 00:00:00 2001 From: 6y Date: Fri, 12 Jul 2024 23:42:40 +0800 Subject: [PATCH 01/69] feat: add plugin functions --- .github/FUNDING.yaml | 1 + .github/ISSUE_TEMPLATE/Bug.yaml | 118 ++++ .github/ISSUE_TEMPLATE/FeatureRequest.yaml | 77 +++ .github/dependabot.yaml | 34 + .github/workflows/stale.yaml | 21 + .gitignore | 8 +- .idea/.gitignore | 4 + .idea/.name | 1 + .idea/appInsightsSettings.xml | 6 + .idea/misc.xml | 10 + .idea/modules.xml | 9 + .idea/runConfigurations/dart_format.xml | 17 + .idea/runConfigurations/example.xml | 6 + .idea/runConfigurations/flutter_analyze.xml | 17 + .../runConfigurations/flutter_pub_publish.xml | 17 + .idea/runConfigurations/pana.xml | 17 + .idea/runConfigurations/test_all.xml | 8 + .idea/vcs.xml | 11 + .metadata | 33 + CHANGELOG.md | 3 + LICENSE | 16 + README.md | 156 +++++ analysis_options.yaml | 96 +++ android/.gitignore | 9 + android/build.gradle | 69 ++ android/settings.gradle | 1 + android/src/main/AndroidManifest.xml | 3 + .../FlutterRotationSensorPlugin.kt | 127 ++++ .../FlutterRotationSensorPluginTest.kt | 4 + example/.gitignore | 26 + example/.idea/libraries/Dart_SDK.xml | 19 + example/.idea/libraries/KotlinJavaRuntime.xml | 15 + example/.idea/modules.xml | 9 + example/.idea/runConfigurations/main_dart.xml | 6 + example/.idea/workspace.xml | 36 + example/README.md | 3 + example/analysis_options.yaml | 28 + example/android/.gitignore | 13 + example/android/.idea/.gitignore | 3 + example/android/.idea/codeStyles/Project.xml | 117 ++++ .../.idea/codeStyles/codeStyleConfig.xml | 5 + example/android/.idea/compiler.xml | 6 + .../.idea/deploymentTargetDropDown.xml | 10 + .../.idea/deploymentTargetSelector.xml | 10 + example/android/.idea/gradle.xml | 34 + example/android/.idea/kotlinc.xml | 6 + example/android/.idea/migrations.xml | 10 + example/android/.idea/misc.xml | 9 + example/android/.idea/other.xml | 263 ++++++++ example/android/.idea/vcs.xml | 6 + example/android/app/build.gradle | 55 ++ .../android/app/src/debug/AndroidManifest.xml | 7 + .../android/app/src/main/AndroidManifest.xml | 45 ++ .../MainActivity.kt | 5 + .../res/drawable-v21/launch_background.xml | 12 + .../main/res/drawable/launch_background.xml | 12 + .../src/main/res/mipmap-hdpi/ic_launcher.png | Bin 0 -> 544 bytes .../src/main/res/mipmap-mdpi/ic_launcher.png | Bin 0 -> 442 bytes .../src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 0 -> 721 bytes .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin 0 -> 1031 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin 0 -> 1443 bytes .../app/src/main/res/values-night/styles.xml | 18 + .../app/src/main/res/values/styles.xml | 18 + .../app/src/profile/AndroidManifest.xml | 7 + example/android/build.gradle | 18 + ...lutter_rotation_sensor_example_android.iml | 29 + example/android/gradle.properties | 3 + .../gradle/wrapper/gradle-wrapper.properties | 5 + example/android/settings.gradle | 25 + example/assets/images/other.png | Bin 0 -> 8013 bytes example/assets/images/top.png | Bin 0 -> 23270 bytes example/flutter_rotation_sensor_example.iml | 17 + example/ios/.gitignore | 34 + example/ios/Flutter/AppFrameworkInfo.plist | 26 + example/ios/Flutter/Debug.xcconfig | 1 + example/ios/Flutter/Release.xcconfig | 1 + example/ios/Runner.xcodeproj/project.pbxproj | 616 ++++++++++++++++++ .../contents.xcworkspacedata | 7 + .../xcshareddata/IDEWorkspaceChecks.plist | 8 + .../xcshareddata/WorkspaceSettings.xcsettings | 8 + .../xcshareddata/xcschemes/Runner.xcscheme | 98 +++ .../contents.xcworkspacedata | 7 + .../xcshareddata/IDEWorkspaceChecks.plist | 8 + .../xcshareddata/WorkspaceSettings.xcsettings | 8 + example/ios/Runner/AppDelegate.swift | 13 + .../AppIcon.appiconset/Contents.json | 122 ++++ .../Icon-App-1024x1024@1x.png | Bin 0 -> 10932 bytes .../AppIcon.appiconset/Icon-App-20x20@1x.png | Bin 0 -> 295 bytes .../AppIcon.appiconset/Icon-App-20x20@2x.png | Bin 0 -> 406 bytes .../AppIcon.appiconset/Icon-App-20x20@3x.png | Bin 0 -> 450 bytes .../AppIcon.appiconset/Icon-App-29x29@1x.png | Bin 0 -> 282 bytes .../AppIcon.appiconset/Icon-App-29x29@2x.png | Bin 0 -> 462 bytes .../AppIcon.appiconset/Icon-App-29x29@3x.png | Bin 0 -> 704 bytes .../AppIcon.appiconset/Icon-App-40x40@1x.png | Bin 0 -> 406 bytes .../AppIcon.appiconset/Icon-App-40x40@2x.png | Bin 0 -> 586 bytes .../AppIcon.appiconset/Icon-App-40x40@3x.png | Bin 0 -> 862 bytes .../AppIcon.appiconset/Icon-App-60x60@2x.png | Bin 0 -> 862 bytes .../AppIcon.appiconset/Icon-App-60x60@3x.png | Bin 0 -> 1674 bytes .../AppIcon.appiconset/Icon-App-76x76@1x.png | Bin 0 -> 762 bytes .../AppIcon.appiconset/Icon-App-76x76@2x.png | Bin 0 -> 1226 bytes .../Icon-App-83.5x83.5@2x.png | Bin 0 -> 1418 bytes .../LaunchImage.imageset/Contents.json | 23 + .../LaunchImage.imageset/LaunchImage.png | Bin 0 -> 68 bytes .../LaunchImage.imageset/LaunchImage@2x.png | Bin 0 -> 68 bytes .../LaunchImage.imageset/LaunchImage@3x.png | Bin 0 -> 68 bytes .../LaunchImage.imageset/README.md | 5 + .../Runner/Base.lproj/LaunchScreen.storyboard | 37 ++ example/ios/Runner/Base.lproj/Main.storyboard | 26 + example/ios/Runner/Info.plist | 49 ++ example/ios/Runner/Runner-Bridging-Header.h | 1 + example/ios/RunnerTests/RunnerTests.swift | 26 + example/lib/main.dart | 173 +++++ example/pubspec.lock | 315 +++++++++ example/pubspec.yaml | 29 + flutter_rotation_sensor.iml | 19 + ios/.gitignore | 38 ++ ios/Assets/.gitkeep | 0 ios/Classes/FlutterRotationSensorPlugin.swift | 66 ++ ios/flutter_rotation_sensor.podspec | 30 + lib/flutter_rotation_sensor.dart | 10 + lib/src/coordinate_system.dart | 129 ++++ lib/src/math/axis3.dart | 40 ++ lib/src/math/axis_angle.dart | 27 + lib/src/math/euler_angles.dart | 88 +++ lib/src/math/matrix3.dart | 266 ++++++++ lib/src/math/quaternion.dart | 158 +++++ lib/src/math/vector3.dart | 82 +++ lib/src/orientation_event.dart | 110 ++++ lib/src/rotation_sensor.dart | 49 ++ lib/src/rotation_sensor_method_channel.dart | 51 ++ .../rotation_sensor_platform_interface.dart | 75 +++ lib/src/sensor_interval.dart | 25 + pubspec.yaml | 43 ++ test/coordinate_system_test.dart | 175 +++++ test/coordinate_system_test.mocks.dart | 93 +++ test/math/axis3_test.dart | 49 ++ test/math/axis_angle_test.dart | 27 + test/math/euler_angles_test.dart | 97 +++ test/math/matrix3_test.dart | 248 +++++++ test/math/quaternion_test.dart | 127 ++++ test/math/vector3_test.dart | 80 +++ test/orientation_event_test.dart | 271 ++++++++ test/rotation_sensor_method_channel_test.dart | 81 +++ test/rotation_sensor_test.dart | 57 ++ test/utils.dart | 59 ++ 145 files changed, 6117 insertions(+), 3 deletions(-) create mode 100644 .github/FUNDING.yaml create mode 100644 .github/ISSUE_TEMPLATE/Bug.yaml create mode 100644 .github/ISSUE_TEMPLATE/FeatureRequest.yaml create mode 100644 .github/dependabot.yaml create mode 100644 .github/workflows/stale.yaml create mode 100644 .idea/.gitignore create mode 100644 .idea/.name create mode 100644 .idea/appInsightsSettings.xml create mode 100644 .idea/misc.xml create mode 100644 .idea/modules.xml create mode 100644 .idea/runConfigurations/dart_format.xml create mode 100644 .idea/runConfigurations/example.xml create mode 100644 .idea/runConfigurations/flutter_analyze.xml create mode 100644 .idea/runConfigurations/flutter_pub_publish.xml create mode 100644 .idea/runConfigurations/pana.xml create mode 100644 .idea/runConfigurations/test_all.xml create mode 100644 .idea/vcs.xml create mode 100644 .metadata create mode 100644 CHANGELOG.md create mode 100644 LICENSE create mode 100644 README.md create mode 100644 analysis_options.yaml create mode 100644 android/.gitignore create mode 100644 android/build.gradle create mode 100644 android/settings.gradle create mode 100644 android/src/main/AndroidManifest.xml create mode 100644 android/src/main/kotlin/net/tlserver6y/flutter_rotation_sensor/FlutterRotationSensorPlugin.kt create mode 100644 android/src/test/kotlin/net/tlserver6y/flutter_rotation_sensor/FlutterRotationSensorPluginTest.kt create mode 100644 example/.gitignore create mode 100644 example/.idea/libraries/Dart_SDK.xml create mode 100644 example/.idea/libraries/KotlinJavaRuntime.xml create mode 100644 example/.idea/modules.xml create mode 100644 example/.idea/runConfigurations/main_dart.xml create mode 100644 example/.idea/workspace.xml create mode 100644 example/README.md create mode 100644 example/analysis_options.yaml create mode 100644 example/android/.gitignore create mode 100644 example/android/.idea/.gitignore create mode 100644 example/android/.idea/codeStyles/Project.xml create mode 100644 example/android/.idea/codeStyles/codeStyleConfig.xml create mode 100644 example/android/.idea/compiler.xml create mode 100644 example/android/.idea/deploymentTargetDropDown.xml create mode 100644 example/android/.idea/deploymentTargetSelector.xml create mode 100644 example/android/.idea/gradle.xml create mode 100644 example/android/.idea/kotlinc.xml create mode 100644 example/android/.idea/migrations.xml create mode 100644 example/android/.idea/misc.xml create mode 100644 example/android/.idea/other.xml create mode 100644 example/android/.idea/vcs.xml create mode 100644 example/android/app/build.gradle create mode 100644 example/android/app/src/debug/AndroidManifest.xml create mode 100644 example/android/app/src/main/AndroidManifest.xml create mode 100644 example/android/app/src/main/kotlin/net/tlserver6y/flutter_rotation_sensor_example/MainActivity.kt create mode 100644 example/android/app/src/main/res/drawable-v21/launch_background.xml create mode 100644 example/android/app/src/main/res/drawable/launch_background.xml create mode 100644 example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png create mode 100644 example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png create mode 100644 example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png create mode 100644 example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png create mode 100644 example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png create mode 100644 example/android/app/src/main/res/values-night/styles.xml create mode 100644 example/android/app/src/main/res/values/styles.xml create mode 100644 example/android/app/src/profile/AndroidManifest.xml create mode 100644 example/android/build.gradle create mode 100644 example/android/flutter_rotation_sensor_example_android.iml create mode 100644 example/android/gradle.properties create mode 100644 example/android/gradle/wrapper/gradle-wrapper.properties create mode 100644 example/android/settings.gradle create mode 100644 example/assets/images/other.png create mode 100644 example/assets/images/top.png create mode 100644 example/flutter_rotation_sensor_example.iml create mode 100644 example/ios/.gitignore create mode 100644 example/ios/Flutter/AppFrameworkInfo.plist create mode 100644 example/ios/Flutter/Debug.xcconfig create mode 100644 example/ios/Flutter/Release.xcconfig create mode 100644 example/ios/Runner.xcodeproj/project.pbxproj create mode 100644 example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata create mode 100644 example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings create mode 100644 example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme create mode 100644 example/ios/Runner.xcworkspace/contents.xcworkspacedata create mode 100644 example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings create mode 100644 example/ios/Runner/AppDelegate.swift create mode 100644 example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json create mode 100644 example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png create mode 100644 example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png create mode 100644 example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png create mode 100644 example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png create mode 100644 example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png create mode 100644 example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png create mode 100644 example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png create mode 100644 example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png create mode 100644 example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png create mode 100644 example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png create mode 100644 example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png create mode 100644 example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png create mode 100644 example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png create mode 100644 example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png create mode 100644 example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png create mode 100644 example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json create mode 100644 example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png create mode 100644 example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png create mode 100644 example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png create mode 100644 example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md create mode 100644 example/ios/Runner/Base.lproj/LaunchScreen.storyboard create mode 100644 example/ios/Runner/Base.lproj/Main.storyboard create mode 100644 example/ios/Runner/Info.plist create mode 100644 example/ios/Runner/Runner-Bridging-Header.h create mode 100644 example/ios/RunnerTests/RunnerTests.swift create mode 100644 example/lib/main.dart create mode 100644 example/pubspec.lock create mode 100644 example/pubspec.yaml create mode 100644 flutter_rotation_sensor.iml create mode 100644 ios/.gitignore create mode 100644 ios/Assets/.gitkeep create mode 100644 ios/Classes/FlutterRotationSensorPlugin.swift create mode 100644 ios/flutter_rotation_sensor.podspec create mode 100644 lib/flutter_rotation_sensor.dart create mode 100644 lib/src/coordinate_system.dart create mode 100644 lib/src/math/axis3.dart create mode 100644 lib/src/math/axis_angle.dart create mode 100644 lib/src/math/euler_angles.dart create mode 100644 lib/src/math/matrix3.dart create mode 100644 lib/src/math/quaternion.dart create mode 100644 lib/src/math/vector3.dart create mode 100644 lib/src/orientation_event.dart create mode 100644 lib/src/rotation_sensor.dart create mode 100644 lib/src/rotation_sensor_method_channel.dart create mode 100644 lib/src/rotation_sensor_platform_interface.dart create mode 100644 lib/src/sensor_interval.dart create mode 100644 pubspec.yaml create mode 100644 test/coordinate_system_test.dart create mode 100644 test/coordinate_system_test.mocks.dart create mode 100644 test/math/axis3_test.dart create mode 100644 test/math/axis_angle_test.dart create mode 100644 test/math/euler_angles_test.dart create mode 100644 test/math/matrix3_test.dart create mode 100644 test/math/quaternion_test.dart create mode 100644 test/math/vector3_test.dart create mode 100644 test/orientation_event_test.dart create mode 100644 test/rotation_sensor_method_channel_test.dart create mode 100644 test/rotation_sensor_test.dart create mode 100644 test/utils.dart diff --git a/.github/FUNDING.yaml b/.github/FUNDING.yaml new file mode 100644 index 0000000..ec3e3e1 --- /dev/null +++ b/.github/FUNDING.yaml @@ -0,0 +1 @@ +github: tlserver diff --git a/.github/ISSUE_TEMPLATE/Bug.yaml b/.github/ISSUE_TEMPLATE/Bug.yaml new file mode 100644 index 0000000..380830f --- /dev/null +++ b/.github/ISSUE_TEMPLATE/Bug.yaml @@ -0,0 +1,118 @@ +name: Bug Report +description: File a report if you've encountered a bug with FlutterRotationSensor. +title: "[Bug]: " +labels: ["bug"] +body: + - type: markdown + attributes: + value: | + # 🐛 Bug Report + + Thank you for using FlutterRotationSensor! Before you submit your bug report, please: + + - Review the [documentation](https://pub.dev/documentation/flutter_map_location_marker/latest/). + - Search for similar issues in both [open and closed tickets](https://github.com/tlserver/flutter_rotation_sensor/issues?q=is%3Aissue). + - Discuss non-bug-related questions on [GitHub discussions](https://github.com/tlserver/flutter_rotation_sensor/discussions) or [Stack Overflow](https://stackoverflow.com/). + + If you're certain the issue you're experiencing is a bug, please provide as much detail as possible in this report so we can help you resolve it. + + **Note:** Bug reports not adhering to this template may be closed for incomplete information. + + - type: checkboxes + id: self-checks + attributes: + label: Preliminary Bug Check + description: Ensure you've taken these steps before submitting a bug. + options: + - label: I've searched the issue tracker for similar bug reports. + required: true + - label: I've checked Google and Stack Overflow for solutions. + required: true + - label: I've read the plugin's documentation. + required: true + - label: I'm using the latest plugin version and all dependencies are updated with `flutter pub upgrade`. + required: true + - label: I've executed `flutter clean`. + required: true + - label: I've tried running the example project. + required: true + + - type: input + id: version + attributes: + label: Plugin Version + description: What version of the plugin are you using? + placeholder: e.g., 1.0.0 + validations: + required: true + + - type: textarea + id: expected + attributes: + label: Expected Behavior + description: What did you expect to happen? + validations: + required: true + + - type: textarea + id: actual + attributes: + label: Actual Behavior + description: What actually happened? Please include as much detail as possible. + validations: + required: true + + - type: textarea + id: code + attributes: + label: Code Sample + render: dart + description: | + Provide a minimal code sample or a link to a gist that reproduces the error. Ideally, share a main.dart file that we can run to see the issue. + validations: + required: false + + - type: textarea + id: steps + attributes: + label: Steps to Reproduce + description: Detail the exact steps to reproduce the bug. + validations: + required: true + + - type: input + id: platform + attributes: + label: Platform Details + description: Which platform and version did the issue occur on (e.g., Android, iOS)? + placeholder: e.g., Android 12, iOS 14 + validations: + required: true + + - type: input + id: sdk + attributes: + label: Flutter SDK Version + description: Provide the version of the Flutter SDK you are using. + placeholder: e.g., 3.0.0 + validations: + required: true + + - type: textarea + id: logs + attributes: + label: Logs + render: shell + description: | + Attach the full output of `flutter run --verbose`. If there's an exception, ensure the log includes enough detail to diagnose the issue. + validations: + required: true + + - type: textarea + id: doctor + attributes: + label: Flutter Doctor Output + render: shell + description: What is the output of `flutter doctor -v`? This provides us with your development environment details. + validations: + required: true \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/FeatureRequest.yaml b/.github/ISSUE_TEMPLATE/FeatureRequest.yaml new file mode 100644 index 0000000..cdfa5a7 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/FeatureRequest.yaml @@ -0,0 +1,77 @@ +name: Feature Request +description: Suggest an idea or enhancement for the FlutterRotationSensor plugin. +title: "[Feature Request]: " +labels: ["enhancement"] +body: + - type: markdown + attributes: + value: | + # ✨ Feature Request + + Thank you for taking the time to suggest a feature for FlutterRotationSensor! + + Before submitting your feature request, please consider the following: + - Check if a similar feature request [has already been submitted](https://github.com/tlserver/flutter_rotation_sensor/issues?q=is%3Aissue+label%3Aenhancement). + - Review the [documentation](https://pub.dev/documentation/flutter_map_location_marker/latest/) to ensure your feature doesn't already exist. + + If you have a specific idea in mind, fill out the template below. Detailed proposals have a higher chance of being considered. + + - type: input + id: feature-summary + attributes: + label: Feature Summary + description: A short, descriptive title for your feature request. + placeholder: e.g., Support for XYZ sensor data + validations: + required: true + + - type: textarea + id: feature-description + attributes: + label: Detailed Description + description: Provide a detailed description of your feature request. What problem does it solve or functionality does it add? + validations: + required: true + + - type: textarea + id: potential-benefits + attributes: + label: Potential Benefits + description: Explain the benefits this feature would provide to users or developers. + validations: + required: true + + - type: textarea + id: possible-solutions + attributes: + label: Possible Solutions + description: If you have ideas on how to implement this feature, please share them here. + validations: + required: false + + - type: textarea + id: alternatives + attributes: + label: Alternatives Considered + description: Describe any alternative solutions or features you've considered. + validations: + required: false + + - type: textarea + id: additional-context + attributes: + label: Additional Context + description: Add any other context, links, or screenshots about the feature request here. + validations: + required: false + + - type: checkboxes + id: additional-checks + attributes: + label: Preliminary Checks + description: Ensure you've considered what's necessary before we proceed with this feature request. + options: + - label: I've checked if this feature request does not already exist. + required: true + - label: I've considered and outlined any potential impact on existing functionality. + required: true diff --git a/.github/dependabot.yaml b/.github/dependabot.yaml new file mode 100644 index 0000000..b3daaaf --- /dev/null +++ b/.github/dependabot.yaml @@ -0,0 +1,34 @@ +version: 2 +updates: + + - package-ecosystem: "pub" + directory: "/" + schedule: + interval: "weekly" + rebase-strategy: "disabled" + commit-message: + prefix: "chore" + + - package-ecosystem: "pub" + directory: "/example" + schedule: + interval: "weekly" + rebase-strategy: "disabled" + commit-message: + prefix: "chore" + + - package-ecosystem: "gradle" + directory: "/android" + schedule: + interval: "monthly" + rebase-strategy: "disabled" + commit-message: + prefix: "chore" + + - package-ecosystem: "gradle" + directory: "/example/android" + schedule: + interval: "monthly" + rebase-strategy: "disabled" + commit-message: + prefix: "chore" diff --git a/.github/workflows/stale.yaml b/.github/workflows/stale.yaml new file mode 100644 index 0000000..6f85eaf --- /dev/null +++ b/.github/workflows/stale.yaml @@ -0,0 +1,21 @@ +name: 'Stale' +on: + schedule: + - cron: '16 10 * * *' + +jobs: + stale: + runs-on: ubuntu-latest + steps: + - uses: actions/stale@v5 + with: + repo-token: ${{ github.token }} + stale-issue-message: 'This issue is stale because it has been open for 30 days with no activity. Remove stale label or comment or this will be closed in 7 days.' + stale-pr-message: 'This PR is stale because it has been open for 60 days with no activity. Remove stale label or comment or this will be closed in 14 days.' + close-issue-message: 'This issue was closed because it has been stalled for 7 days with no activity.' + close-pr-message: 'This PR was closed because it has been stalled for 14 days with no activity.' + close-issue-reason: 'not_planned' + days-before-issue-stale: 30 + days-before-issue-close: 7 + days-before-pr-stale: 60 + days-before-pr-close: 14 diff --git a/.gitignore b/.gitignore index 330dc47..a553464 100644 --- a/.gitignore +++ b/.gitignore @@ -7,7 +7,6 @@ .dart_tool/ .flutter-plugins .flutter-plugins-dependencies -.fvm/flutter_sdk .packages .pub-cache/ .pub/ @@ -17,7 +16,7 @@ lib/generated_plugin_registrant.dart # For library packages, don’t commit the pubspec.lock file. # Regenerating the pubspec.lock file lets you test your package against the latest compatible versions of its dependencies. # See https://dart.dev/guides/libraries/private-files#pubspeclock -pubspec.lock +/pubspec.lock # Android related **/android/**/gradle-wrapper.jar @@ -178,4 +177,7 @@ fabric.properties # https://plugins.jetbrains.com/plugin/8053-azure-toolkit-for-intellij .idea/**/azureSettings.xml -# End of https://www.toptal.com/developers/gitignore/api/jetbrains,flutter \ No newline at end of file +# End of https://www.toptal.com/developers/gitignore/api/jetbrains,flutter + +# FVM Version Cache +.fvm/ \ No newline at end of file diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..402e09c --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,4 @@ +# Default ignored files +/libraries/ +/shelf/ +/workspace.xml diff --git a/.idea/.name b/.idea/.name new file mode 100644 index 0000000..6177abb --- /dev/null +++ b/.idea/.name @@ -0,0 +1 @@ +FlutterRotationSensor \ No newline at end of file diff --git a/.idea/appInsightsSettings.xml b/.idea/appInsightsSettings.xml new file mode 100644 index 0000000..6bbe2ae --- /dev/null +++ b/.idea/appInsightsSettings.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..5db477d --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,10 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..caf8a4b --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/runConfigurations/dart_format.xml b/.idea/runConfigurations/dart_format.xml new file mode 100644 index 0000000..84d1ae4 --- /dev/null +++ b/.idea/runConfigurations/dart_format.xml @@ -0,0 +1,17 @@ + + + + \ No newline at end of file diff --git a/.idea/runConfigurations/example.xml b/.idea/runConfigurations/example.xml new file mode 100644 index 0000000..5650683 --- /dev/null +++ b/.idea/runConfigurations/example.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/.idea/runConfigurations/flutter_analyze.xml b/.idea/runConfigurations/flutter_analyze.xml new file mode 100644 index 0000000..3933bdd --- /dev/null +++ b/.idea/runConfigurations/flutter_analyze.xml @@ -0,0 +1,17 @@ + + + + \ No newline at end of file diff --git a/.idea/runConfigurations/flutter_pub_publish.xml b/.idea/runConfigurations/flutter_pub_publish.xml new file mode 100644 index 0000000..fd7f521 --- /dev/null +++ b/.idea/runConfigurations/flutter_pub_publish.xml @@ -0,0 +1,17 @@ + + + + \ No newline at end of file diff --git a/.idea/runConfigurations/pana.xml b/.idea/runConfigurations/pana.xml new file mode 100644 index 0000000..7133d80 --- /dev/null +++ b/.idea/runConfigurations/pana.xml @@ -0,0 +1,17 @@ + + + + \ No newline at end of file diff --git a/.idea/runConfigurations/test_all.xml b/.idea/runConfigurations/test_all.xml new file mode 100644 index 0000000..c6602dc --- /dev/null +++ b/.idea/runConfigurations/test_all.xml @@ -0,0 +1,8 @@ + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..5fc0921 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..458e07f --- /dev/null +++ b/.metadata @@ -0,0 +1,33 @@ +# This file tracks properties of this Flutter project. +# Used by Flutter tool to assess capabilities and perform upgrades etc. +# +# This file should be version controlled and should not be manually edited. + +version: + revision: "761747bfc538b5af34aa0d3fac380f1bc331ec49" + channel: "stable" + +project_type: plugin + +# Tracks metadata for the flutter migrate command +migration: + platforms: + - platform: root + create_revision: 761747bfc538b5af34aa0d3fac380f1bc331ec49 + base_revision: 761747bfc538b5af34aa0d3fac380f1bc331ec49 + - platform: android + create_revision: 761747bfc538b5af34aa0d3fac380f1bc331ec49 + base_revision: 761747bfc538b5af34aa0d3fac380f1bc331ec49 + - platform: ios + create_revision: 761747bfc538b5af34aa0d3fac380f1bc331ec49 + base_revision: 761747bfc538b5af34aa0d3fac380f1bc331ec49 + + # User provided section + + # List of Local paths (relative to this file) that should be + # ignored by the migrate tool. + # + # Files that are not part of the templates will be ignored by default. + unmanaged_files: + - 'lib/main.dart' + - 'ios/Runner.xcodeproj/project.pbxproj' diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..41cc7d8 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,3 @@ +## 0.0.1 + +* TODO: Describe initial release. diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..68950d0 --- /dev/null +++ b/LICENSE @@ -0,0 +1,16 @@ +Copyright (c) 2024 tlserver6y.net + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and +associated documentation files (the "Software"), to deal in the Software without restriction, +including without limitation the rights to use, copy, modify, merge, publish, distribute, +sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial +portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT +NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES +OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..1f928d2 --- /dev/null +++ b/README.md @@ -0,0 +1,156 @@ +# flutter_rotation_sensor + +[![pub package](https://img.shields.io/pub/v/rotation_sensor)](https://pub.dartlang.org/packages/rotation_sensor) +[![github tag](https://img.shields.io/github/v/tag/tlserver/flutter_rotation_sensor?include_prereleases&sort=semver)](https://github.com/tlserver/flutter_rotation_sensor) +[![license](https://img.shields.io/github/license/tlserver/flutter_rotation_sensor)](https://github.com/tlserver/flutter_rotation_sensor/blob/master/LICENSE) + +The `flutter_rotation_sensor` plugin provides easy access to the device's physical orientation in +three distinct representations: rotation matrix, quaternion, and Euler angles (azimuth, pitch, +roll). This is ideal for applications requiring precise tracking of the device's movement or +orientation in space, such as augmented reality, gaming, navigation, and more. + +## Features + +- **Real-time Rotation Data**: Access to real-time rotation data. +- **Multiple Formats Supported**: Provides rotation matrix, quaternion, and Euler angles (azimuth, + pitch, roll). +- **Customizable Update Intervals**: Set custom intervals for sensor data retrieval. +- **Coordinate System Remapping**: Supports orientation coordinate system remapping. + +## Installation + +To add `flutter_rotation_sensor` to your project, follow these steps: + +1. Add `flutter_rotation_sensor` as a dependency in your `pubspec.yaml` file: + ```yaml + dependencies: + flutter_rotation_sensor: ^latest_version + ``` + +2. Install the plugin by running: + ```sh + flutter pub get + ``` + +3. Import the plugin in your Dart code: + ```dart + import 'package:flutter_rotation_sensor/flutter_rotation_sensor.dart'; + ``` + +## Usage + +To start receiving orientation data from the sensors, simply use the stream in a `StreamBuilder`: + +```dart +@override +Widget build(BuildContext context) { + return StreamBuilder( + stream: RotationSensor.orientationStream, + builder: (context, snapshot) { + if (snapshot.hasData) { + final data = snapshot.data!; + print(data.quaternion); + print(data.rotationMatrix); + print(data.eulerAngles); + // ... + } else if (snapshot.hasError) { + return Text('Error: ${snapshot.error}'); + } else { + return const CircularProgressIndicator(); + } + }, + ); +} +``` + +For more control, you can subscribe to the stream directly: + +1. Initialize the sensor and specify the desired update interval during `initState`: + ```dart + late final StreamSubscription orientationSubscription; + + @override + void initState() { + super.initState(); + orientationSubscription = RotationSensor.orientationStream.listen((event) { + final azimuth = event.eulerAngles.azimuth; + // Print azimuth: 0 for North, π/2 for East, π for South, -π/2 for West + print(azimuth); + }); + } + ``` + +2. Remember to cancel the subscription in the `dispose` method to prevent memory leaks: + ```dart + @override + void dispose() { + orientationSubscription.cancel(); + super.dispose(); + } + ``` + +## Configuration + +To configure the `flutter_rotation_sensor` plugin, you can set various properties at any time, such +as in your `initState` method. Below is an example demonstrating how to configure these settings: + +```dart +@override +void initState() { + super.initState(); + // Set the sampling period for the rotation sensor + RotationSensor.samplingPeriod = SensorInterval.uiInterval; + + // Set the coordinate system for the rotation sensor + RotationSensor.coordinateSystem = CoordinateSystem.transformed(Axis3.X, Axis3.Z); +} +``` + +### Sampling Period + +The [RotationSensor.samplingPeriod](https://pub.dev/documentation/flutter_rotation_sensor/latest/flutter_rotation_sensor/RotationSensor/samplingPeriod.html) +determines how frequently the sensor data is updated. Here are the predefined values you can use: + +- `SensorInterval.normal` (200ms): Default rate, suitable for general use. +- `SensorInterval.ui` (66ms): Suitable for UI updates, balancing update rate and power consumption. +- `SensorInterval.game` (20ms): Suitable for games, updating at a rate to ensure smooth motion. +- `SensorInterval.fastest` (0ms): Updates as fast as possible. + +You can also set a custom [Duration](https://api.dart.dev/stable/dart-core/Duration-class.html), for +example: + +```dart +void config() { + RotationSensor.samplingPeriod = Duration(seconds: 1); +} +``` + +Events may arrive at a rate faster or slower than the sampling period, which is only a hint to the +system. The actual rate depends on the system's event queue and sensor hardware capabilities. + +### Coordinate System + +The [RotationSensor.coordinateSystem](https://pub.dev/documentation/flutter_rotation_sensor/latest/flutter_rotation_sensor/RotationSensor/coordinateSystem.html) +property allows you to remap the coordinate system used by the sensor data. By default, the +coordinate system follows the display's orientation. You can transform the coordinate system to +match your application's needs. Here are the predefined coordinate systems you can use: + +- `CoordinateSystem.device()`: Defined relative to the device's screen in its default orientation. +- `CoordinateSystem.display()`: *(default value)* Adapts to the device's current orientation. +- `CoordinateSystem.transformed()`: Applies a transformation on top of a base coordinate system. + +For example, a driving navigation application may want a transformed coordinate system where the +y-axis points to the back of the device. This ensures that the plugin can return the azimuth +correctly when the device is mounted in front of the driver. + +```dart +void config() { + // The new x-axis is same as old x-axis and the new y-axis is the old negative-z-axis which points + // to the back of the device. + RotationSensor.coordinateSystem = CoordinateSystem.transformed(Axis3.X, -Axis3.Z); +} +``` + +## License + +This plugin is licensed under the [MIT License](LICENSE). diff --git a/analysis_options.yaml b/analysis_options.yaml new file mode 100644 index 0000000..1d0804c --- /dev/null +++ b/analysis_options.yaml @@ -0,0 +1,96 @@ +# This file configures the analyzer to use the lint rule set from `package:lint` +include: package:flutter_lints/flutter.yaml + +linter: + rules: + - avoid_dynamic_calls + - cancel_subscriptions + - close_sinks + - comment_references + - deprecated_member_use_from_same_package + - diagnostic_describe_all_properties + - literal_only_boolean_expressions + - no_self_assignments + - no_wildcard_variable_uses + - prefer_relative_imports + - prefer_void_to_null + - test_types_in_equals + - throw_in_finally + - unnecessary_statements + + - avoid_bool_literals_in_conditional_expressions + - avoid_catches_without_on_clauses + - avoid_catching_errors + - avoid_double_and_int_checks + - avoid_equals_and_hash_code_on_mutable_classes + - avoid_escaping_inner_quotes + - avoid_final_parameters + - avoid_implementing_value_types + - avoid_js_rounded_ints + - avoid_multiple_declarations_per_line + - avoid_positional_boolean_parameters + - avoid_redundant_argument_values + - avoid_returning_this + - avoid_setters_without_getters + - avoid_types_on_closure_parameters + - avoid_unused_constructor_parameters + - avoid_void_async + - cascade_invocations + - cast_nullable_to_non_nullable + - combinators_ordering + - conditional_uri_does_not_exist + - deprecated_consistency + - directives_ordering + - do_not_use_environment + - eol_at_end_of_file + - join_return_with_assignment + - leading_newlines_in_multiline_strings + - library_annotations + - lines_longer_than_80_chars + - matching_super_parameters + - missing_whitespace_between_adjacent_strings + - no_literal_bool_comparisons + - no_runtimeType_toString + - noop_primitive_operations + - omit_local_variable_types + - one_member_abstracts + - only_throw_errors + - prefer_asserts_in_initializer_lists + - prefer_asserts_with_message + - prefer_constructors_over_static_methods + - prefer_expression_function_bodies + - prefer_final_fields + - prefer_final_in_for_each + - prefer_foreach + - prefer_if_elements_to_conditional_expressions + - prefer_int_literals + - prefer_mixin + - prefer_null_aware_method_calls + - prefer_single_quotes + - require_trailing_commas + - sized_box_shrink_expand + - sort_unnamed_constructors_first + - tighten_type_of_initializing_formals + - type_annotate_public_apis + - unawaited_futures + - unnecessary_await_in_return + - unnecessary_breaks + - unnecessary_lambdas + - unnecessary_library_directive + - unnecessary_null_aware_operator_on_extension_on_nullable + - unnecessary_parenthesis + - unnecessary_raw_strings + - unreachable_from_main + - use_colored_box + - use_decorated_box + - use_enums + - use_if_null_to_convert_nulls_to_bools + - use_is_even_rather_than_modulo + - use_named_constants + - use_raw_strings + - use_setters_to_change_properties + - use_string_buffers + - use_test_throws_matchers + - use_to_and_as_if_applicable + + - sort_pub_dependencies diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..161bdcd --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,9 @@ +*.iml +.gradle +/local.properties +/.idea/workspace.xml +/.idea/libraries +.DS_Store +/build +/captures +.cxx diff --git a/android/build.gradle b/android/build.gradle new file mode 100644 index 0000000..55e2565 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,69 @@ +group 'net.tlserver6y.flutter_rotation_sensor' +version '1.0-SNAPSHOT' + +buildscript { + ext.agp_version = '8.5.1' + ext.kotlin_version = '2.0.0' + repositories { + google() + mavenCentral() + } + + dependencies { + classpath "com.android.tools.build:gradle:$agp_version" + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + mavenCentral() + } +} + +apply plugin: 'com.android.library' +apply plugin: 'kotlin-android' + +android { + if (project.android.hasProperty("namespace")) { + namespace 'net.tlserver6y.flutter_rotation_sensor' + } + + compileSdk = 34 + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + + kotlinOptions { + jvmTarget = '1.8' + } + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + test.java.srcDirs += 'src/test/kotlin' + } + + defaultConfig { + minSdk = 19 + } + + dependencies { + testImplementation 'org.jetbrains.kotlin:kotlin-test' + testImplementation 'org.mockito:mockito-core:5.12.0' + } + + testOptions { + unitTests.all { + useJUnitPlatform() + + testLogging { + events "passed", "skipped", "failed", "standardOut", "standardError" + outputs.upToDateWhen {false} + showStandardStreams = true + } + } + } +} diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..e792a4c --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1 @@ +rootProject.name = 'flutter_rotation_sensor' diff --git a/android/src/main/AndroidManifest.xml b/android/src/main/AndroidManifest.xml new file mode 100644 index 0000000..2bdd789 --- /dev/null +++ b/android/src/main/AndroidManifest.xml @@ -0,0 +1,3 @@ + + diff --git a/android/src/main/kotlin/net/tlserver6y/flutter_rotation_sensor/FlutterRotationSensorPlugin.kt b/android/src/main/kotlin/net/tlserver6y/flutter_rotation_sensor/FlutterRotationSensorPlugin.kt new file mode 100644 index 0000000..1bc1a87 --- /dev/null +++ b/android/src/main/kotlin/net/tlserver6y/flutter_rotation_sensor/FlutterRotationSensorPlugin.kt @@ -0,0 +1,127 @@ +package net.tlserver6y.flutter_rotation_sensor + +import android.content.Context +import android.hardware.Sensor +import android.hardware.SensorEvent +import android.hardware.SensorEventListener +import android.hardware.SensorManager +import io.flutter.embedding.engine.plugins.FlutterPlugin +import io.flutter.plugin.common.BinaryMessenger +import io.flutter.plugin.common.EventChannel +import io.flutter.plugin.common.EventChannel.EventSink +import io.flutter.plugin.common.EventChannel.StreamHandler +import io.flutter.plugin.common.MethodCall +import io.flutter.plugin.common.MethodChannel +import io.flutter.plugin.common.MethodChannel.MethodCallHandler +import io.flutter.plugin.common.MethodChannel.Result + +class FlutterRotationSensorPlugin : FlutterPlugin, MethodCallHandler, StreamHandler { + private lateinit var methodChannel: MethodChannel + private lateinit var eventChannel: EventChannel + private lateinit var sensorManager: SensorManager + private var sensor: Sensor? = null + private var sensorEventListener: SensorEventListener? = null + private var samplingPeriod = 200000 + + override fun onAttachedToEngine(flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) { + sensorManager = + flutterPluginBinding.applicationContext.getSystemService(Context.SENSOR_SERVICE) as SensorManager + sensor = sensorManager.getDefaultSensor(Sensor.TYPE_ROTATION_VECTOR) + setupMethodChannel(flutterPluginBinding.binaryMessenger) + setupEventChannel(flutterPluginBinding.binaryMessenger) + } + + override fun onDetachedFromEngine(binding: FlutterPlugin.FlutterPluginBinding) { + teardownMethodChannel() + teardownEventChannels() + } + + private fun setupMethodChannel(messenger: BinaryMessenger) { + methodChannel = MethodChannel(messenger, "rotation_sensor/method") + methodChannel.setMethodCallHandler(this) + } + + private fun teardownMethodChannel() { + methodChannel.setMethodCallHandler(null); + } + + private fun setupEventChannel(messenger: BinaryMessenger) { + eventChannel = EventChannel(messenger, "rotation_sensor/orientation") + eventChannel.setStreamHandler(this) + } + + private fun teardownEventChannels() { + eventChannel.setStreamHandler(null) + onCancel(null) + } + + override fun onMethodCall(call: MethodCall, result: Result) { + when (call.method) { + "getOrientationStream" -> { + if (call.hasArgument("samplingPeriod")) { + val samplingPeriod = call.argument("samplingPeriod") + if ( + (samplingPeriod != null && + samplingPeriod != this.samplingPeriod) && + sensorEventListener != null + ) { + this.samplingPeriod = samplingPeriod + sensorManager.unregisterListener(sensorEventListener) + sensorManager.registerListener(sensorEventListener, sensor, samplingPeriod) + } + } + result.success(null); + } + else -> { + result.notImplemented() + } + } + } + + override fun onListen(arguments: Any?, events: EventSink) { + if (sensor != null) { + sensorEventListener = createSensorEventListener(events) + sensorManager.registerListener(sensorEventListener, sensor, samplingPeriod) + } else { + events.error( + "NO_SENSOR", + "Sensor not found", + "It seems that your device has no rotation vector sensor" + ) + } + } + + override fun onCancel(arguments: Any?) { + if (sensor != null) { + sensorEventListener?.let { + sensorManager.unregisterListener(it) + sensorEventListener = null + } + } + } + + private fun createSensorEventListener(events: EventSink): SensorEventListener { + return object : SensorEventListener { + override fun onAccuracyChanged(sensor: Sensor, accuracy: Int) {} + + override fun onSensorChanged(event: SensorEvent) { + + val rotationMatrix = FloatArray(9) + SensorManager.getRotationMatrixFromVector(rotationMatrix, event.values) + + val orientation = FloatArray(3) + SensorManager.getOrientation(rotationMatrix, orientation) + + val sensorValues = arrayListOf( + event.values[0].toDouble(), + event.values[1].toDouble(), + event.values[2].toDouble(), + event.values[3].toDouble(), + event.values[4].toDouble(), + event.timestamp, + ) + events.success(sensorValues) + } + } + } +} diff --git a/android/src/test/kotlin/net/tlserver6y/flutter_rotation_sensor/FlutterRotationSensorPluginTest.kt b/android/src/test/kotlin/net/tlserver6y/flutter_rotation_sensor/FlutterRotationSensorPluginTest.kt new file mode 100644 index 0000000..fd20c36 --- /dev/null +++ b/android/src/test/kotlin/net/tlserver6y/flutter_rotation_sensor/FlutterRotationSensorPluginTest.kt @@ -0,0 +1,4 @@ +package net.tlserver6y.flutter_rotation_sensor + +internal class FlutterRotationSensorPluginTest { +} diff --git a/example/.gitignore b/example/.gitignore new file mode 100644 index 0000000..cef2e8f --- /dev/null +++ b/example/.gitignore @@ -0,0 +1,26 @@ +# Created by https://www.toptal.com/developers/gitignore/api/jetbrains,flutter +# Edit at https://www.toptal.com/developers/gitignore?templates=jetbrains,flutter + +### Flutter ### +# Flutter/Dart/Pub related +**/doc/api/ +**/ios/Flutter/.last_build_id +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.pub-cache/ +.pub/ +build/ +coverage/ +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Android Studio will place build artifacts here +/android/app/debug +/android/app/profile +/android/app/release diff --git a/example/.idea/libraries/Dart_SDK.xml b/example/.idea/libraries/Dart_SDK.xml new file mode 100644 index 0000000..d351807 --- /dev/null +++ b/example/.idea/libraries/Dart_SDK.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/example/.idea/libraries/KotlinJavaRuntime.xml b/example/.idea/libraries/KotlinJavaRuntime.xml new file mode 100644 index 0000000..2b96ac4 --- /dev/null +++ b/example/.idea/libraries/KotlinJavaRuntime.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/example/.idea/modules.xml b/example/.idea/modules.xml new file mode 100644 index 0000000..2cad400 --- /dev/null +++ b/example/.idea/modules.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/example/.idea/runConfigurations/main_dart.xml b/example/.idea/runConfigurations/main_dart.xml new file mode 100644 index 0000000..aab7b5c --- /dev/null +++ b/example/.idea/runConfigurations/main_dart.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/example/.idea/workspace.xml b/example/.idea/workspace.xml new file mode 100644 index 0000000..5b3388c --- /dev/null +++ b/example/.idea/workspace.xml @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/example/README.md b/example/README.md new file mode 100644 index 0000000..58b31eb --- /dev/null +++ b/example/README.md @@ -0,0 +1,3 @@ +# flutter_rotation_sensor_example + +Demonstrates how to use the flutter_rotation_sensor plugin. diff --git a/example/analysis_options.yaml b/example/analysis_options.yaml new file mode 100644 index 0000000..0d29021 --- /dev/null +++ b/example/analysis_options.yaml @@ -0,0 +1,28 @@ +# 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.dev/lints. + # + # 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/android/.gitignore b/example/android/.gitignore new file mode 100644 index 0000000..6f56801 --- /dev/null +++ b/example/android/.gitignore @@ -0,0 +1,13 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java + +# Remember to never publicly share your keystore. +# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app +key.properties +**/*.keystore +**/*.jks diff --git a/example/android/.idea/.gitignore b/example/android/.idea/.gitignore new file mode 100644 index 0000000..26d3352 --- /dev/null +++ b/example/android/.idea/.gitignore @@ -0,0 +1,3 @@ +# Default ignored files +/shelf/ +/workspace.xml diff --git a/example/android/.idea/codeStyles/Project.xml b/example/android/.idea/codeStyles/Project.xml new file mode 100644 index 0000000..4bec4ea --- /dev/null +++ b/example/android/.idea/codeStyles/Project.xml @@ -0,0 +1,117 @@ + + + + + + \ No newline at end of file diff --git a/example/android/.idea/codeStyles/codeStyleConfig.xml b/example/android/.idea/codeStyles/codeStyleConfig.xml new file mode 100644 index 0000000..a55e7a1 --- /dev/null +++ b/example/android/.idea/codeStyles/codeStyleConfig.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/example/android/.idea/compiler.xml b/example/android/.idea/compiler.xml new file mode 100644 index 0000000..b589d56 --- /dev/null +++ b/example/android/.idea/compiler.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/example/android/.idea/deploymentTargetDropDown.xml b/example/android/.idea/deploymentTargetDropDown.xml new file mode 100644 index 0000000..0c0c338 --- /dev/null +++ b/example/android/.idea/deploymentTargetDropDown.xml @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/example/android/.idea/deploymentTargetSelector.xml b/example/android/.idea/deploymentTargetSelector.xml new file mode 100644 index 0000000..b268ef3 --- /dev/null +++ b/example/android/.idea/deploymentTargetSelector.xml @@ -0,0 +1,10 @@ + + + + + + + + + \ No newline at end of file diff --git a/example/android/.idea/gradle.xml b/example/android/.idea/gradle.xml new file mode 100644 index 0000000..0eab322 --- /dev/null +++ b/example/android/.idea/gradle.xml @@ -0,0 +1,34 @@ + + + + + + + \ No newline at end of file diff --git a/example/android/.idea/kotlinc.xml b/example/android/.idea/kotlinc.xml new file mode 100644 index 0000000..6d0ee1c --- /dev/null +++ b/example/android/.idea/kotlinc.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/example/android/.idea/migrations.xml b/example/android/.idea/migrations.xml new file mode 100644 index 0000000..f8051a6 --- /dev/null +++ b/example/android/.idea/migrations.xml @@ -0,0 +1,10 @@ + + + + + + \ No newline at end of file diff --git a/example/android/.idea/misc.xml b/example/android/.idea/misc.xml new file mode 100644 index 0000000..8978d23 --- /dev/null +++ b/example/android/.idea/misc.xml @@ -0,0 +1,9 @@ + + + + + + + + \ No newline at end of file diff --git a/example/android/.idea/other.xml b/example/android/.idea/other.xml new file mode 100644 index 0000000..0d3a1fb --- /dev/null +++ b/example/android/.idea/other.xml @@ -0,0 +1,263 @@ + + + + + + \ No newline at end of file diff --git a/example/android/.idea/vcs.xml b/example/android/.idea/vcs.xml new file mode 100644 index 0000000..b2bdec2 --- /dev/null +++ b/example/android/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/example/android/app/build.gradle b/example/android/app/build.gradle new file mode 100644 index 0000000..54d0f7b --- /dev/null +++ b/example/android/app/build.gradle @@ -0,0 +1,55 @@ +plugins { + id "com.android.application" + id "kotlin-android" + // The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins. + id "dev.flutter.flutter-gradle-plugin" +} + +def localProperties = new Properties() +def localPropertiesFile = rootProject.file("local.properties") +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader("UTF-8") { reader -> + localProperties.load(reader) + } +} + +def flutterVersionCode = localProperties.getProperty("flutter.versionCode") +if (flutterVersionCode == null) { + flutterVersionCode = "1" +} + +def flutterVersionName = localProperties.getProperty("flutter.versionName") +if (flutterVersionName == null) { + flutterVersionName = "1.0" +} + +android { + namespace = "net.tlserver6y.flutter_rotation_sensor_example" + compileSdk = flutter.compileSdkVersion + ndkVersion = flutter.ndkVersion + + compileOptions { + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 + } + + defaultConfig { + applicationId = "net.tlserver6y.flutter_rotation_sensor_example" + minSdk = flutter.minSdkVersion + targetSdk = flutter.targetSdkVersion + versionCode = flutterVersionCode.toInteger() + versionName = flutterVersionName + } + + buildTypes { + release { + // TODO: Add your own signing config for the release build. + // Signing with the debug keys for now, so `flutter run --release` works. + signingConfig = signingConfigs.debug + } + } +} + +flutter { + source = "../.." +} diff --git a/example/android/app/src/debug/AndroidManifest.xml b/example/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..399f698 --- /dev/null +++ b/example/android/app/src/debug/AndroidManifest.xml @@ -0,0 +1,7 @@ + + + + diff --git a/example/android/app/src/main/AndroidManifest.xml b/example/android/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..6ebd455 --- /dev/null +++ b/example/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/example/android/app/src/main/kotlin/net/tlserver6y/flutter_rotation_sensor_example/MainActivity.kt b/example/android/app/src/main/kotlin/net/tlserver6y/flutter_rotation_sensor_example/MainActivity.kt new file mode 100644 index 0000000..3866d29 --- /dev/null +++ b/example/android/app/src/main/kotlin/net/tlserver6y/flutter_rotation_sensor_example/MainActivity.kt @@ -0,0 +1,5 @@ +package net.tlserver6y.flutter_rotation_sensor_example + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() diff --git a/example/android/app/src/main/res/drawable-v21/launch_background.xml b/example/android/app/src/main/res/drawable-v21/launch_background.xml new file mode 100644 index 0000000..f74085f --- /dev/null +++ b/example/android/app/src/main/res/drawable-v21/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/example/android/app/src/main/res/drawable/launch_background.xml b/example/android/app/src/main/res/drawable/launch_background.xml new file mode 100644 index 0000000..304732f --- /dev/null +++ b/example/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..db77bb4b7b0906d62b1847e87f15cdcacf6a4f29 GIT binary patch literal 544 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY3?!3`olAj~WQl7;NpOBzNqJ&XDuZK6ep0G} zXKrG8YEWuoN@d~6R2!h8bpbvhu0Wd6uZuB!w&u2PAxD2eNXD>P5D~Wn-+_Wa#27Xc zC?Zj|6r#X(-D3u$NCt}(Ms06KgJ4FxJVv{GM)!I~&n8Bnc94O7-Hd)cjDZswgC;Qs zO=b+9!WcT8F?0rF7!Uys2bs@gozCP?z~o%U|N3vA*22NaGQG zlg@K`O_XuxvZ&Ks^m&R!`&1=spLvfx7oGDKDwpwW`#iqdw@AL`7MR}m`rwr|mZgU`8P7SBkL78fFf!WnuYWm$5Z0 zNXhDbCv&49sM544K|?c)WrFfiZvCi9h0O)B3Pgg&ebxsLQ05GG~ AQ2+n{ literal 0 HcmV?d00001 diff --git a/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..17987b79bb8a35cc66c3c1fd44f5a5526c1b78be GIT binary patch literal 442 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA3?vioaBc-sk|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*D5Xx&nMcT!A!W`0S9QKQy;}1Cl^CgaH=;G9cpY;r$Q>i*pfB zP2drbID<_#qf;rPZx^FqH)F_D#*k@@q03KywUtLX8Ua?`H+NMzkczFPK3lFz@i_kW%1NOn0|D2I9n9wzH8m|-tHjsw|9>@K=iMBhxvkv6m8Y-l zytQ?X=U+MF$@3 zt`~i=@j|6y)RWMK--}M|=T`o&^Ni>IoWKHEbBXz7?A@mgWoL>!*SXo`SZH-*HSdS+ yn*9;$7;m`l>wYBC5bq;=U}IMqLzqbYCidGC!)_gkIk_C@Uy!y&wkt5C($~2D>~)O*cj@FGjOCM)M>_ixfudOh)?xMu#Fs z#}Y=@YDTwOM)x{K_j*Q;dPdJ?Mz0n|pLRx{4n|)f>SXlmV)XB04CrSJn#dS5nK2lM zrZ9#~WelCp7&e13Y$jvaEXHskn$2V!!DN-nWS__6T*l;H&Fopn?A6HZ-6WRLFP=R` zqG+CE#d4|IbyAI+rJJ`&x9*T`+a=p|0O(+s{UBcyZdkhj=yS1>AirP+0R;mf2uMgM zC}@~JfByORAh4SyRgi&!(cja>F(l*O+nd+@4m$|6K6KDn_&uvCpV23&>G9HJp{xgg zoq1^2_p9@|WEo z*X_Uko@K)qYYv~>43eQGMdbiGbo>E~Q& zrYBH{QP^@Sti!`2)uG{irBBq@y*$B zi#&(U-*=fp74j)RyIw49+0MRPMRU)+a2r*PJ$L5roHt2$UjExCTZSbq%V!HeS7J$N zdG@vOZB4v_lF7Plrx+hxo7(fCV&}fHq)$ literal 0 HcmV?d00001 diff --git a/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..d5f1c8d34e7a88e3f88bea192c3a370d44689c3c GIT binary patch literal 1031 zcmeAS@N?(olHy`uVBq!ia0vp^6F``Q8Ax83A=Cw=BuiW)N`mv#O3D+9QW+dm@{>{( zJaZG%Q-e|yQz{EjrrIztFa`(sgt!6~Yi|1%a`XoT0ojZ}lNrNjb9xjc(B0U1_% zz5^97Xt*%oq$rQy4?0GKNfJ44uvxI)gC`h-NZ|&0-7(qS@?b!5r36oQ}zyZrNO3 zMO=Or+<~>+A&uN&E!^Sl+>xE!QC-|oJv`ApDhqC^EWD|@=#J`=d#Xzxs4ah}w&Jnc z$|q_opQ^2TrnVZ0o~wh<3t%W&flvYGe#$xqda2bR_R zvPYgMcHgjZ5nSA^lJr%;<&0do;O^tDDh~=pIxA#coaCY>&N%M2^tq^U%3DB@ynvKo}b?yu-bFc-u0JHzced$sg7S3zqI(2 z#Km{dPr7I=pQ5>FuK#)QwK?Y`E`B?nP+}U)I#c1+FM*1kNvWG|a(TpksZQ3B@sD~b zpQ2)*V*TdwjFOtHvV|;OsiDqHi=6%)o4b!)x$)%9pGTsE z-JL={-Ffv+T87W(Xpooq<`r*VzWQcgBN$$`u}f>-ZQI1BB8ykN*=e4rIsJx9>z}*o zo~|9I;xof literal 0 HcmV?d00001 diff --git a/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..4d6372eebdb28e45604e46eeda8dd24651419bc0 GIT binary patch literal 1443 zcmb`G{WsKk6vsdJTdFg%tJav9_E4vzrOaqkWF|A724Nly!y+?N9`YV6wZ}5(X(D_N(?!*n3`|_r0Hc?=PQw&*vnU?QTFY zB_MsH|!j$PP;I}?dppoE_gA(4uc!jV&0!l7_;&p2^pxNo>PEcNJv za5_RT$o2Mf!<+r?&EbHH6nMoTsDOa;mN(wv8RNsHpG)`^ymG-S5By8=l9iVXzN_eG%Xg2@Xeq76tTZ*dGh~Lo9vl;Zfs+W#BydUw zCkZ$o1LqWQO$FC9aKlLl*7x9^0q%0}$OMlp@Kk_jHXOjofdePND+j!A{q!8~Jn+s3 z?~~w@4?egS02}8NuulUA=L~QQfm;MzCGd)XhiftT;+zFO&JVyp2mBww?;QByS_1w! zrQlx%{^cMj0|Bo1FjwY@Q8?Hx0cIPF*@-ZRFpPc#bBw{5@tD(5%sClzIfl8WU~V#u zm5Q;_F!wa$BSpqhN>W@2De?TKWR*!ujY;Yylk_X5#~V!L*Gw~;$%4Q8~Mad z@`-kG?yb$a9cHIApZDVZ^U6Xkp<*4rU82O7%}0jjHlK{id@?-wpN*fCHXyXh(bLt* zPc}H-x0e4E&nQ>y%B-(EL=9}RyC%MyX=upHuFhAk&MLbsF0LP-q`XnH78@fT+pKPW zu72MW`|?8ht^tz$iC}ZwLp4tB;Q49K!QCF3@!iB1qOI=?w z7In!}F~ij(18UYUjnbmC!qKhPo%24?8U1x{7o(+?^Zu0Hx81|FuS?bJ0jgBhEMzf< zCgUq7r2OCB(`XkKcN-TL>u5y#dD6D!)5W?`O5)V^>jb)P)GBdy%t$uUMpf$SNV31$ zb||OojAbvMP?T@$h_ZiFLFVHDmbyMhJF|-_)HX3%m=CDI+ID$0^C>kzxprBW)hw(v zr!Gmda);ICoQyhV_oP5+C%?jcG8v+D@9f?Dk*!BxY}dazmrT@64UrP3hlslANK)bq z$67n83eh}OeW&SV@HG95P|bjfqJ7gw$e+`Hxo!4cx`jdK1bJ>YDSpGKLPZ^1cv$ek zIB?0S<#tX?SJCLWdMd{-ME?$hc7A$zBOdIJ)4!KcAwb=VMov)nK;9z>x~rfT1>dS+ zZ6#`2v@`jgbqq)P22H)Tx2CpmM^o1$B+xT6`(v%5xJ(?j#>Q$+rx_R|7TzDZe{J6q zG1*EcU%tE?!kO%^M;3aM6JN*LAKUVb^xz8-Pxo#jR5(-KBeLJvA@-gxNHx0M-ZJLl z;#JwQoh~9V?`UVo#}{6ka@II>++D@%KqGpMdlQ}?9E*wFcf5(#XQnP$Dk5~%iX^>f z%$y;?M0BLp{O3a(-4A?ewryHrrD%cx#Q^%KY1H zNre$ve+vceSLZcNY4U(RBX&)oZn*Py()h)XkE?PL$!bNb{N5FVI2Y%LKEm%yvpyTP z(1P?z~7YxD~Rf<(a@_y` literal 0 HcmV?d00001 diff --git a/example/android/app/src/main/res/values-night/styles.xml b/example/android/app/src/main/res/values-night/styles.xml new file mode 100644 index 0000000..06952be --- /dev/null +++ b/example/android/app/src/main/res/values-night/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/example/android/app/src/main/res/values/styles.xml b/example/android/app/src/main/res/values/styles.xml new file mode 100644 index 0000000..cb1ef88 --- /dev/null +++ b/example/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/example/android/app/src/profile/AndroidManifest.xml b/example/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..399f698 --- /dev/null +++ b/example/android/app/src/profile/AndroidManifest.xml @@ -0,0 +1,7 @@ + + + + diff --git a/example/android/build.gradle b/example/android/build.gradle new file mode 100644 index 0000000..bc157bd --- /dev/null +++ b/example/android/build.gradle @@ -0,0 +1,18 @@ +allprojects { + repositories { + google() + mavenCentral() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +tasks.register("clean", Delete) { + delete rootProject.buildDir +} diff --git a/example/android/flutter_rotation_sensor_example_android.iml b/example/android/flutter_rotation_sensor_example_android.iml new file mode 100644 index 0000000..1899969 --- /dev/null +++ b/example/android/flutter_rotation_sensor_example_android.iml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/example/android/gradle.properties b/example/android/gradle.properties new file mode 100644 index 0000000..3b5b324 --- /dev/null +++ b/example/android/gradle.properties @@ -0,0 +1,3 @@ +org.gradle.jvmargs=-Xmx4G -XX:+HeapDumpOnOutOfMemoryError +android.useAndroidX=true +android.enableJetifier=true diff --git a/example/android/gradle/wrapper/gradle-wrapper.properties b/example/android/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..3c85cfe --- /dev/null +++ b/example/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-all.zip diff --git a/example/android/settings.gradle b/example/android/settings.gradle new file mode 100644 index 0000000..d0a1b95 --- /dev/null +++ b/example/android/settings.gradle @@ -0,0 +1,25 @@ +pluginManagement { + def flutterSdkPath = { + def properties = new Properties() + file("local.properties").withInputStream { properties.load(it) } + def flutterSdkPath = properties.getProperty("flutter.sdk") + assert flutterSdkPath != null, "flutter.sdk not set in local.properties" + return flutterSdkPath + }() + + includeBuild("$flutterSdkPath/packages/flutter_tools/gradle") + + repositories { + google() + mavenCentral() + gradlePluginPortal() + } +} + +plugins { + id "dev.flutter.flutter-plugin-loader" version "1.0.0" + id "com.android.application" version "8.5.1" apply false + id "org.jetbrains.kotlin.android" version "2.0.0" apply false +} + +include ":app" diff --git a/example/assets/images/other.png b/example/assets/images/other.png new file mode 100644 index 0000000000000000000000000000000000000000..5e816d453438c803152907a20f2fdd2617f43c18 GIT binary patch literal 8013 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 nEAafIXhd25-wFTv+dj!VVTs9mu+ + + + + + + + + + + + + + + + + diff --git a/example/ios/.gitignore b/example/ios/.gitignore new file mode 100644 index 0000000..7a7f987 --- /dev/null +++ b/example/ios/.gitignore @@ -0,0 +1,34 @@ +**/dgph +*.mode1v3 +*.mode2v3 +*.moved-aside +*.pbxuser +*.perspectivev3 +**/*sync/ +.sconsign.dblite +.tags* +**/.vagrant/ +**/DerivedData/ +Icon? +**/Pods/ +**/.symlinks/ +profile +xcuserdata +**/.generated/ +Flutter/App.framework +Flutter/Flutter.framework +Flutter/Flutter.podspec +Flutter/Generated.xcconfig +Flutter/ephemeral/ +Flutter/app.flx +Flutter/app.zip +Flutter/flutter_assets/ +Flutter/flutter_export_environment.sh +ServiceDefinitions.json +Runner/GeneratedPluginRegistrant.* + +# Exceptions to above rules. +!default.mode1v3 +!default.mode2v3 +!default.pbxuser +!default.perspectivev3 diff --git a/example/ios/Flutter/AppFrameworkInfo.plist b/example/ios/Flutter/AppFrameworkInfo.plist new file mode 100644 index 0000000..7c56964 --- /dev/null +++ b/example/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 12.0 + + diff --git a/example/ios/Flutter/Debug.xcconfig b/example/ios/Flutter/Debug.xcconfig new file mode 100644 index 0000000..592ceee --- /dev/null +++ b/example/ios/Flutter/Debug.xcconfig @@ -0,0 +1 @@ +#include "Generated.xcconfig" diff --git a/example/ios/Flutter/Release.xcconfig b/example/ios/Flutter/Release.xcconfig new file mode 100644 index 0000000..592ceee --- /dev/null +++ b/example/ios/Flutter/Release.xcconfig @@ -0,0 +1 @@ +#include "Generated.xcconfig" diff --git a/example/ios/Runner.xcodeproj/project.pbxproj b/example/ios/Runner.xcodeproj/project.pbxproj new file mode 100644 index 0000000..25a96f1 --- /dev/null +++ b/example/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,616 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 54; + objects = { + +/* Begin PBXBuildFile section */ + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; + 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; }; + 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 */; }; + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 331C8085294A63A400263BE5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 97C146E61CF9000F007C117D /* Project object */; + proxyType = 1; + remoteGlobalIDString = 97C146ED1CF9000F007C117D; + remoteInfo = Runner; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 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 = ""; }; + 331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; + 331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; + 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 = ""; }; + 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; + 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; + 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 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 = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 97C146EB1CF9000F007C117D /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 331C8082294A63A400263BE5 /* RunnerTests */ = { + isa = PBXGroup; + children = ( + 331C807B294A618700263BE5 /* RunnerTests.swift */, + ); + path = RunnerTests; + sourceTree = ""; + }; + 9740EEB11CF90186004384FC /* Flutter */ = { + isa = PBXGroup; + children = ( + 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, + 9740EEB21CF90195004384FC /* Debug.xcconfig */, + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, + 9740EEB31CF90195004384FC /* Generated.xcconfig */, + ); + name = Flutter; + sourceTree = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + 331C8082294A63A400263BE5 /* RunnerTests */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + 331C8081294A63A400263BE5 /* RunnerTests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 331C8080294A63A400263BE5 /* RunnerTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; + buildPhases = ( + 331C807D294A63A400263BE5 /* Sources */, + 331C807F294A63A400263BE5 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 331C8086294A63A400263BE5 /* PBXTargetDependency */, + ); + name = RunnerTests; + productName = RunnerTests; + productReference = 331C8081294A63A400263BE5 /* RunnerTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; + 97C146ED1CF9000F007C117D /* Runner */ = { + isa = PBXNativeTarget; + buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; + buildPhases = ( + 9740EEB61CF901F6004384FC /* Run Script */, + 97C146EA1CF9000F007C117D /* Sources */, + 97C146EB1CF9000F007C117D /* Frameworks */, + 97C146EC1CF9000F007C117D /* Resources */, + 9705A1C41CF9048500538489 /* Embed Frameworks */, + 3B06AD1E1E4923F5004D2608 /* Thin Binary */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Runner; + productName = Runner; + productReference = 97C146EE1CF9000F007C117D /* Runner.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 97C146E61CF9000F007C117D /* Project object */ = { + isa = PBXProject; + attributes = { + BuildIndependentTargetsInParallel = YES; + LastUpgradeCheck = 1510; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 331C8080294A63A400263BE5 = { + CreatedOnToolsVersion = 14.0; + TestTargetID = 97C146ED1CF9000F007C117D; + }; + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + 331C8080294A63A400263BE5 /* RunnerTests */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 331C807F294A63A400263BE5 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}", + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + 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"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 331C807D294A63A400263BE5 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 331C8086294A63A400263BE5 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 97C146ED1CF9000F007C117D /* Runner */; + targetProxy = 331C8085294A63A400263BE5 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Profile; + }; + 249021D4217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = net.tlserver6y.flutterRotationSensorExample; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 331C8088294A63A400263BE5 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = net.tlserver6y.flutterRotationSensorExample.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; + }; + name = Debug; + }; + 331C8089294A63A400263BE5 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = net.tlserver6y.flutterRotationSensorExample.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; + }; + name = Release; + }; + 331C808A294A63A400263BE5 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = net.tlserver6y.flutterRotationSensorExample.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 97C147061CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = net.tlserver6y.flutterRotationSensorExample; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Debug; + }; + 97C147071CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = net.tlserver6y.flutterRotationSensorExample; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 331C8088294A63A400263BE5 /* Debug */, + 331C8089294A63A400263BE5 /* Release */, + 331C808A294A63A400263BE5 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..919434a --- /dev/null +++ b/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 0000000..f9b0d7c --- /dev/null +++ b/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme new file mode 100644 index 0000000..8e3ca5d --- /dev/null +++ b/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,98 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/example/ios/Runner.xcworkspace/contents.xcworkspacedata b/example/ios/Runner.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /dev/null +++ b/example/ios/Runner.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 0000000..f9b0d7c --- /dev/null +++ b/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/example/ios/Runner/AppDelegate.swift b/example/ios/Runner/AppDelegate.swift new file mode 100644 index 0000000..9074fee --- /dev/null +++ b/example/ios/Runner/AppDelegate.swift @@ -0,0 +1,13 @@ +import Flutter +import UIKit + +@UIApplicationMain +@objc class AppDelegate: FlutterAppDelegate { + override func application( + _ application: UIApplication, + didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? + ) -> Bool { + GeneratedPluginRegistrant.register(with: self) + return super.application(application, didFinishLaunchingWithOptions: launchOptions) + } +} diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..d36b1fa --- /dev/null +++ b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,122 @@ +{ + "images" : [ + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "Icon-App-20x20@2x.png", + "scale" : "2x" + }, + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "Icon-App-20x20@3x.png", + "scale" : "3x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@1x.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@2x.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@3x.png", + "scale" : "3x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Icon-App-40x40@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Icon-App-40x40@3x.png", + "scale" : "3x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon-App-60x60@2x.png", + "scale" : "2x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon-App-60x60@3x.png", + "scale" : "3x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "Icon-App-20x20@1x.png", + "scale" : "1x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "Icon-App-20x20@2x.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "Icon-App-29x29@1x.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "Icon-App-29x29@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon-App-40x40@1x.png", + "scale" : "1x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon-App-40x40@2x.png", + "scale" : "2x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon-App-76x76@1x.png", + "scale" : "1x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon-App-76x76@2x.png", + "scale" : "2x" + }, + { + "size" : "83.5x83.5", + "idiom" : "ipad", + "filename" : "Icon-App-83.5x83.5@2x.png", + "scale" : "2x" + }, + { + "size" : "1024x1024", + "idiom" : "ios-marketing", + "filename" : "Icon-App-1024x1024@1x.png", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png new file mode 100644 index 0000000000000000000000000000000000000000..dc9ada4725e9b0ddb1deab583e5b5102493aa332 GIT binary patch literal 10932 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 literal 0 HcmV?d00001 diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..797d452e458972bab9d994556c8305db4c827017 GIT binary patch literal 406 zcmV;H0crk;P))>cdjpWt&rLJgVp-t?DREyuq1A%0Z4)6_WsQ7{nzjN zo!X zGXV)2i3kcZIL~_j>uIKPK_zib+3T+Nt3Mb&Br)s)UIaA}@p{wDda>7=Q|mGRp7pqY zkJ!7E{MNz$9nOwoVqpFb)}$IP24Wn2JJ=Cw(!`OXJBr45rP>>AQr$6c7slJWvbpNW z@KTwna6d?PP>hvXCcp=4F;=GR@R4E7{4VU^0p4F>v^#A|>07*qoM6N<$f*5nx ACIA2c literal 0 HcmV?d00001 diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..6ed2d933e1120817fe9182483a228007b18ab6ae GIT binary patch literal 450 zcmV;z0X_bSP)iGWQ_5NJQ_~rNh*z)}eT%KUb z`7gNk0#AwF^#0T0?hIa^`~Ck;!}#m+_uT050aTR(J!bU#|IzRL%^UsMS#KsYnTF*!YeDOytlP4VhV?b} z%rz_<=#CPc)tU1MZTq~*2=8~iZ!lSa<{9b@2Jl;?IEV8)=fG217*|@)CCYgFze-x? zIFODUIA>nWKpE+bn~n7;-89sa>#DR>TSlqWk*!2hSN6D~Qb#VqbP~4Fk&m`@1$JGr zXPIdeRE&b2Thd#{MtDK$px*d3-Wx``>!oimf%|A-&-q*6KAH)e$3|6JV%HX{Hig)k suLT-RhftRq8b9;(V=235Wa|I=027H2wCDra;{X5v07*qoM6N<$f;9x^2LJ#7 literal 0 HcmV?d00001 diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png new file mode 100644 index 0000000000000000000000000000000000000000..4cd7b0099ca80c806f8fe495613e8d6c69460d76 GIT binary patch literal 282 zcmV+#0p(^bcu7P-R4C8Q z&e;xxFbF_Vrezo%_kH*OKhshZ6BFpG-Y1e10`QXJKbND7AMQ&cMj60B5TNObaZxYybcN07*qoM6N<$g3m;S%K!iX literal 0 HcmV?d00001 diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..fe730945a01f64a61e2235dbe3f45b08f7729182 GIT binary patch literal 462 zcmV;<0WtoGP)-}iV`2<;=$?g5M=KQbZ{F&YRNy7Nn@%_*5{gvDM0aKI4?ESmw z{NnZg)A0R`+4?NF_RZexyVB&^^ZvN!{I28tr{Vje;QNTz`dG&Jz0~Ek&f2;*Z7>B|cg}xYpxEFY+0YrKLF;^Q+-HreN0P{&i zK~zY`?b7ECf-n?@;d<&orQ*Q7KoR%4|C>{W^h6@&01>0SKS`dn{Q}GT%Qj_{PLZ_& zs`MFI#j-(>?bvdZ!8^xTwlY{qA)T4QLbY@j(!YJ7aXJervHy6HaG_2SB`6CC{He}f zHVw(fJWApwPq!6VY7r1w-Fs)@ox~N+q|w~e;JI~C4Vf^@d>Wvj=fl`^u9x9wd9 zR%3*Q+)t%S!MU_`id^@&Y{y7-r98lZX0?YrHlfmwb?#}^1b{8g&KzmkE(L>Z&)179 zp<)v6Y}pRl100G2FL_t(o!|l{-Q-VMg#&MKg7c{O0 z2wJImOS3Gy*Z2Qifdv~JYOp;v+U)a|nLoc7hNH;I$;lzDt$}rkaFw1mYK5_0Q(Sut zvbEloxON7$+HSOgC9Z8ltuC&0OSF!-mXv5caV>#bc3@hBPX@I$58-z}(ZZE!t-aOG zpjNkbau@>yEzH(5Yj4kZiMH32XI!4~gVXNnjAvRx;Sdg^`>2DpUEwoMhTs_st8pKG z(%SHyHdU&v%f36~uERh!bd`!T2dw;z6PrOTQ7Vt*#9F2uHlUVnb#ev_o^fh}Dzmq} zWtlk35}k=?xj28uO|5>>$yXadTUE@@IPpgH`gJ~Ro4>jd1IF|(+IX>8M4Ps{PNvmI zNj4D+XgN83gPt_Gm}`Ybv{;+&yu-C(Grdiahmo~BjG-l&mWM+{e5M1sm&=xduwgM9 z`8OEh`=F3r`^E{n_;%9weN{cf2%7=VzC@cYj+lg>+3|D|_1C@{hcU(DyQG_BvBWe? zvTv``=%b1zrol#=R`JB)>cdjpWt&rLJgVp-t?DREyuq1A%0Z4)6_WsQ7{nzjN zo!X zGXV)2i3kcZIL~_j>uIKPK_zib+3T+Nt3Mb&Br)s)UIaA}@p{wDda>7=Q|mGRp7pqY zkJ!7E{MNz$9nOwoVqpFb)}$IP24Wn2JJ=Cw(!`OXJBr45rP>>AQr$6c7slJWvbpNW z@KTwna6d?PP>hvXCcp=4F;=GR@R4E7{4VU^0p4F>v^#A|>07*qoM6N<$f*5nx ACIA2c literal 0 HcmV?d00001 diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..502f463a9bc882b461c96aadf492d1729e49e725 GIT binary patch literal 586 zcmV-Q0=4~#P)+}#`wDE{8-2Mebf5<{{PqV{TgVcv*r8?UZ3{-|G?_}T*&y;@cqf{ z{Q*~+qr%%p!1pS*_Uicl#q9lc(D`!D`LN62sNwq{oYw(Wmhk)k<@f$!$@ng~_5)Ru z0Z)trIA5^j{DIW^c+vT2%lW+2<(RtE2wR;4O@)Tm`Xr*?A(qYoM}7i5Yxw>D(&6ou zxz!_Xr~yNF+waPe00049Nkl*;a!v6h%{rlvIH#gW3s8p;bFr=l}mRqpW2h zw=OA%hdyL~z+UHOzl0eKhEr$YYOL-c-%Y<)=j?(bzDweB7{b+%_ypvm_cG{SvM=DK zhv{K@m>#Bw>2W$eUI#iU)Wdgs8Y3U+A$Gd&{+j)d)BmGKx+43U_!tik_YlN)>$7G! zhkE!s;%oku3;IwG3U^2kw?z+HM)jB{@zFhK8P#KMSytSthr+4!c(5c%+^UBn`0X*2 zy3(k600_CSZj?O$Qu%&$;|TGUJrptR(HzyIx>5E(2r{eA(<6t3e3I0B)7d6s7?Z5J zZ!rtKvA{MiEBm&KFtoifx>5P^Z=vl)95XJn()aS5%ad(s?4-=Tkis9IGu{`Fy8r+H07*qoM6N<$f20Z)wqMt%V?S?~D#06};F zA3KcL`Wb+>5ObvgQIG&ig8(;V04hz?@cqy3{mSh8o!|U|)cI!1_+!fWH@o*8vh^CU z^ws0;(c$gI+2~q^tO#GDHf@=;DncUw00J^eL_t(&-tE|HQ`%4vfZ;WsBqu-$0nu1R zq^Vj;p$clf^?twn|KHO+IGt^q#a3X?w9dXC@*yxhv&l}F322(8Y1&=P&I}~G@#h6; z1CV9ecD9ZEe87{{NtI*)_aJ<`kJa z?5=RBtFF50s;jQLFil-`)m2wrb=6h(&brpj%nG_U&ut~$?8Rokzxi8zJoWr#2dto5 zOX_URcc<1`Iky+jc;A%Vzx}1QU{2$|cKPom2Vf1{8m`vja4{F>HS?^Nc^rp}xo+Nh zxd}eOm`fm3@MQC1< zIk&aCjb~Yh%5+Yq0`)D;q{#-Uqlv*o+Oor zE!I71Z@ASH3grl8&P^L0WpavHoP|UX4e?!igT`4?AZk$hu*@%6WJ;zDOGlw7kj@ zY5!B-0ft0f?Lgb>C;$Ke07*qoM6N<$f~t1N9smFU literal 0 HcmV?d00001 diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..0ec303439225b78712f49115768196d8d76f6790 GIT binary patch literal 862 zcmV-k1EKthP)20Z)wqMt%V?S?~D#06};F zA3KcL`Wb+>5ObvgQIG&ig8(;V04hz?@cqy3{mSh8o!|U|)cI!1_+!fWH@o*8vh^CU z^ws0;(c$gI+2~q^tO#GDHf@=;DncUw00J^eL_t(&-tE|HQ`%4vfZ;WsBqu-$0nu1R zq^Vj;p$clf^?twn|KHO+IGt^q#a3X?w9dXC@*yxhv&l}F322(8Y1&=P&I}~G@#h6; z1CV9ecD9ZEe87{{NtI*)_aJ<`kJa z?5=RBtFF50s;jQLFil-`)m2wrb=6h(&brpj%nG_U&ut~$?8Rokzxi8zJoWr#2dto5 zOX_URcc<1`Iky+jc;A%Vzx}1QU{2$|cKPom2Vf1{8m`vja4{F>HS?^Nc^rp}xo+Nh zxd}eOm`fm3@MQC1< zIk&aCjb~Yh%5+Yq0`)D;q{#-Uqlv*o+Oor zE!I71Z@ASH3grl8&P^L0WpavHoP|UX4e?!igT`4?AZk$hu*@%6WJ;zDOGlw7kj@ zY5!B-0ft0f?Lgb>C;$Ke07*qoM6N<$f~t1N9smFU literal 0 HcmV?d00001 diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..e9f5fea27c705180eb716271f41b582e76dcbd90 GIT binary patch literal 1674 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 literal 0 HcmV?d00001 diff --git a/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..0467bf12aa4d28f374bb26596605a46dcbb3e7c8 GIT binary patch literal 1418 zcmV;51$Fv~P)q zKfU)WzW*n(@|xWGCA9ScMt*e9`2kdxPQ&&>|-UCa7_51w+ zLUsW@ZzZSW0y$)Hp~e9%PvP|a03ks1`~K?q{u;6NC8*{AOqIUq{CL&;p56Lf$oQGq z^={4hPQv)y=I|4n+?>7Fim=dxt1 z2H+Dm+1+fh+IF>G0SjJMkQQre1x4|G*Z==(Ot&kCnUrL4I(rf(ucITwmuHf^hXiJT zkdTm&kdTm&kdTm&kdP`esgWG0BcWCVkVZ&2dUwN`cgM8QJb`Z7Z~e<&Yj2(}>Tmf` zm1{eLgw!b{bXkjWbF%dTkTZEJWyWOb##Lfw4EK2}<0d6%>AGS{po>WCOy&f$Tay_> z?NBlkpo@s-O;0V%Y_Xa-G#_O08q5LR*~F%&)}{}r&L%Sbs8AS4t7Y0NEx*{soY=0MZExqA5XHQkqi#4gW3 zqODM^iyZl;dvf)-bOXtOru(s)Uc7~BFx{w-FK;2{`VA?(g&@3z&bfLFyctOH!cVsF z7IL=fo-qBndRUm;kAdXR4e6>k-z|21AaN%ubeVrHl*<|s&Ax@W-t?LR(P-24A5=>a z*R9#QvjzF8n%@1Nw@?CG@6(%>+-0ASK~jEmCV|&a*7-GKT72W<(TbSjf)&Eme6nGE z>Gkj4Sq&2e+-G%|+NM8OOm5zVl9{Z8Dd8A5z3y8mZ=4Bv4%>as_{9cN#bm~;h>62( zdqY93Zy}v&c4n($Vv!UybR8ocs7#zbfX1IY-*w~)p}XyZ-SFC~4w>BvMVr`dFbelV{lLL0bx7@*ZZdebr3`sP;? zVImji)kG)(6Juv0lz@q`F!k1FE;CQ(D0iG$wchPbKZQELlsZ#~rt8#90Y_Xh&3U-< z{s<&cCV_1`^TD^ia9!*mQDq& zn2{r`j};V|uV%_wsP!zB?m%;FeaRe+X47K0e+KE!8C{gAWF8)lCd1u1%~|M!XNRvw zvtqy3iz0WSpWdhn6$hP8PaRBmp)q`#PCA`Vd#Tc$@f1tAcM>f_I@bC)hkI9|o(Iqv zo}Piadq!j76}004RBio<`)70k^`K1NK)q>w?p^C6J2ZC!+UppiK6&y3Kmbv&O!oYF z34$0Z;QO!JOY#!`qyGH<3Pd}Pt@q*A0V=3SVtWKRR8d8Z&@)3qLPA19LPA19LPEUC YUoZo%k(ykuW&i*H07*qoM6N<$f+CH{y8r+H literal 0 HcmV?d00001 diff --git a/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json b/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json new file mode 100644 index 0000000..0bedcf2 --- /dev/null +++ b/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png b/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png new file mode 100644 index 0000000000000000000000000000000000000000..9da19eacad3b03bb08bbddbbf4ac48dd78b3d838 GIT binary patch literal 68 zcmeAS@N?(olHy`uVBq!ia0vp^j3CUx0wlM}@Gt=>Zci7-kcv6Uzs@r-FtIZ-&5|)J Q1PU{Fy85}Sb4q9e0B4a5jsO4v literal 0 HcmV?d00001 diff --git a/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png b/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..9da19eacad3b03bb08bbddbbf4ac48dd78b3d838 GIT binary patch literal 68 zcmeAS@N?(olHy`uVBq!ia0vp^j3CUx0wlM}@Gt=>Zci7-kcv6Uzs@r-FtIZ-&5|)J Q1PU{Fy85}Sb4q9e0B4a5jsO4v literal 0 HcmV?d00001 diff --git a/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png b/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..9da19eacad3b03bb08bbddbbf4ac48dd78b3d838 GIT binary patch literal 68 zcmeAS@N?(olHy`uVBq!ia0vp^j3CUx0wlM}@Gt=>Zci7-kcv6Uzs@r-FtIZ-&5|)J Q1PU{Fy85}Sb4q9e0B4a5jsO4v literal 0 HcmV?d00001 diff --git a/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md b/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md new file mode 100644 index 0000000..89c2725 --- /dev/null +++ b/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md @@ -0,0 +1,5 @@ +# Launch Screen Assets + +You can customize the launch screen with your own desired assets by replacing the image files in this directory. + +You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. \ No newline at end of file diff --git a/example/ios/Runner/Base.lproj/LaunchScreen.storyboard b/example/ios/Runner/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 0000000..f2e259c --- /dev/null +++ b/example/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/example/ios/Runner/Base.lproj/Main.storyboard b/example/ios/Runner/Base.lproj/Main.storyboard new file mode 100644 index 0000000..f3c2851 --- /dev/null +++ b/example/ios/Runner/Base.lproj/Main.storyboard @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/example/ios/Runner/Info.plist b/example/ios/Runner/Info.plist new file mode 100644 index 0000000..1879ebd --- /dev/null +++ b/example/ios/Runner/Info.plist @@ -0,0 +1,49 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleDisplayName + Flutter Rotation Sensor + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + flutter_rotation_sensor_example + CFBundlePackageType + APPL + CFBundleShortVersionString + $(FLUTTER_BUILD_NAME) + CFBundleSignature + ???? + CFBundleVersion + $(FLUTTER_BUILD_NUMBER) + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + CADisableMinimumFrameDurationOnPhone + + UIApplicationSupportsIndirectInputEvents + + + diff --git a/example/ios/Runner/Runner-Bridging-Header.h b/example/ios/Runner/Runner-Bridging-Header.h new file mode 100644 index 0000000..308a2a5 --- /dev/null +++ b/example/ios/Runner/Runner-Bridging-Header.h @@ -0,0 +1 @@ +#import "GeneratedPluginRegistrant.h" diff --git a/example/ios/RunnerTests/RunnerTests.swift b/example/ios/RunnerTests/RunnerTests.swift new file mode 100644 index 0000000..61de4bc --- /dev/null +++ b/example/ios/RunnerTests/RunnerTests.swift @@ -0,0 +1,26 @@ +import Flutter +import UIKit +import XCTest + +@testable import flutter_rotation_sensor + +// This demonstrates a simple unit test of the Swift portion of this plugin's implementation. +// +// See https://developer.apple.com/documentation/xctest for more information about using XCTest. + +class RunnerTests: XCTestCase { + + func testGetPlatformVersion() { + let plugin = FlutterRotationSensorPlugin() + + let call = FlutterMethodCall(methodName: "getPlatformVersion", arguments: []) + + let resultExpectation = expectation(description: "result block must be called.") + plugin.handle(call) { result in + XCTAssertEqual(result as! String, "iOS " + UIDevice.current.systemVersion) + resultExpectation.fulfill() + } + waitForExpectations(timeout: 1) + } + +} diff --git a/example/lib/main.dart b/example/lib/main.dart new file mode 100644 index 0000000..9de5112 --- /dev/null +++ b/example/lib/main.dart @@ -0,0 +1,173 @@ +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_rotation_sensor/flutter_rotation_sensor.dart'; +import 'package:simple_3d/simple_3d.dart'; +import 'package:simple_3d_renderer/simple_3d_renderer.dart'; +import 'package:util_simple_3d/util_simple_3d.dart'; + +void main() { + WidgetsFlutterBinding.ensureInitialized(); + SystemChrome.setPreferredOrientations([ + DeviceOrientation.portraitUp, + DeviceOrientation.portraitDown, + DeviceOrientation.landscapeLeft, + DeviceOrientation.landscapeRight, + ]); + runApp(const MyApp()); +} + +class MyApp extends StatefulWidget { + const MyApp({super.key}); + + @override + State createState() => _MyAppState(); +} + +class _MyAppState extends State { + late final Sp3dWorld world; + + @override + void initState() { + super.initState(); + const black = Color(0xFF000000); + final obj = UtilSp3dGeometry.cube(60, 200, 40, 1, 1, 1) + ..move(Sp3dV3D(0, 0, -20)) + ..materials = [ + Sp3dMaterial(black, true, 0, black, imageIndex: 0), + Sp3dMaterial(black, true, 0, black, imageIndex: 1), + FSp3dMaterial.red, + FSp3dMaterial.blue, + ] + ..fragments[0].faces[0].materialIndex = 1 + ..fragments[0].faces[2].materialIndex = 2 + ..fragments[0].faces[4].materialIndex = 3; + + world = Sp3dWorld([obj]); + + loadImages(world); + + RotationSensor.samplingPeriod = SensorInterval.uiInterval; + } + + @override + Widget build(BuildContext context) => MaterialApp( + home: Scaffold( + appBar: AppBar( + title: const Text('Rotation Sensor Example'), + ), + body: OrientationBuilder( + builder: (context, orientation) => StreamBuilder( + stream: RotationSensor.orientationStream, + builder: (context, snapshot) { + if (snapshot.hasData) { + final data = snapshot.data!; + final axisAngle = data.quaternion.invert().toAxisAngle(); + final axis = axisAngle.axis; + return Center( + child: Flex( + direction: orientation == Orientation.portrait + ? Axis.vertical + : Axis.horizontal, + children: [ + SizedBox( + width: 240, + height: 240, + child: Sp3dRenderer( + const Size(240, 240), + const Sp3dV2D(120, 120), + world, + Sp3dCamera( + Sp3dV3D(0, 0, 3000), + 3000, + rotateAxis: Sp3dV3D(axis.x, axis.y, axis.z), + radian: axisAngle.angle, + ), + Sp3dLight(Sp3dV3D(0, 0, 1)), + useUserGesture: false, + ), + ), + Expanded( + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + Text( + 'Euler:\n' + '${formatEulerAngles(data.eulerAngles)}', + textAlign: TextAlign.center, + ), + Text( + 'Quaternion:\n' + '${formatQuaternion(data.quaternion)}', + textAlign: TextAlign.center, + ), + Text( + 'Matrix:\n' + '${formatMatrix(data.rotationMatrix)}', + textAlign: TextAlign.center, + ), + Text( + 'Accuracy:\n' + '${formatDouble(data.accuracy)}', + textAlign: TextAlign.center, + ), + Text( + 'Timestamp:\n' + '${data.timestamp}', + textAlign: TextAlign.center, + ), + ], + ), + ), + ], + ), + ); + } else if (snapshot.hasError) { + return Text('Error: ${snapshot.error}'); + } else { + return const CircularProgressIndicator(); + } + }, + ), + ), + ), + ); + + Future loadImages(Sp3dWorld world) async { + world.objs[0].images = await Future.wait([ + readImageFile('./assets/images/other.png'), + readImageFile('./assets/images/top.png'), + ]); + await world.initImages(); + } + + Future readImageFile(String filePath) async { + final byteData = await rootBundle.load(filePath); + return byteData.buffer.asUint8List(); + } + + String formatQuaternion(Quaternion q) { + final f = formatDouble; + return '(${f(q.x)}, ${f(q.y)}, ${f(q.z)} @ ${f(q.w)})'; + } + + String formatMatrix(Matrix3 m) { + final f = formatDouble; + return '/${f(m[0])}, ${f(m[3])}, ${f(m[6])}\\\n' + '| ${f(m[1])}, ${f(m[4])}, ${f(m[7])} |\n' + '\\${f(m[2])}, ${f(m[5])}, ${f(m[8])}/'; + } + + String formatEulerAngles(EulerAngles e) { + final f = formatDouble; + return '(${f(e.azimuth)}, ${f(e.pitch)}, ${f(e.roll)})'; + } + + String formatDouble(double d) => d.toStringAsFixed(2).padLeft(5); + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties.add(DiagnosticsProperty('world', world)); + } +} diff --git a/example/pubspec.lock b/example/pubspec.lock new file mode 100644 index 0000000..ccc914f --- /dev/null +++ b/example/pubspec.lock @@ -0,0 +1,315 @@ +# Generated by pub +# See https://dart.dev/tools/pub/glossary#lockfile +packages: + async: + dependency: transitive + description: + name: async + sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" + url: "https://pub.dev" + source: hosted + version: "2.11.0" + boolean_selector: + dependency: transitive + description: + name: boolean_selector + sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" + url: "https://pub.dev" + source: hosted + version: "2.1.1" + characters: + dependency: transitive + description: + name: characters + sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605" + url: "https://pub.dev" + source: hosted + version: "1.3.0" + clock: + dependency: transitive + description: + name: clock + sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf + url: "https://pub.dev" + source: hosted + version: "1.1.1" + collection: + dependency: transitive + description: + name: collection + sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a + url: "https://pub.dev" + source: hosted + version: "1.18.0" + fake_async: + dependency: transitive + description: + name: fake_async + sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78" + url: "https://pub.dev" + source: hosted + version: "1.3.1" + file: + dependency: transitive + description: + name: file + sha256: "5fc22d7c25582e38ad9a8515372cd9a93834027aacf1801cf01164dac0ffa08c" + url: "https://pub.dev" + source: hosted + version: "7.0.0" + flutter: + dependency: "direct main" + description: flutter + source: sdk + version: "0.0.0" + flutter_driver: + dependency: transitive + description: flutter + source: sdk + version: "0.0.0" + flutter_lints: + dependency: "direct dev" + description: + name: flutter_lints + sha256: "3f41d009ba7172d5ff9be5f6e6e6abb4300e263aab8866d2a0842ed2a70f8f0c" + url: "https://pub.dev" + source: hosted + version: "4.0.0" + flutter_rotation_sensor: + dependency: "direct main" + description: + path: ".." + relative: true + source: path + version: "0.0.1" + flutter_test: + dependency: "direct dev" + description: flutter + source: sdk + version: "0.0.0" + fuchsia_remote_debug_protocol: + dependency: transitive + description: flutter + source: sdk + version: "0.0.0" + integration_test: + dependency: "direct dev" + description: flutter + source: sdk + version: "0.0.0" + leak_tracker: + dependency: transitive + description: + name: leak_tracker + sha256: "7f0df31977cb2c0b88585095d168e689669a2cc9b97c309665e3386f3e9d341a" + url: "https://pub.dev" + source: hosted + version: "10.0.4" + leak_tracker_flutter_testing: + dependency: transitive + description: + name: leak_tracker_flutter_testing + sha256: "06e98f569d004c1315b991ded39924b21af84cf14cc94791b8aea337d25b57f8" + url: "https://pub.dev" + source: hosted + version: "3.0.3" + leak_tracker_testing: + dependency: transitive + description: + name: leak_tracker_testing + sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3" + url: "https://pub.dev" + source: hosted + version: "3.0.1" + lints: + dependency: transitive + description: + name: lints + sha256: "976c774dd944a42e83e2467f4cc670daef7eed6295b10b36ae8c85bcbf828235" + url: "https://pub.dev" + source: hosted + version: "4.0.0" + logging: + dependency: transitive + description: + name: logging + sha256: "623a88c9594aa774443aa3eb2d41807a48486b5613e67599fb4c41c0ad47c340" + url: "https://pub.dev" + source: hosted + version: "1.2.0" + matcher: + dependency: transitive + description: + name: matcher + sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb + url: "https://pub.dev" + source: hosted + version: "0.12.16+1" + material_color_utilities: + dependency: transitive + description: + name: material_color_utilities + sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a" + url: "https://pub.dev" + source: hosted + version: "0.8.0" + meta: + dependency: transitive + description: + name: meta + sha256: "7687075e408b093f36e6bbf6c91878cc0d4cd10f409506f7bc996f68220b9136" + url: "https://pub.dev" + source: hosted + version: "1.12.0" + native_device_orientation: + dependency: transitive + description: + name: native_device_orientation + sha256: "0c330c068575e4be72cce5968ca479a3f8d5d1e5dfce7d89d5c13a1e943b338c" + url: "https://pub.dev" + source: hosted + version: "2.0.3" + path: + dependency: transitive + description: + name: path + sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" + url: "https://pub.dev" + source: hosted + version: "1.9.0" + platform: + dependency: transitive + description: + name: platform + sha256: "12220bb4b65720483f8fa9450b4332347737cf8213dd2840d8b2c823e47243ec" + url: "https://pub.dev" + source: hosted + version: "3.1.4" + plugin_platform_interface: + dependency: transitive + description: + name: plugin_platform_interface + sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02" + url: "https://pub.dev" + source: hosted + version: "2.1.8" + process: + dependency: transitive + description: + name: process + sha256: "21e54fd2faf1b5bdd5102afd25012184a6793927648ea81eea80552ac9405b32" + url: "https://pub.dev" + source: hosted + version: "5.0.2" + simple_3d: + dependency: "direct main" + description: + name: simple_3d + sha256: "8ab92d87c7be0b1f93c65d49d9f2adcd3c0d7ff16b0af9e5a5ecd4f51f27ce55" + url: "https://pub.dev" + source: hosted + version: "13.3.0" + simple_3d_renderer: + dependency: "direct main" + description: + name: simple_3d_renderer + sha256: "8ec9bad88f35d643cea038ae3b7593dc7eb490a82488fbe39f10e8ee07fea1b7" + url: "https://pub.dev" + source: hosted + version: "19.1.0" + sky_engine: + dependency: transitive + description: flutter + source: sdk + version: "0.0.99" + source_span: + dependency: transitive + description: + name: source_span + sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" + url: "https://pub.dev" + source: hosted + version: "1.10.0" + stack_trace: + dependency: transitive + description: + name: stack_trace + sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b" + url: "https://pub.dev" + source: hosted + version: "1.11.1" + stream_channel: + dependency: transitive + description: + name: stream_channel + sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7 + url: "https://pub.dev" + source: hosted + version: "2.1.2" + string_scanner: + dependency: transitive + description: + name: string_scanner + sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" + url: "https://pub.dev" + source: hosted + version: "1.2.0" + sync_http: + dependency: transitive + description: + name: sync_http + sha256: "7f0cd72eca000d2e026bcd6f990b81d0ca06022ef4e32fb257b30d3d1014a961" + url: "https://pub.dev" + source: hosted + version: "0.3.1" + term_glyph: + dependency: transitive + description: + name: term_glyph + sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 + url: "https://pub.dev" + source: hosted + version: "1.2.1" + test_api: + dependency: transitive + description: + name: test_api + sha256: "9955ae474176f7ac8ee4e989dadfb411a58c30415bcfb648fa04b2b8a03afa7f" + url: "https://pub.dev" + source: hosted + version: "0.7.0" + util_simple_3d: + dependency: "direct main" + description: + name: util_simple_3d + sha256: "2164a36207dfa1bfbba6e8c064779e7b3842deabd759d40de76454c771620ebc" + url: "https://pub.dev" + source: hosted + version: "9.4.1" + vector_math: + dependency: transitive + description: + name: vector_math + sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" + url: "https://pub.dev" + source: hosted + version: "2.1.4" + vm_service: + dependency: transitive + description: + name: vm_service + sha256: "3923c89304b715fb1eb6423f017651664a03bf5f4b29983627c4da791f74a4ec" + url: "https://pub.dev" + source: hosted + version: "14.2.1" + webdriver: + dependency: transitive + description: + name: webdriver + sha256: "003d7da9519e1e5f329422b36c4dcdf18d7d2978d1ba099ea4e45ba490ed845e" + url: "https://pub.dev" + source: hosted + version: "3.0.3" +sdks: + dart: ">=3.3.0 <4.0.0" + flutter: ">=3.18.0-18.0.pre.54" diff --git a/example/pubspec.yaml b/example/pubspec.yaml new file mode 100644 index 0000000..fcf946b --- /dev/null +++ b/example/pubspec.yaml @@ -0,0 +1,29 @@ +name: flutter_rotation_sensor_example +description: "Demonstrates how to use the flutter_rotation_sensor plugin." +publish_to: 'none' + +environment: + sdk: '>=3.2.3 <4.0.0' + +dependencies: + flutter: + sdk: flutter + flutter_rotation_sensor: + path: ../ + simple_3d: any + simple_3d_renderer: ^19.1.0 + util_simple_3d: any + +dev_dependencies: + flutter_lints: ^4.0.0 + flutter_test: + sdk: flutter + integration_test: + sdk: flutter + +flutter: + uses-material-design: true + + assets: + - 'assets/images/top.png' + - 'assets/images/other.png' diff --git a/flutter_rotation_sensor.iml b/flutter_rotation_sensor.iml new file mode 100644 index 0000000..c0043c2 --- /dev/null +++ b/flutter_rotation_sensor.iml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..034771f --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,38 @@ +.idea/ +.vagrant/ +.sconsign.dblite +.svn/ + +.DS_Store +*.swp +profile + +DerivedData/ +build/ +GeneratedPluginRegistrant.h +GeneratedPluginRegistrant.m + +.generated/ + +*.pbxuser +*.mode1v3 +*.mode2v3 +*.perspectivev3 + +!default.pbxuser +!default.mode1v3 +!default.mode2v3 +!default.perspectivev3 + +xcuserdata + +*.moved-aside + +*.pyc +*sync/ +Icon? +.tags* + +/Flutter/Generated.xcconfig +/Flutter/ephemeral/ +/Flutter/flutter_export_environment.sh diff --git a/ios/Assets/.gitkeep b/ios/Assets/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/ios/Classes/FlutterRotationSensorPlugin.swift b/ios/Classes/FlutterRotationSensorPlugin.swift new file mode 100644 index 0000000..ef8d55b --- /dev/null +++ b/ios/Classes/FlutterRotationSensorPlugin.swift @@ -0,0 +1,66 @@ +import Flutter +import UIKit +import CoreMotion + +public class FlutterRotationSensorPlugin: NSObject, FlutterPlugin, FlutterStreamHandler { + + private var eventChannel: FlutterEventChannel + private let motionManager: CMMotionManager + + public static func register(with registrar: FlutterPluginRegistrar) { + let methodChannel = FlutterMethodChannel(name: "rotation_sensor/method", binaryMessenger: registrar.messenger()) + let eventChannel = FlutterEventChannel(name: "rotation_sensor/orientation", binaryMessenger: registrar.messenger()) + let motionManager = CMMotionManager() + motionManager.deviceMotionUpdateInterval = 0.2 + let instance = RotationSensorPlugin(eventChannel: eventChannel, motionManager: motionManager) + registrar.addMethodCallDelegate(instance, channel: methodChannel) + eventChannel.setStreamHandler(instance) + } + + public init(eventChannel: FlutterEventChannel, motionManager: CMMotionManager) { + self.eventChannel = eventChannel + self.motionManager = motionManager + } + + public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { + switch call.method { + case "getOrientationStream": + if let args = call.arguments as? [String: Any], + let samplingPeriod = args["samplingPeriod"] as? Double { + motionManager.deviceMotionUpdateInterval = samplingPeriod * 0.000001 + } + result(nil) + default: + result(FlutterMethodNotImplemented) + } + } + + public func onListen(withArguments arguments: Any?, eventSink events: @escaping FlutterEventSink) -> FlutterError? { + if motionManager.isDeviceMotionAvailable { + motionManager.startDeviceMotionUpdates(to: OperationQueue()) { (motion, error) in + guard let motion = motion, error == nil else { + events(FlutterError(code: "UNAVAILABLE", message: "Device motion updates unavailable", details: nil)) + return + } + + let orientation = motion.orientation.quaternion + let rotationVector = [orientation.x, orientation.y, orientation.z, orientation.w, -1.0, Int64((motion.timestamp * 1000000000).rounded())] + DispatchQueue.main.async { + events(rotationVector) + } + } + return nil + } else { + return FlutterError(code: "NO_SENSOR", message: "Rotation vector sensor unavailable", details: nil) + } + } + + public func onCancel(withArguments arguments: Any?) -> FlutterError? { + motionManager.stopDeviceMotionUpdates() + return nil + } + + public func detachFromEngine(for registrar: FlutterPluginRegistrar) { + eventChannel.setStreamHandler(nil) + } +} diff --git a/ios/flutter_rotation_sensor.podspec b/ios/flutter_rotation_sensor.podspec new file mode 100644 index 0000000..5c88285 --- /dev/null +++ b/ios/flutter_rotation_sensor.podspec @@ -0,0 +1,30 @@ +# +# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html. +# Run `pod lib lint flutter_rotation_sensor.podspec` to validate before publishing. +# +Pod::Spec.new do |s| + s.name = 'flutter_rotation_sensor' + s.version = '0.0.1' + s.summary = <<-DESC +A package provides a stream of device's orientation in three different representations: a rotation +matrix, a quaternion, and Euler angles (azimuth, pitch, roll). + DESC + s.description = <<-DESC +A package provides a stream of device's orientation in three different representations: a rotation +matrix, a quaternion, and Euler angles (azimuth, pitch, roll). + DESC + s.homepage = 'http://example.com' + s.license = { :file => '../LICENSE' } + s.author = { 'Your Company' => 'email@example.com' } + s.source = { :path => '.' } + s.source_files = 'Classes/**/*' + s.dependency 'Flutter' + s.platform = :ios, '12.0' + + # Flutter.framework does not contain a i386 slice. + s.pod_target_xcconfig = { + 'DEFINES_MODULE' => 'YES', + 'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'i386', + } + s.swift_version = '5.0' +end diff --git a/lib/flutter_rotation_sensor.dart b/lib/flutter_rotation_sensor.dart new file mode 100644 index 0000000..816e0c5 --- /dev/null +++ b/lib/flutter_rotation_sensor.dart @@ -0,0 +1,10 @@ +export 'src/coordinate_system.dart'; +export 'src/math/axis3.dart'; +export 'src/math/axis_angle.dart'; +export 'src/math/euler_angles.dart'; +export 'src/math/matrix3.dart'; +export 'src/math/quaternion.dart'; +export 'src/math/vector3.dart'; +export 'src/orientation_event.dart'; +export 'src/rotation_sensor.dart'; +export 'src/sensor_interval.dart'; diff --git a/lib/src/coordinate_system.dart b/lib/src/coordinate_system.dart new file mode 100644 index 0000000..6afefdf --- /dev/null +++ b/lib/src/coordinate_system.dart @@ -0,0 +1,129 @@ +import 'dart:async'; + +import 'package:meta/meta.dart'; +import 'package:native_device_orientation/native_device_orientation.dart'; + +import 'math/axis3.dart'; +import 'orientation_event.dart'; + +/// An abstract class representing a standard 3-axis right-handed Cartesian +/// coordinate system to express orientation data values. +abstract class CoordinateSystem { + const CoordinateSystem(); + + factory CoordinateSystem.device() = DeviceCoordinateSystem; + + factory CoordinateSystem.display() = DisplayCoordinateSystem; + + factory CoordinateSystem.transformed( + Axis3 newX, + Axis3 newY, [ + CoordinateSystem? base, + ]) = TransformedCoordinateSystem; + + /// Applies the coordinate system transformation to the given orientation + /// event. + OrientationEvent apply(OrientationEvent event); +} + +/// A coordinate system defined relative to the device's screen when the device +/// is held in its default orientation, which is the orientation that the system +/// first uses for its boot logo, or the orientation in which the hardware logos +/// or markings are upright, or the orientation in which the cameras are at the +/// top. +/// +/// - X axis: Horizontal, points to the right of the screen in its default +/// orientation. +/// - Y axis: Vertical, points up in device's default orientation. +/// - Z axis: Points toward the outside of the screen. Coordinates behind the +/// screen have negative Z values. +class DeviceCoordinateSystem extends CoordinateSystem { + static const DeviceCoordinateSystem instance = DeviceCoordinateSystem._(); + + factory DeviceCoordinateSystem() => instance; + + const DeviceCoordinateSystem._(); + + @override + OrientationEvent apply(OrientationEvent event) => event; +} + +/// A coordinate system that adapts to the device's current orientation. It +/// adjusts based on the device's rotation. +/// +/// - X axis: Horizontal, points to the right of the current UI orientation. +/// - Y axis: Vertical, points up in current UI orientation. +/// - Z axis: Points toward the outside of the screen. Coordinates behind the +/// screen have negative Z values. +class DisplayCoordinateSystem extends CoordinateSystem { + static final DisplayCoordinateSystem instance = DisplayCoordinateSystem._(); + + late NativeDeviceOrientationCommunicator _communicator; + + @visibleForTesting + NativeDeviceOrientationCommunicator get communicator => _communicator; + + @visibleForTesting + set communicator(NativeDeviceOrientationCommunicator value) { + _communicator = value; + _orientationStreamSubscription?.cancel(); + _orientationStreamSubscription = value.onOrientationChanged().listen( + (o) => orientation = o, + ); + } + + StreamSubscription? _orientationStreamSubscription; + + @visibleForTesting + NativeDeviceOrientation orientation = NativeDeviceOrientation.portraitUp; + + factory DisplayCoordinateSystem() => instance; + + DisplayCoordinateSystem._() { + communicator = NativeDeviceOrientationCommunicator(); + } + + @override + OrientationEvent apply(OrientationEvent event) { + switch (orientation) { + case NativeDeviceOrientation.portraitUp: + return event; + case NativeDeviceOrientation.portraitDown: + return event.remapCoordinateSystem(-Axis3.X, -Axis3.Y); + case NativeDeviceOrientation.landscapeLeft: + return event.remapCoordinateSystem(-Axis3.Y, Axis3.X); + case NativeDeviceOrientation.landscapeRight: + return event.remapCoordinateSystem(Axis3.Y, -Axis3.X); + case NativeDeviceOrientation.unknown: + throw StateError('Cannot get display orientation.'); + } + } +} + +/// A coordinate system that applies a transformation on top of an optional base +/// coordinate system. If no base is provided, it defaults to the display +/// coordinate system. +/// +/// This transformation allows you to remap the coordinate axes according to +/// your application's specific requirements. The new coordinate system is +/// defined as: +/// +/// - X axis: Corresponds to the `newX` axis in the `base` coordinate system. +/// - Y axis: Corresponds to the `newY` axis in the `base` coordinate system. +/// - Z axis: Defined by the cross product of `newX` and `newY` axes in the +/// `base` coordinate system, ensuring a right-handed coordinate +/// system. +class TransformedCoordinateSystem extends CoordinateSystem { + final CoordinateSystem base; + final Axis3 newX; + final Axis3 newY; + + TransformedCoordinateSystem(this.newX, this.newY, [CoordinateSystem? base]) + : base = base ?? CoordinateSystem.display(); + + @override + OrientationEvent apply(OrientationEvent event) { + event = base.apply(event); + return event.remapCoordinateSystem(newX, newY); + } +} diff --git a/lib/src/math/axis3.dart b/lib/src/math/axis3.dart new file mode 100644 index 0000000..6b6cbd9 --- /dev/null +++ b/lib/src/math/axis3.dart @@ -0,0 +1,40 @@ +import 'package:meta/meta.dart'; + +import 'vector3.dart'; + +/// Represents an axis of a 3D coordinate system, internally storing a unit +/// vector that indicates the direction of the axis. +@immutable +class Axis3 extends Vector3 { + /// Represents an invalid axis, often used as a placeholder or error state. + static final invalid = Axis3._(0, 0, 0); + + /// Represents the X-axis of a 3D coordinate system. + static final X = Axis3._(1, 0, 0); + + /// Represents the Y-axis of a 3D coordinate system. + static final Y = Axis3._(0, 1, 0); + + /// Represents the Z-axis of a 3D coordinate system. + static final Z = Axis3._(0, 0, 1); + + Axis3._(super.x, super.y, super.z); + + /// Negates the axis vector, effectively representing the axis in the opposite + /// direction. + @override + Axis3 operator -() => Axis3._(-x, -y, -z); + + /// Converts the Axis to a human-readable string, identifying the Axis by its + /// standard Cartesian coordinate name. + @override + String toString() { + if (this == X) return 'X'; + if (this == Y) return 'Y'; + if (this == Z) return 'Z'; + if (this == -X) return '-X'; + if (this == -Y) return '-Y'; + if (this == -Z) return '-Z'; + return 'Invalid'; + } +} diff --git a/lib/src/math/axis_angle.dart b/lib/src/math/axis_angle.dart new file mode 100644 index 0000000..ec48f35 --- /dev/null +++ b/lib/src/math/axis_angle.dart @@ -0,0 +1,27 @@ +import 'dart:math'; + +import 'package:meta/meta.dart'; + +import 'quaternion.dart'; +import 'vector3.dart'; + +/// A class representing an axis-angle rotation. The rotation is defined by an +/// axis and an angle of rotation around that axis. +@immutable +class AxisAngle { + /// The axis represented by a [Vector3]. + final Vector3 axis; + + /// The angle in radians. + final double angle; + + /// Constructs an AxisAngle. + const AxisAngle(this.axis, this.angle); + + /// Converts this axis-angle representation to a quaternion. + Quaternion toQuaternion() { + final a = angle * 0.5; + final s = sin(a); + return Quaternion(s * axis.x, s * axis.y, s * axis.z, cos(a)); + } +} diff --git a/lib/src/math/euler_angles.dart b/lib/src/math/euler_angles.dart new file mode 100644 index 0000000..7fa984b --- /dev/null +++ b/lib/src/math/euler_angles.dart @@ -0,0 +1,88 @@ +import 'dart:math'; + +import 'matrix3.dart'; +import 'vector3.dart'; + +const twoPi = pi * 2; +const halfPi = pi / 2; + +/// Represents the orientation as +/// [Euler angles](https://en.wikipedia.org/wiki/Euler_angles), which are angles +/// of rotation about each of the three principal axes. The sequence of +/// rotations follows the order of azimuth (yaw), pitch, and roll. All angles +/// are in radians. This plugin utilizes +/// [intrinsic](https://en.wikipedia.org/wiki/Euler_angles#Intrinsic_rotations) +/// [Tait-Bryan angles](https://en.wikipedia.org/wiki/Euler_angles#Tait%E2%80%93Bryan_angles), +/// indicating that rotations are performed relative to the rotating reference +/// frame of the device's coordinate system (XYZ axes). +class EulerAngles extends Vector3 { + /// Angle of rotation about the -Z axis. This value represents the angle + /// between the device's Y axis and the magnetic north pole (y-axis). When + /// facing north, this angle is 0, when facing south, this angle is π. + /// Likewise, when facing east, this angle is π/2, and when facing west, this + /// angle is 3π/2. The range of values is 0(inclusive) to 2π(exclusive). + /// + /// This value is also known as [yaw]. + double get azimuth => -z; + + /// Angle of rotation about the -Z axis. This value represents the angle + /// between the device's Y axis and the magnetic north pole (y-axis). When + /// facing north, this angle is 0, when facing south, this angle is π. + /// Likewise, when facing east, this angle is π/2, and when facing west, this + /// angle is 3π/2. The range of values is 0(inclusive) to 2π(exclusive). + /// + /// This value is also known as [azimuth]. + double get yaw => -z; + + /// Angle of rotation about the X axis. This value represents the angle + /// between a plane parallel to the device's screen and a plane parallel to + /// the ground. Assuming that the bottom edge of the device faces the user and + /// that the screen is face-up, tilting the top edge of the device toward the + /// sky creates a positive pitch angle. The range of values is -π/2(inclusive) + /// to π/2(inclusive). + double get pitch => x; + + /// Angle of rotation about the Y axis. This value represents the angle + /// between a plane perpendicular to the device's screen and a plane + /// perpendicular to the ground. Assuming that the bottom edge of the device + /// faces the user and that the screen is face-up, tilting the left edge of + /// the device toward the sky creates a positive roll angle. The range of + /// values is -π(exclusive) to π(inclusive). + double get roll => y; + + /// Constructs an EulerAngles. + factory EulerAngles(double azimuth, double pitch, double roll) { + azimuth %= twoPi; + if (pitch.abs() > halfPi) { + throw UnsupportedError( + 'The value $pitch is not a valid pitch angle. A valid pitch angle must ' + 'be in the range -π/2 (inclusive) to π/2 (inclusive).', + ); + } + roll = -(-(roll + pi) % twoPi) + pi; + return EulerAngles._(pitch, roll, -azimuth); + } + + EulerAngles._(super.x, super.y, super.z); + + /// Converts this Euler angles to a rotation matrix. + Matrix3 toRotationMatrix() { + final cx = cos(x); + final cy = cos(y); + final cz = cos(z); + final sx = sin(x); + final sy = sin(y); + final sz = sin(z); + return Matrix3( + cz * cy - sz * sx * sy, + -cx * sz, + cz * sy + cy * sz * sx, + cy * sz + cz * sx * sy, + cz * cx, + sz * sy - cz * cy * sx, + -cx * sy, + sx, + cx * cy, + ); + } +} diff --git a/lib/src/math/matrix3.dart b/lib/src/math/matrix3.dart new file mode 100644 index 0000000..f2c4862 --- /dev/null +++ b/lib/src/math/matrix3.dart @@ -0,0 +1,266 @@ +import 'dart:math'; +import 'dart:typed_data'; +import 'dart:ui'; + +import 'package:meta/meta.dart'; + +import 'euler_angles.dart'; +import 'quaternion.dart'; +import 'vector3.dart'; + +/// A class representing a 3x3 matrix. +@immutable +class Matrix3 { + static const dimension = 3; + + final Float32List _m3Storage; + + /// Constructs a Matrix3 with the specified elements. + Matrix3( + double a, + double b, + double c, + double d, + double e, + double f, + double g, + double h, + double i, + ) : _m3Storage = Float32List.fromList([a, b, c, d, e, f, g, h, i]); + + /// Constructs a Matrix3 from the given row vectors. + Matrix3.rows(Vector3 r0, Vector3 r1, Vector3 r2) + : _m3Storage = Float32List.fromList( + [r0.x, r0.y, r0.z, r1.x, r1.y, r1.z, r2.x, r2.y, r2.z], + ); + + /// Constructs a Matrix3 from the given column vectors. + Matrix3.columns(Vector3 c0, Vector3 c1, Vector3 c2) + : _m3Storage = Float32List.fromList( + [c0.x, c1.x, c2.x, c0.y, c1.y, c2.y, c0.z, c1.z, c2.z], + ); + + /// Constructs a Matrix3 with all elements initialized to zero. + Matrix3.zero() : _m3Storage = Float32List(9); + + /// Constructs an identity Matrix3. + Matrix3.identity() + : _m3Storage = Float32List.fromList([1, 0, 0, 0, 1, 0, 0, 0, 1]); + + /// Constructs a rotation matrix around the X-axis. + factory Matrix3.rotateX(double r) { + final cr = cos(r); + final sr = sin(r); + return Matrix3(1, 0, 0, 0, cr, -sr, 0, sr, cr); + } + + /// Constructs a rotation matrix around the Y-axis. + factory Matrix3.rotateY(double r) { + final cr = cos(r); + final sr = sin(r); + return Matrix3(cr, 0, sr, 0, 1, 0, -sr, 0, cr); + } + + /// Constructs a rotation matrix around the Z-axis. + factory Matrix3.rotateZ(double r) { + final cr = cos(r); + final sr = sin(r); + return Matrix3(cr, -sr, 0, sr, cr, 0, 0, 0, 1); + } + + /// Determines whether this matrix is equal to another object. Returns true + /// if the other object is an Matrix3 with the same elements. + @override + bool operator ==(Object other) => + identical(this, other) || + other is Matrix3 && + a == other.a && + b == other.b && + c == other.c && + d == other.d && + e == other.e && + f == other.f && + g == other.g && + h == other.h && + i == other.i; + + @override + int get hashCode => Object.hash(a, b, c, d, e, f, g, h, i); + + @override + String toString() => '⌈$a,$b,$c⌉\n|$d,$e,$f|\n⌊$g,$h,$i⌋\n'; + + /// Returns the element at the first row and first column. + double get a => _m3Storage[0]; + + /// Returns the element at the first row and second column. + double get b => _m3Storage[1]; + + /// Returns the element at the first row and third column. + double get c => _m3Storage[2]; + + /// Returns the element at the second row and first column. + double get d => _m3Storage[3]; + + /// Returns the element at the second row and second column. + double get e => _m3Storage[4]; + + /// Returns the element at the second row and third column. + double get f => _m3Storage[5]; + + /// Returns the element at the third row and first column. + double get g => _m3Storage[6]; + + /// Returns the element at the third row and second column. + double get h => _m3Storage[7]; + + /// Returns the element at the third row and third column. + double get i => _m3Storage[8]; + + /// Returns the element at the given index in row major order. + double operator [](int i) => _m3Storage[i]; + + /// Returns the row at the given index. + Vector3 row(int r) { + final i = r * 3; + return Vector3(this[i + 0], this[i + 1], this[i + 2]); + } + + /// Returns the column at the given index. + Vector3 column(int c) => Vector3(this[0 + c], this[3 + c], this[6 + c]); + + /// Returns the negation of this matrix. + Matrix3 operator -() => Matrix3(-a, -b, -c, -d, -e, -f, -g, -h, -i); + + /// Adds the given matrix to this matrix. + Matrix3 operator +(Matrix3 o) => Matrix3( + a + o.a, + b + o.b, + c + o.c, + d + o.d, + e + o.e, + f + o.f, + g + o.g, + h + o.h, + i + o.i, + ); + + /// Subtracts the given matrix from this matrix. + Matrix3 operator -(Matrix3 o) => Matrix3( + a - o.a, + b - o.b, + c - o.c, + d - o.d, + e - o.e, + f - o.f, + g - o.g, + h - o.h, + i - o.i, + ); + + /// Multiplies this matrix by the given scalar. + Matrix3 operator *(double s) => + Matrix3(a * s, b * s, c * s, d * s, e * s, f * s, g * s, h * s, i * s); + + /// Divides this matrix by the given scalar. + Matrix3 operator /(double s) => + Matrix3(a / s, b / s, c / s, d / s, e / s, f / s, g / s, h / s, i / s); + + /// Multiplies this matrix by the given matrix. + Matrix3 multiply(Matrix3 o) => Matrix3( + a * o.a + b * o.d + c * o.g, + a * o.b + b * o.e + c * o.h, + a * o.c + b * o.f + c * o.i, + d * o.a + e * o.d + f * o.g, + d * o.b + e * o.e + f * o.h, + d * o.c + e * o.f + f * o.i, + g * o.a + h * o.d + i * o.g, + g * o.b + h * o.e + i * o.h, + g * o.c + h * o.f + i * o.i, + ); + + /// Returns the trace of this matrix. + double get trace => a + e + i; + + /// Returns the determinant of this matrix. + double get determinant => + a * e * i + b * f * g + c * d * h - a * f * h - b * d * i - c * e * g; + + /// Returns the transpose of this matrix. + Matrix3 transpose() => Matrix3(a, d, g, b, e, h, c, f, i); + + /// Returns the adjoint of this matrix. + Matrix3 adjoint() => Matrix3( + e * i - f * h, + c * h - b * i, + b * f - c * e, + f * g - d * i, + a * i - c * g, + c * d - a * f, + d * h - e * g, + b * g - a * h, + a * e - b * d, + ); + + /// Returns the inverse of this matrix. + /// If the determinant is zero, returns this matrix. + Matrix3 invert() { + final t = determinant; + if (t == 0) { + return this; + } else { + return Matrix3( + (e * i - f * h) / t, + (c * h - b * i) / t, + (b * f - c * e) / t, + (f * g - d * i) / t, + (a * i - c * g) / t, + (c * d - a * f) / t, + (d * h - e * g) / t, + (b * g - a * h) / t, + (a * e - b * d) / t, + ); + } + } + + /// Applies the given function to each element of the matrix. + Matrix3 apply(double Function(double) t) => + Matrix3(t(a), t(b), t(c), t(d), t(e), t(f), t(g), t(h), t(i)); + + /// Converts this matrix to Euler angles. + EulerAngles toEulerAngles() { + final x = asin(clampDouble(h, -1, 1)); + final double y; + final double z; + if (h.abs() < 0.9999999) { + y = atan2(-g, i); + z = atan2(-b, e); + } else { + y = 0; + z = atan2(d, a); + } + return EulerAngles(-z, x, y); + } + + /// Converts this matrix to a quaternion. + Quaternion toQuaternion() { + final t = trace; + if (t > 0) { + final s = sqrt(t + 1); + final r = 0.5 / s; + return Quaternion((h - f) * r, (c - g) * r, (d - b) * r, s * 0.5); + } else { + final u = a < e ? (e < i ? 2 : 1) : (a < i ? 2 : 0); + final v = (u + 1) % 3; + final w = (u + 2) % 3; + final s = sqrt(this[u * 4] - this[v * 4] - this[w * 4] + 1); + final q = Float32List(4); + final r = 0.5 / s; + q[u] = s * 0.5; + q[v] = (this[v * 3 + u] + this[u * 3 + v]) * r; + q[w] = (this[w * 3 + u] + this[u * 3 + w]) * r; + q[3] = (this[w * 3 + v] - this[v * 3 + w]) * r; + return Quaternion(q[0], q[1], q[2], q[3]); + } + } +} diff --git a/lib/src/math/quaternion.dart b/lib/src/math/quaternion.dart new file mode 100644 index 0000000..8c9d56e --- /dev/null +++ b/lib/src/math/quaternion.dart @@ -0,0 +1,158 @@ +import 'dart:math'; +import 'dart:typed_data'; + +import 'package:meta/meta.dart'; + +import 'axis_angle.dart'; +import 'matrix3.dart'; +import 'vector3.dart'; + +/// A class representing a quaternion. +/// +/// The quaternion number system extends the complex numbers. Quaternions have +/// practical uses in applied mathematics, particularly for calculations +/// involving three-dimensional rotations, such as in three-dimensional computer +/// graphics, computer vision, magnetic resonance imaging and crystallographic +/// texture analysis. They can be used alongside other methods of rotation, such +/// as Euler angles and rotation matrices, or as an alternative to them, +/// depending on the application. +@immutable +class Quaternion { + final Float32List _qStorage; + + /// Constructs a Quaternion with given x, y, z, w components + Quaternion(double x, double y, double z, double w) + : _qStorage = Float32List.fromList([x, y, z, w]); + + /// constructs an identity Quaternion (0, 0, 0, 1) + factory Quaternion.identity() => Quaternion(0, 0, 0, 1); + + /// Determines whether this quaternion is equal to another object. Returns + /// true if the other object is an Quaternion with the same components. + @override + bool operator ==(Object other) => + identical(this, other) || + other is Quaternion && + x == other.x && + y == other.y && + z == other.z && + w == other.w; + + @override + int get hashCode => Object.hash(x, y, z, w); + + @override + String toString() => '$x, $y, $z @ $w'; + + /// The x component of the quaternion. + double get x => _qStorage[0]; + + /// The y component of the quaternion. + double get y => _qStorage[1]; + + /// The z component of the quaternion. + double get z => _qStorage[2]; + + /// The w component of the quaternion. + double get w => _qStorage[3]; + + /// Negates this quaternion. + Quaternion operator -() => Quaternion(-x, -y, -z, -w); + + /// Adds this quaternion with another [Quaternion]. + Quaternion operator +(Quaternion o) => + Quaternion(x + o.x, y + o.y, z + o.z, w + o.w); + + /// Subtracts another [Quaternion] from this quaternion. + Quaternion operator -(Quaternion o) => + Quaternion(x - o.x, y - o.y, z - o.z, w - o.w); + + /// Multiplies this quaternion by a scalar. + Quaternion operator *(double s) => Quaternion(x * s, y * s, z * s, w * s); + + /// Divides this quaternion by a scalar. + Quaternion operator /(double s) => Quaternion(x / s, y / s, z / s, w / s); + + /// Computes the Hamilton product of this quaternion with another + /// [Quaternion]. + Quaternion multiply(Quaternion o) => Quaternion( + w * o.x + x * o.w + y * o.z - z * o.y, + w * o.y + y * o.w + z * o.x - x * o.z, + w * o.z + z * o.w + x * o.y - y * o.x, + w * o.w - x * o.x - y * o.y - z * o.z, + ); + + /// The squared length of this quaternion. + double get length2 => x * x + y * y + z * z + w * w; + + /// The length (magnitude) of this quaternion. + double get length => sqrt(length2); + + /// Normalizes this quaternion. + Quaternion normalize() { + final l = length; + if (l == 0) { + return this; + } else { + return this / l; + } + } + + /// Returns the conjugate of this quaternion. + Quaternion conjugate() => Quaternion(-x, -y, -z, w); + + /// Inverts the quaternion. + Quaternion invert() { + final l = length2; + return Quaternion(-x / l, -y / l, -z / l, w / l); + } + + /// Applies a function [f] to each component of this quaternion and returns a + /// new [Quaternion]. + Quaternion apply(double Function(double) f) => + Quaternion(f(x), f(y), f(z), f(w)); + + /// Converts quaternion to axis-angle representation. + AxisAngle toAxisAngle() { + final d = 1 - (w * w); + if (d < 0.00001) { + return AxisAngle(Vector3.zero(), 0); + } else { + final s = sqrt(d); + return AxisAngle(Vector3(x / s, y / s, z / s), 2 * acos(w)); + } + } + + /// Converts quaternion to rotation matrix. + Matrix3 toRotationMatrix() { + final l = length2; + assert(l != 0.0, 'Cannot convert a zero quaternion to rotation matrix.'); + final s = 2.0 / l; + + final xs = x * s; + final ys = y * s; + final zs = z * s; + + final wx = w * xs; + final wy = w * ys; + final wz = w * zs; + final xx = x * xs; + final xy = x * ys; + final xz = x * zs; + final yy = y * ys; + final yz = y * zs; + final zz = z * zs; + + return Matrix3( + 1 - yy - zz, + xy - wz, + xz + wy, + xy + wz, + 1 - xx - zz, + yz - wx, + xz - wy, + yz + wx, + 1 - xx - yy, + ); + } +} diff --git a/lib/src/math/vector3.dart b/lib/src/math/vector3.dart new file mode 100644 index 0000000..5fbe4c9 --- /dev/null +++ b/lib/src/math/vector3.dart @@ -0,0 +1,82 @@ +import 'dart:math'; +import 'dart:typed_data'; + +import 'package:meta/meta.dart'; + +/// A 3D vector class for representing and manipulating vectors in +/// three-dimensional space. +@immutable +class Vector3 { + final Float32List _v3Storage; + + /// Constructs a [Vector3] with the given [x], [y], and [z] components. + Vector3(double x, double y, double z) + : _v3Storage = Float32List.fromList([x, y, z]); + + /// Constructs a [Vector3] initialized to zero (0, 0, 0). + Vector3.zero() : _v3Storage = Float32List(3); + + /// Determines whether this vector is equal to another object. Returns true if + /// the other object is an Vector3 with the same components. + @override + bool operator ==(Object other) => + identical(this, other) || + other is Vector3 && x == other.x && y == other.y && z == other.z; + + @override + int get hashCode => Object.hash(x, y, z); + + @override + String toString() => '[$x,$y,$z]'; + + /// The x component of the vector. + double get x => _v3Storage[0]; + + /// The y component of the vector. + double get y => _v3Storage[1]; + + /// The z component of the vector. + double get z => _v3Storage[2]; + + /// Negates this vector. + Vector3 operator -() => Vector3(-x, -y, -z); + + /// Adds this vector with another [Vector3]. + Vector3 operator +(Vector3 o) => Vector3(x + o.x, y + o.y, z + o.z); + + /// Subtracts another [Vector3] from this vector. + Vector3 operator -(Vector3 o) => Vector3(x - o.x, y - o.y, z - o.z); + + /// Multiplies this vector by a scalar. + Vector3 operator *(double s) => Vector3(x * s, y * s, z * s); + + /// Divides this vector by a scalar. + Vector3 operator /(double s) => Vector3(x / s, y / s, z / s); + + /// Computes the dot product of this vector with another [Vector3]. + double dot(Vector3 o) => x * o.x + y * o.y + z * o.z; + + /// Computes the cross product of this vector with another [Vector3]. + Vector3 cross(Vector3 o) => + Vector3(y * o.z - z * o.y, z * o.x - x * o.z, x * o.y - y * o.x); + + /// The squared length of this vector. + double get length2 => x * x + y * y + z * z; + + /// The length (magnitude) of this vector. + double get length => sqrt(length2); + + /// Normalizes this vector. + Vector3 normalize() { + final l = length; + if (l == 0) { + return this; + } else { + return this / l; + } + } + + /// Applies a function [f] to each component of this vector and returns a new + /// [Vector3]. + Vector3 apply(double Function(double) f) => Vector3(f(x), f(y), f(z)); +} diff --git a/lib/src/orientation_event.dart b/lib/src/orientation_event.dart new file mode 100644 index 0000000..5668c4f --- /dev/null +++ b/lib/src/orientation_event.dart @@ -0,0 +1,110 @@ +import 'math/axis3.dart'; +import 'math/euler_angles.dart'; +import 'math/matrix3.dart'; +import 'math/quaternion.dart'; + +/// Represents an orientation event detected by sensors, providing information +/// about the orientation of the device. +/// +/// The device's coordinate system is defined relative to the screen in its +/// default orientation. It remains unchanged when the device's screen +/// orientation changes. +/// - X axis: Horizontal and points to the right. +/// - Y axis: Vertical and points up. +/// - Z axis: Points towards the outside of the front face of the screen. +/// Coordinates behind the screen have negative Z values. +/// +/// The world coordinate system is defined as a direct orthonormal basis: +/// - x axis: Defined as the vector cross product y⨯z. It is tangential to the +/// ground at the device's current location and roughly points East. +/// - y axis: Tangential to the ground at the device's current location and +/// points towards magnetic north. +/// - z axis: Points towards the sky and is perpendicular to the ground. +/// +/// A +/// [right-handed reference frame](https://en.wikipedia.org/wiki/Right-hand_rule) +/// is adopted, with the +/// [right-hand rule](https://en.wikipedia.org/wiki/Right-hand_rule) used to +/// determine the sign of the angles. +class OrientationEvent { + /// The orientation of the device represented as a quaternion. + final Quaternion quaternion; + + /// An estimated accuracy of the sensor data (in radians). The actual device + /// orientation is expected to be within this margin of error. If the accuracy + /// is unavailable, this value is -1. Accuracy information was introduced in + /// Android SDK level 18, but not all devices support it. For iOS devices, + /// this is always -1. + final double accuracy; + + /// The timestamp at which the event was recorded, in microseconds since + /// some arbitrary point in time, usually the time of system boot. + final int timestamp; + + /// The coordinate system in which the orientation is expressed, represented + /// as a 3x3 matrix. + final Matrix3 coordinateSystem; + + /// Constructs an [OrientationEvent] with the given [quaternion], [accuracy], + /// and [timestamp]. The [coordinateSystem] is initialized to the identity + /// matrix, representing the device's default coordinate system. + OrientationEvent({ + required this.quaternion, + required this.accuracy, + required this.timestamp, + }) : coordinateSystem = Matrix3.identity(); + + /// Constructs an [OrientationEvent] with a specific coordinate system. + OrientationEvent._( + this.quaternion, + this.accuracy, + this.timestamp, + this.coordinateSystem, + ); + + @override + String toString() => 'OrientationEvent(\n' + 'quaternion: $quaternion,\n' + 'accuracy: $accuracy,\n' + 'timestamp: $timestamp,\n' + 'coordinateSystem:\n' + '$coordinateSystem' + ')'; + + /// The orientation of the device represented as a rotation matrix. + Matrix3 get rotationMatrix => quaternion.toRotationMatrix(); + + /// The orientation of the device represented as euler angles (azimuth, pitch, + /// roll). + EulerAngles get eulerAngles => rotationMatrix.toEulerAngles(); + + /// Remaps the device coordinate system of this [OrientationEvent] to a new + /// coordinate system defined by the specified 'newX' and 'newY' axes. + /// + /// The 'newZ' axis is calculated as the cross product of 'newX' and 'newY'. + /// + /// Throws an [UnsupportedError] if 'newX' and 'newY' are not orthogonal or if + /// they are identical. + /// + /// Returns a new [OrientationEvent] instance with the remapped coordinate + /// system and updated quaternion representing the orientation in the new + /// system. + OrientationEvent remapCoordinateSystem(Axis3 newX, Axis3 newY) { + final newZ = newX.cross(newY); + if (newZ.length2 != 1) { + throw UnsupportedError( + 'The specified axes for newX and newY are not orthogonal or are ' + 'identical. Please specify two different, non-parallel axes that are ' + 'orthogonal to each other.', + ); + } + final transformMatrix = Matrix3.columns(newX, newY, newZ); + + return OrientationEvent._( + quaternion.multiply(transformMatrix.toQuaternion()), + accuracy, + timestamp, + coordinateSystem.multiply(transformMatrix), + ); + } +} diff --git a/lib/src/rotation_sensor.dart b/lib/src/rotation_sensor.dart new file mode 100644 index 0000000..ad948aa --- /dev/null +++ b/lib/src/rotation_sensor.dart @@ -0,0 +1,49 @@ +import 'package:meta/meta.dart'; + +import 'coordinate_system.dart'; +import 'orientation_event.dart'; +import 'rotation_sensor_platform_interface.dart'; +import 'sensor_interval.dart'; + +/// Provides access to the device's rotation sensor, offering a real-time stream +/// of the device's orientation. +/// +/// This class allows applications to retrieve a stream of [OrientationEvent]s +/// which include the device's orientation represented as a rotation matrix, +/// quaternion, and Euler angles (azimuth, pitch, roll). +@sealed +class RotationSensor { + @visibleForTesting + static RotationSensorPlatform platform = RotationSensorPlatform.instance; + + /// A broadcast [Stream] of [OrientationEvent]s which emits events containing + /// the orientation of the device from the device's rotation sensor. + static Stream get orientationStream => + RotationSensorPlatform.instance.orientationStream; + + /// The [samplingPeriod] for the device's rotation sensor. The events may + /// arrive at a rate faster or slower than the [samplingPeriod], which is only + /// a hint to the system. The actual rate depends on the system's event queue + /// and sensor hardware capabilities. + /// + /// Defaults to [SensorInterval.normalInterval]. It can be set to other + /// predefined [SensorInterval] values or any [Duration] as needed to suit + /// different use cases such as gaming or UI responsiveness. When changing + /// this value, all existing listeners will be affected. + static Duration get samplingPeriod => + RotationSensorPlatform.instance.samplingPeriod; + + static set samplingPeriod(Duration value) => + RotationSensorPlatform.instance.samplingPeriod = value; + + /// The [coordinateSystem] used for upcoming [OrientationEvent]. + /// + /// Defaults to [DisplayCoordinateSystem]. When changing this value, all + /// existing listeners will receive [OrientationEvent] in the new coordinate + /// system. + static CoordinateSystem get coordinateSystem => + RotationSensorPlatform.instance.coordinateSystem; + + static set coordinateSystem(CoordinateSystem value) => + RotationSensorPlatform.instance.coordinateSystem = value; +} diff --git a/lib/src/rotation_sensor_method_channel.dart b/lib/src/rotation_sensor_method_channel.dart new file mode 100644 index 0000000..d90a4b1 --- /dev/null +++ b/lib/src/rotation_sensor_method_channel.dart @@ -0,0 +1,51 @@ +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; + +import 'math/quaternion.dart'; +import 'orientation_event.dart'; +import 'rotation_sensor_platform_interface.dart'; + +/// An implementation of [RotationSensorPlatform] that uses method channels. +class MethodChannelRotationSensor extends RotationSensorPlatform { + /// The method channel used to interact with the native platform. + @visibleForTesting + static const methodChannel = MethodChannel('rotation_sensor/method'); + + /// The event channel used to receive orientation events from the native + /// platform. + @visibleForTesting + static const eventChannel = EventChannel('rotation_sensor/orientation'); + + Stream? _orientationStream; + + /// A broadcast [Stream] of [OrientationEvent]s which emits events containing + /// the orientation of the device from the device's rotation sensor. + @override + Stream get orientationStream { + if (_orientationStream != null) { + return _orientationStream!; + } + methodChannel.invokeMethod('getOrientationStream', { + 'samplingPeriod': samplingMicroseconds, + }); + return _orientationStream = + eventChannel.receiveBroadcastStream().map((event) { + final data = event as List; + final orientationEvent = OrientationEvent( + quaternion: Quaternion(data[0], data[1], data[2], data[3]), + accuracy: data[4], + timestamp: data[5], + ); + return coordinateSystem.apply(orientationEvent); + }); + } + + @override + @protected + void updateSamplingPeriod(int value) { + methodChannel.invokeMethod('getOrientationStream', { + 'samplingPeriod': value, + }); + } +} diff --git a/lib/src/rotation_sensor_platform_interface.dart b/lib/src/rotation_sensor_platform_interface.dart new file mode 100644 index 0000000..aeb337b --- /dev/null +++ b/lib/src/rotation_sensor_platform_interface.dart @@ -0,0 +1,75 @@ +import 'package:logging/logging.dart'; +import 'package:meta/meta.dart'; +import 'package:plugin_platform_interface/plugin_platform_interface.dart'; + +import 'coordinate_system.dart'; +import 'orientation_event.dart'; +import 'rotation_sensor_method_channel.dart'; +import 'sensor_interval.dart'; + +/// The interface that implementations of rotation_sensor must implement. +abstract class RotationSensorPlatform extends PlatformInterface { + /// Constructs a RotationSensorPlatform. + RotationSensorPlatform() : super(token: _token); + + static final Object _token = Object(); + + /// The default instance of [RotationSensorPlatform] to use. + static RotationSensorPlatform _instance = MethodChannelRotationSensor(); + + static RotationSensorPlatform get instance => _instance; + + static set instance(RotationSensorPlatform instance) { + PlatformInterface.verifyToken(instance, _token); + _instance = instance; + } + + final logger = Logger('MethodChannelRotationSensor'); + + /// A broadcast [Stream] of [OrientationEvent]s which emits events containing + /// the orientation of the device from the device's rotation sensor. + Stream get orientationStream; + + @protected + int samplingMicroseconds = SensorInterval.normalInterval.inMicroseconds; + + /// The [samplingPeriod] for the device's rotation sensor. The events may + /// arrive at a rate faster or slower than the [samplingPeriod], which is only + /// a hint to the system. The actual rate depends on the system's event queue + /// and sensor hardware capabilities. + /// + /// Defaults to [SensorInterval.normalInterval]. It can be set to other + /// predefined [SensorInterval] values or any [Duration] as needed to suit + /// different use cases such as gaming or UI responsiveness. When changing + /// this value, all existing listeners will be affected. + Duration get samplingPeriod => Duration(microseconds: samplingMicroseconds); + + set samplingPeriod(Duration value) { + samplingMicroseconds = value.inMicroseconds; + if (samplingMicroseconds >= 1 && samplingMicroseconds <= 3) { + logger.warning( + 'The sampling period is currently set to $samplingMicrosecondsμs, ' + 'which is a reserved value in Android. Please consider changing it to ' + // ignore: missing_whitespace_between_adjacent_strings + 'either 0 or 4μs. See https://developer.android.com/reference/android/' + 'hardware/SensorManager#registerListener(android.hardware.' + 'SensorEventListener,%20android.hardware.Sensor,%20int) for more ' + 'information.', + ); + samplingMicroseconds = 0; + } + updateSamplingPeriod(samplingMicroseconds); + } + + /// The [coordinateSystem] used for upcoming [OrientationEvent]. + /// + /// Defaults to [DisplayCoordinateSystem]. When changing this value, all + /// existing listeners will receive [OrientationEvent] in the new coordinate + /// system. + CoordinateSystem coordinateSystem = CoordinateSystem.display(); + + @protected + void updateSamplingPeriod(int value) { + // no-op + } +} diff --git a/lib/src/sensor_interval.dart b/lib/src/sensor_interval.dart new file mode 100644 index 0000000..51f39de --- /dev/null +++ b/lib/src/sensor_interval.dart @@ -0,0 +1,25 @@ +import 'package:meta/meta.dart'; + +/// Defines some common intervals for sensor data updates. +@sealed +class SensorInterval { + /// Default update interval suitable for tracking screen orientation changes. + /// This is a balanced rate that does not demand high processing power and is + /// sufficient for most applications that react to orientation changes. + static const normalInterval = Duration(milliseconds: 200); + + /// Update interval optimised for user interface responsiveness. This faster + /// rate is appropriate when the UI needs to update smoothly in response to + /// sensor data, such as in animations or transitions. + static const uiInterval = Duration(milliseconds: 66, microseconds: 667); + + /// High-frequency update interval suitable for gaming applications. Provides + /// more frequent updates to ensure game mechanics based on sensor data are + /// responsive and provide a fluid experience. + static const gameInterval = Duration(milliseconds: 20); + + /// The fastest possible update interval for sensor data. This setting is for + /// applications that require real-time updates from the sensor, such as those + /// needed for precise scientific measurements or advanced simulation. + static const fastestInterval = Duration.zero; +} diff --git a/pubspec.yaml b/pubspec.yaml new file mode 100644 index 0000000..3443a13 --- /dev/null +++ b/pubspec.yaml @@ -0,0 +1,43 @@ +name: flutter_rotation_sensor +description: > + A package provides a stream of device's orientation in three different representations: a rotation + matrix, a quaternion, and Euler angles (azimuth, pitch, roll). +version: 0.0.1 +repository: https://github.com/tlserver/flutter_rotation_sensor + +environment: + sdk: '>=3.2.3 <4.0.0' + flutter: '>=3.3.0' + +topics: + - rotation + - orientation + - heading + - sensor + - compass + +dependencies: + flutter: + sdk: flutter + logging: ^1.2.0 + # flutter_test depends on meta, so use any + meta: any + native_device_orientation: ^2.0.3 + plugin_platform_interface: ^2.1.8 + +dev_dependencies: + build_runner: ^2.4.11 + flutter_lints: ^4.0.0 + flutter_test: + sdk: flutter + lint: ^2.3.0 + mockito: ^5.4.4 + +flutter: + plugin: + platforms: + android: + package: net.tlserver6y.flutter_rotation_sensor + pluginClass: FlutterRotationSensorPlugin + ios: + pluginClass: FlutterRotationSensorPlugin diff --git a/test/coordinate_system_test.dart b/test/coordinate_system_test.dart new file mode 100644 index 0000000..3eb8643 --- /dev/null +++ b/test/coordinate_system_test.dart @@ -0,0 +1,175 @@ +import 'dart:async'; + +import 'package:flutter_rotation_sensor/flutter_rotation_sensor.dart'; +import 'package:flutter_rotation_sensor/src/rotation_sensor_method_channel.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mockito/annotations.dart'; +import 'package:mockito/mockito.dart'; +import 'package:native_device_orientation/native_device_orientation.dart'; + +@GenerateNiceMocks([MockSpec()]) +import 'coordinate_system_test.mocks.dart'; + +void main() { + TestWidgetsFlutterBinding.ensureInitialized(); + + final platform = MethodChannelRotationSensor(); + final binaryMessenger = + TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger; + const methodChannel = MethodChannelRotationSensor.methodChannel; + const orientationChannel = MethodChannelRotationSensor.eventChannel; + // ignore: close_sinks + late StreamController oeStreamController; + late int expectedSamplingPeriod; + + setUp(() { + oeStreamController = StreamController(); + expectedSamplingPeriod = platform.samplingPeriod.inMicroseconds; + binaryMessenger + ..setMockMethodCallHandler( + methodChannel, + (methodCall) async { + switch (methodCall.method) { + case 'getOrientationStream': + final arguments = methodCall.arguments as Map; + final samplingPeriod = arguments['samplingPeriod'] as int; + expect(samplingPeriod, expectedSamplingPeriod); + return null; + default: + throw UnsupportedError(methodCall.method); + } + }, + ) + ..setMockStreamHandler( + orientationChannel, + MockStreamHandler.inline( + onListen: (args, sink) => oeStreamController.stream.listen( + (_) => sink.success([ + // Quaternion + 0.0, 0.0, 0.0, 1.0, + // Accuracy + -1.0, + // Timestamp + 123456789, + ]), + onDone: () => sink.endOfStream(), + ), + ), + ); + }); + + tearDown(() async { + await oeStreamController.sink.close(); + binaryMessenger + ..setMockMethodCallHandler(methodChannel, null) + ..setMockStreamHandler(orientationChannel, null); + }); + + test( + 'orientationStream emit OrientationEvent in device coordinate system', + () async { + platform.coordinateSystem = CoordinateSystem.device(); + oeStreamController.sink.add(null); + final orientationEvent = await platform.orientationStream.first; + expect( + orientationEvent.coordinateSystem, + equals(Matrix3.identity()), + ); + }, + ); + + test( + 'orientationStream emit OrientationEvent in display coordinate system', + () async { + final displayCoordinateSystem = DisplayCoordinateSystem(); + platform.coordinateSystem = displayCoordinateSystem; + final ndoStreamController = + StreamController.broadcast(); + final mockCommunicator = MockNativeDeviceOrientationCommunicator(); + when(mockCommunicator.onOrientationChanged()).thenAnswer( + (_) => ndoStreamController.stream, + ); + displayCoordinateSystem.communicator = mockCommunicator; + expect(displayCoordinateSystem.communicator, equals(mockCommunicator)); + + final orientations = [ + NativeDeviceOrientation.portraitUp, + NativeDeviceOrientation.landscapeRight, + NativeDeviceOrientation.portraitDown, + NativeDeviceOrientation.landscapeLeft, + ]; + + final orientationEventsFuture = + platform.orientationStream.take(orientations.length).toList(); + for (final orientation in orientations) { + ndoStreamController.sink.add(orientation); + await Future.delayed(const Duration(microseconds: 1), () {}); + oeStreamController.sink.add(null); + await Future.delayed(const Duration(microseconds: 1), () {}); + } + final orientationEvents = await orientationEventsFuture; + + for (var t = 0, e = Matrix3.identity(); + t < orientationEvents.length; + t++, e = e.multiply(Matrix3(0, -1, 0, 1, 0, 0, 0, 0, 1))) { + final orientationEvent = orientationEvents[t]; + expect( + orientationEvent.coordinateSystem, + equals(e), + reason: 'orientationEvents[$t]', + ); + } + + ndoStreamController.sink.add(NativeDeviceOrientation.portraitUp); + await ndoStreamController.close(); + }, + ); + + test( + 'orientationStream emit error in display coordinate system', + () async { + final displayCoordinateSystem = DisplayCoordinateSystem(); + platform.coordinateSystem = displayCoordinateSystem; + final ndoStreamController = + StreamController.broadcast(); + final mockCommunicator = MockNativeDeviceOrientationCommunicator(); + when(mockCommunicator.onOrientationChanged()).thenAnswer( + (_) => ndoStreamController.stream, + ); + displayCoordinateSystem.communicator = mockCommunicator; + expect(displayCoordinateSystem.communicator, equals(mockCommunicator)); + + ndoStreamController.sink.add(NativeDeviceOrientation.unknown); + await Future.delayed(const Duration(microseconds: 1), () {}); + oeStreamController.sink.add(null); + await Future.delayed(const Duration(microseconds: 1), () {}); + await expectLater( + () => platform.orientationStream.first, + throwsStateError, + ); + + ndoStreamController.sink.add(NativeDeviceOrientation.portraitUp); + await ndoStreamController.close(); + }, + ); + + test( + 'orientationStream emit OrientationEvent in transformed coordinate system', + () async { + platform.coordinateSystem = CoordinateSystem.transformed( + Axis3.X, + Axis3.Z, + CoordinateSystem.transformed( + Axis3.X, + Axis3.Y, + ), + ); + oeStreamController.sink.add(null); + final orientationEvent = await platform.orientationStream.first; + expect( + orientationEvent.coordinateSystem, + equals(Matrix3(1, 0, 0, 0, 0, -1, 0, 1, 0)), + ); + }, + ); +} diff --git a/test/coordinate_system_test.mocks.dart b/test/coordinate_system_test.mocks.dart new file mode 100644 index 0000000..0499cc8 --- /dev/null +++ b/test/coordinate_system_test.mocks.dart @@ -0,0 +1,93 @@ +// Mocks generated by Mockito 5.4.4 from annotations +// in rotation_sensor/test/coordinate_system_test.dart. +// Do not manually edit this file. + +// ignore_for_file: no_leading_underscores_for_library_prefixes +import 'dart:async' as _i3; + +import 'package:mockito/mockito.dart' as _i1; +import 'package:native_device_orientation/src/native_device_orientation.dart' + as _i4; +import 'package:native_device_orientation/src/native_device_orientation_communicator.dart' + as _i2; + +// ignore_for_file: type=lint +// ignore_for_file: avoid_redundant_argument_values +// ignore_for_file: avoid_setters_without_getters +// ignore_for_file: comment_references +// ignore_for_file: deprecated_member_use +// ignore_for_file: deprecated_member_use_from_same_package +// ignore_for_file: implementation_imports +// ignore_for_file: invalid_use_of_visible_for_testing_member +// ignore_for_file: prefer_const_constructors +// ignore_for_file: unnecessary_parenthesis +// ignore_for_file: camel_case_types +// ignore_for_file: subtype_of_sealed_class + +/// A class which mocks [NativeDeviceOrientationCommunicator]. +/// +/// See the documentation for Mockito's code generation for more information. +class MockNativeDeviceOrientationCommunicator extends _i1.Mock + implements _i2.NativeDeviceOrientationCommunicator { + @override + _i3.Future<_i4.NativeDeviceOrientation> orientation({ + bool? useSensor = false, + _i4.NativeDeviceOrientation? defaultOrientation = + _i4.NativeDeviceOrientation.portraitUp, + }) => + (super.noSuchMethod( + Invocation.method( + #orientation, + [], + { + #useSensor: useSensor, + #defaultOrientation: defaultOrientation, + }, + ), + returnValue: _i3.Future<_i4.NativeDeviceOrientation>.value( + _i4.NativeDeviceOrientation.portraitUp), + returnValueForMissingStub: + _i3.Future<_i4.NativeDeviceOrientation>.value( + _i4.NativeDeviceOrientation.portraitUp), + ) as _i3.Future<_i4.NativeDeviceOrientation>); + + @override + _i3.Future pause() => (super.noSuchMethod( + Invocation.method( + #pause, + [], + ), + returnValue: _i3.Future.value(), + returnValueForMissingStub: _i3.Future.value(), + ) as _i3.Future); + + @override + _i3.Future resume() => (super.noSuchMethod( + Invocation.method( + #resume, + [], + ), + returnValue: _i3.Future.value(), + returnValueForMissingStub: _i3.Future.value(), + ) as _i3.Future); + + @override + _i3.Stream<_i4.NativeDeviceOrientation> onOrientationChanged({ + bool? useSensor = false, + _i4.NativeDeviceOrientation? defaultOrientation = + _i4.NativeDeviceOrientation.portraitUp, + }) => + (super.noSuchMethod( + Invocation.method( + #onOrientationChanged, + [], + { + #useSensor: useSensor, + #defaultOrientation: defaultOrientation, + }, + ), + returnValue: _i3.Stream<_i4.NativeDeviceOrientation>.empty(), + returnValueForMissingStub: + _i3.Stream<_i4.NativeDeviceOrientation>.empty(), + ) as _i3.Stream<_i4.NativeDeviceOrientation>); +} diff --git a/test/math/axis3_test.dart b/test/math/axis3_test.dart new file mode 100644 index 0000000..2eb6414 --- /dev/null +++ b/test/math/axis3_test.dart @@ -0,0 +1,49 @@ +import 'package:flutter_rotation_sensor/flutter_rotation_sensor.dart'; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + test('predefined axes returns correct unit vectors', () { + expect(Axis3.X, equals(Vector3(1, 0, 0))); + expect(Axis3.Y, equals(Vector3(0, 1, 0))); + expect(Axis3.Z, equals(Vector3(0, 0, 1))); + expect(Axis3.invalid, equals(Vector3(0, 0, 0))); + }); + + test('negating axes reverse their direction', () { + final negX = -Axis3.X; + final negY = -Axis3.Y; + final negZ = -Axis3.Z; + + expect(negX, equals(Vector3(-1, 0, 0))); + expect(negY, equals(Vector3(0, -1, 0))); + expect(negZ, equals(Vector3(0, 0, -1))); + }); + + test('cross product of axes produce correct orthogonal axis', () { + final crossXY = Axis3.X.cross(Axis3.Y); + final crossYZ = Axis3.Y.cross(Axis3.Z); + final crossZX = Axis3.Z.cross(Axis3.X); + + expect(crossXY, equals(Axis3.Z)); + expect(crossYZ, equals(Axis3.X)); + expect(crossZX, equals(Axis3.Y)); + }); + + test('axis instances with the same vector are equal', () { + final axis1 = Axis3.X; + final axis2 = Axis3.Y.cross(Axis3.Z); + + expect(axis1 == axis2, isTrue); + expect(axis1.hashCode, equals(axis2.hashCode)); + }); + + test('toString return the correct representation', () { + expect(Axis3.X.toString(), equals('X')); + expect(Axis3.Y.toString(), equals('Y')); + expect(Axis3.Z.toString(), equals('Z')); + expect((-Axis3.X).toString(), equals('-X')); + expect((-Axis3.Y).toString(), equals('-Y')); + expect((-Axis3.Z).toString(), equals('-Z')); + expect(Axis3.invalid.toString(), equals('Invalid')); + }); +} diff --git a/test/math/axis_angle_test.dart b/test/math/axis_angle_test.dart new file mode 100644 index 0000000..db268de --- /dev/null +++ b/test/math/axis_angle_test.dart @@ -0,0 +1,27 @@ +import 'dart:math'; + +import 'package:flutter_rotation_sensor/flutter_rotation_sensor.dart'; +import 'package:flutter_test/flutter_test.dart'; + +import '../utils.dart'; + +void main() { + test('constructor returns an axis-angle with correct component', () { + final a = AxisAngle(Vector3(1, 0, 0), 1); + expect(a.axis.x, equals(1)); + expect(a.axis.y, equals(0)); + expect(a.axis.z, equals(0)); + expect(a.angle, equals(1)); + }); + + test('toQuaternion converts this axis-angle to quaternion', () { + expect( + AxisAngle(Vector3(0, 0, 1), pi / 2).toQuaternion(), + closeToQuaternion(Quaternion(0, 0, sin(pi / 4), cos(pi / 4))), + ); + expect( + AxisAngle(Vector3(0, 0, 0), 0).toQuaternion(), + closeToQuaternion(Quaternion(0, 0, 0, 1)), + ); + }); +} diff --git a/test/math/euler_angles_test.dart b/test/math/euler_angles_test.dart new file mode 100644 index 0000000..6273441 --- /dev/null +++ b/test/math/euler_angles_test.dart @@ -0,0 +1,97 @@ +import 'dart:math'; + +import 'package:flutter_rotation_sensor/flutter_rotation_sensor.dart'; +import 'package:flutter_test/flutter_test.dart'; + +import '../utils.dart'; + +void main() { + test('constructor sets azimuth, pitch, and roll correctly', () { + const azimuth = pi / 2; // 90 degrees + const pitch = pi / 4; // 45 degrees + const roll = -pi / 6; // -30 degrees + final eulerAngles = EulerAngles(azimuth, pitch, roll); + + expect(eulerAngles.azimuth, closeTo(azimuth, delta)); + expect(eulerAngles.pitch, closeTo(pitch, delta)); + expect(eulerAngles.roll, closeTo(roll, delta)); + }); + + test('azimuth returns the correct value', () { + const azimuth = pi / 3; // 60 degrees + final eulerAngles = EulerAngles(azimuth, 0, 0); + + expect(eulerAngles.azimuth, closeTo(azimuth, delta)); + }); + + test('pitch returns the correct value', () { + const pitch = -pi / 4; // -45 degrees + final eulerAngles = EulerAngles(0, pitch, 0); + + expect(eulerAngles.pitch, closeTo(pitch, delta)); + }); + + test('roll returns the correct value', () { + const roll = pi; // 180 degrees + final eulerAngles = EulerAngles(0, 0, roll); + + expect(eulerAngles.roll, closeTo(roll, delta)); + }); + + test('yaw is equivalent to azimuth', () { + const azimuth = pi / 2; // 90 degrees + final eulerAngles = EulerAngles(azimuth, 0, 0); + + expect(eulerAngles.yaw, closeTo(eulerAngles.azimuth, delta)); + }); + + test('azimuth is normalized to the range 0 to 2π', () { + final eulerAngles = EulerAngles(-2 * pi, 0, 0); + + expect(eulerAngles.azimuth, closeTo(0, delta)); + }); + + test('pitch is within the range -π/2 to π/2', () { + const pitchAngles = [ + -pi / 2, // -90 degrees + pi / 4, // 45 degrees + pi / 2, // 90 degrees + ]; + for (final pitchAngle in pitchAngles) { + final eulerAngles1 = EulerAngles(0, pitchAngle, 0); + expect(eulerAngles1.pitch, closeTo(pitchAngle, delta)); + } + }); + + test('pitch outside -π/2 to π/2 throws InvalidPitchException', () { + expect( + () => EulerAngles(0, pi, 0), + throwsA(isA()), + ); + }); + + test('roll is normalized to the range -π to π', () { + final eulerAngles = EulerAngles(0, 0, -3 * pi); + + expect(eulerAngles.roll, closeTo(pi, delta)); + }); + + test('toRotationMatrix converts to matrix', () { + expect( + EulerAngles(0.1, 0.2, 0.3).toRotationMatrix(), + closeToMatrix3( + Matrix3( + 00.9564251, + 00.0978434, + 00.2750958, + -0.0369570, + 00.9751703, + -0.2183507, + -0.2896295, + 00.1986693, + 00.9362934, + ), + ), + ); + }); +} diff --git a/test/math/matrix3_test.dart b/test/math/matrix3_test.dart new file mode 100644 index 0000000..0355be3 --- /dev/null +++ b/test/math/matrix3_test.dart @@ -0,0 +1,248 @@ +// ignore_for_file: prefer_int_literals + +import 'dart:math'; + +import 'package:flutter_rotation_sensor/flutter_rotation_sensor.dart'; +import 'package:flutter_test/flutter_test.dart'; + +import '../utils.dart'; + +void main() { + test('constructor returns an matrix with correct elements', () { + final m = Matrix3(1, 2, 3, 4, 5, 6, 7, 8, 9); + expect(m.a, equals(1)); + expect(m.b, equals(2)); + expect(m.c, equals(3)); + expect(m.d, equals(4)); + expect(m.e, equals(5)); + expect(m.f, equals(6)); + expect(m.g, equals(7)); + expect(m.h, equals(8)); + expect(m.i, equals(9)); + }); + + test('identity constructor returns an identity matrix', () { + expect( + Matrix3.identity(), + equals(Matrix3(1, 0, 0, 0, 1, 0, 0, 0, 1)), + ); + }); + + test('rows constructor returns an matrix with given row vectors', () { + final v = Vector3(1, 2, 3); + expect( + Matrix3.rows(v, v, v), + equals(Matrix3(1, 2, 3, 1, 2, 3, 1, 2, 3)), + ); + }); + + test('columns constructor returns an matrix with given columns vectors', () { + final v = Vector3(1, 2, 3); + expect( + Matrix3.columns(v, v, v), + equals(Matrix3(1, 1, 1, 2, 2, 2, 3, 3, 3)), + ); + }); + + test('zero constructor returns a zero matrix', () { + expect( + Matrix3.zero(), + equals(Matrix3(0, 0, 0, 0, 0, 0, 0, 0, 0)), + ); + }); + + test('rotateX constructor returns a zero matrix', () { + expect( + Matrix3.rotateX(1), + closeToMatrix3( + Matrix3( + 01.0000000, + 00.0000000, + 00.0000000, + 00.0000000, + 00.5403023, + -0.8414710, + 00.0000000, + 00.8414710, + 00.5403023, + ), + ), + ); + }); + + test('rotateY constructor returns a zero matrix', () { + expect( + Matrix3.rotateY(2), + closeToMatrix3( + Matrix3( + -0.4161468, + 00.0000000, + 00.9092974, + 00.0000000, + 01.0000000, + 00.0000000, + -0.9092974, + 00.0000000, + -0.4161468, + ), + ), + ); + }); + + test('rotateZ constructor returns a zero matrix', () { + expect( + Matrix3.rotateZ(3), + closeToMatrix3( + Matrix3( + -0.9899925, + -0.1411200, + 00.0000000, + 00.1411200, + -0.9899925, + 00.0000000, + 00.0000000, + 00.0000000, + 01.0000000, + ), + ), + ); + }); + + test('equality and hashCode', () { + final m1 = Matrix3(1, 2, 3, 4, 5, 6, 7, 8, 9); + final m2 = Matrix3(1, 2, 3, 4, 5, 6, 7, 8, 9); + final m3 = Matrix3(9, 8, 7, 6, 5, 4, 3, 2, 1); + expect(m1 == m2, isTrue); + expect(m1 == m3, isFalse); + expect(m1.hashCode == m2.hashCode, isTrue); + expect(m1.hashCode == m3.hashCode, isFalse); + }); + + test('toString returns the correct representation', () { + expect( + Matrix3(1, 2, 3, 4, 5, 6, 7, 8, 9).toString(), + equals('⌈1.0,2.0,3.0⌉\n|4.0,5.0,6.0|\n⌊7.0,8.0,9.0⌋\n'), + ); + }); + + test('row returns the corresponding elements at index', () { + expect( + Matrix3(1, 2, 3, 4, 5, 6, 7, 8, 9).row(1), + equals(Vector3(4, 5, 6)), + ); + }); + + test('column returns the corresponding elements at index', () { + expect( + Matrix3(1, 2, 3, 4, 5, 6, 7, 8, 9).column(1), + equals(Vector3(2, 5, 8)), + ); + }); + + test('negation changes sign of each element', () { + expect( + -Matrix3(1, 2, 3, 4, 5, 6, 7, 8, 9), + equals(Matrix3(-1, -2, -3, -4, -5, -6, -7, -8, -9)), + ); + }); + + test('addition sums corresponding elements', () { + expect( + Matrix3(1, 2, 3, 4, 5, 6, 7, 8, 9) + Matrix3(9, 8, 7, 6, 5, 4, 3, 2, 1), + equals(Matrix3(10, 10, 10, 10, 10, 10, 10, 10, 10)), + ); + }); + + test('subtraction subtracts corresponding elements', () { + expect( + Matrix3(1, 2, 3, 4, 5, 6, 7, 8, 9) - Matrix3(9, 8, 7, 6, 5, 4, 3, 2, 1), + equals(Matrix3(-8, -6, -4, -2, 0, 2, 4, 6, 8)), + ); + }); + + test('multiplication scales each element by a scalar', () { + expect( + Matrix3(1, 2, 3, 4, 5, 6, 7, 8, 9) * 2, + equals(Matrix3(2, 4, 6, 8, 10, 12, 14, 16, 18)), + ); + }); + + test('division scales each element by a scalar', () { + expect( + Matrix3(2, 4, 6, 8, 10, 12, 14, 16, 18) / 2, + equals(Matrix3(1, 2, 3, 4, 5, 6, 7, 8, 9)), + ); + }); + + test('multiplication matrix calculates product of two matrices', () { + expect( + Matrix3(1, 2, 3, 4, 5, 6, 7, 8, 9) + .multiply(Matrix3(9, 8, 7, 6, 5, 4, 3, 2, 1)), + equals(Matrix3(30, 24, 18, 84, 69, 54, 138, 114, 90)), + ); + }); + + test('trace calculates the sum of main diagonal', () { + expect(Matrix3(1, 2, 3, 0, 1, 4, 5, 6, 0).trace, equals(2)); + }); + + test('determinant calculates the determinant value', () { + expect(Matrix3(1, 2, 3, 0, 1, 4, 5, 6, 0).determinant, equals(1)); + }); + + test('transpose swaps rows and columns', () { + expect( + Matrix3(1, 2, 3, 4, 5, 6, 7, 8, 9).transpose(), + equals(Matrix3(1, 4, 7, 2, 5, 8, 3, 6, 9)), + ); + }); + + test('adjoint calculates the adjugate matrix', () { + expect( + Matrix3(1, 2, 3, 0, 1, 4, 5, 6, 0).adjoint(), + equals(Matrix3(-24, 18, 5, 20, -15, -4, -5, 4, 1)), + ); + }); + + test('invert calculates the inverse matrix', () { + expect( + Matrix3(1, 2, 3, 0, 1, 4, 5, 6, 0).invert(), + equals(Matrix3(-24, 18, 5, 20, -15, -4, -5, 4, 1)), + ); + }); + + test('apply function applies function to each element', () { + expect( + Matrix3(1, 2, 3, 4, 5, 6, 7, 8, 9).apply((x) => min(x * 2, 9)), + equals(Matrix3(2, 4, 6, 8, 9, 9, 9, 9, 9)), + ); + }); + + test('toQuaternion converts this rotation matrix to quaternion', () { + expect( + Matrix3(1, 0, 0, 0, -1, 0, 0, 0, -1).toQuaternion(), + equals(Quaternion(1, 0, 0, 0)), + ); + }); + + test('toEulerAngles converts this rotation matrix to Euler-angles', () { + expect( + Matrix3(1, 0, 0, 0, -1, 0, 0, 0, -1).toEulerAngles(), + closeToEulerAngles(EulerAngles(pi, 0, pi)), + ); + expect( + Matrix3( + 00.5403023, + 00.0000000, + 00.8414710, + 00.8414710, + 00.0000000, + -0.5403023, + 00.0000000, + 01.0000000, + 00.0000000, + ).toEulerAngles(), + closeToEulerAngles(EulerAngles(pi * 2 - 1, pi / 2, 0)), + ); + }); +} diff --git a/test/math/quaternion_test.dart b/test/math/quaternion_test.dart new file mode 100644 index 0000000..ba7aa52 --- /dev/null +++ b/test/math/quaternion_test.dart @@ -0,0 +1,127 @@ +import 'dart:math'; + +import 'package:flutter_rotation_sensor/flutter_rotation_sensor.dart'; +import 'package:flutter_test/flutter_test.dart'; + +import '../utils.dart'; + +void main() { + test('constructor returns a quaternion with correct components', () { + final q = Quaternion(1, 2, 3, 4); + expect(q.x, equals(1)); + expect(q.y, equals(2)); + expect(q.z, equals(3)); + expect(q.w, equals(4)); + }); + + test('identity constructor returns a identity quaternion', () { + expect(Quaternion.identity(), equals(Quaternion(0, 0, 0, 1))); + }); + + test('equality and hashCode', () { + final q1 = Quaternion(1, 2, 3, 4); + final q2 = Quaternion(1, 2, 3, 4); + final q3 = Quaternion(2, 3, 4, 5); + expect(q1 == q2, isTrue); + expect(q1 == q3, isFalse); + expect(q1.hashCode == q2.hashCode, isTrue); + expect(q1.hashCode == q3.hashCode, isFalse); + }); + + test('toString returns the correct representation', () { + expect(Quaternion(1, 2, 3, 4).toString(), equals('1.0, 2.0, 3.0 @ 4.0')); + }); + + test('negation changes sign of each component', () { + expect(-Quaternion(1, 2, 3, 4), equals(Quaternion(-1, -2, -3, -4))); + }); + + test('addition sums corresponding components', () { + expect( + Quaternion(1, 2, 3, 4) + Quaternion(5, 6, 7, 8), + equals(Quaternion(6, 8, 10, 12)), + ); + }); + + test('subtraction subtracts corresponding components', () { + expect( + Quaternion(5, 6, 7, 8) - Quaternion(1, 2, 3, 4), + equals(Quaternion(4, 4, 4, 4)), + ); + }); + + test('multiplication scales each component by a scalar', () { + expect( + Quaternion(1, 2, 3, 4) * 2, + equals(Quaternion(2, 4, 6, 8)), + ); + }); + + test('division scales each component by a scalar', () { + expect( + Quaternion(2, 4, 6, 8) / 2, + equals(Quaternion(1, 2, 3, 4)), + ); + }); + + test('multiplication quaternion calculates product of two quaternions', () { + expect( + Quaternion(1, 2, 3, 4).multiply(Quaternion(5, 6, 7, 8)), + equals(Quaternion(24, 48, 48, -6)), + ); + }); + + test('length and length2 calculate quaternion magnitude and its square', () { + final q = Quaternion(1, 2, 3, 4); + expect(q.length2, closeTo(30, delta)); + expect(q.length, closeTo(5.4772256, delta)); + }); + + test('normalize scales quaternion to unit length', () { + expect( + Quaternion(1, 2, 3, 4).normalize(), + closeToQuaternion(Quaternion(0.1825742, 0.3651484, 0.5477226, 0.7302967)), + ); + }); + + test('conjugate', () { + expect( + Quaternion(1, 2, 3, 4).conjugate(), + equals(Quaternion(-1, -2, -3, 4)), + ); + }); + + test('invert calculates the inverse quaternion', () { + expect( + Quaternion(1, 2, 3, 4).invert(), + closeToQuaternion( + Quaternion(-0.0333333, -0.0666667, -0.1000000, 0.1333333), + ), + ); + }); + + test('apply function applies function to each component', () { + expect( + Quaternion(1, 2, 3, 4).apply((x) => min(x * 2, 5)), + equals(Quaternion(2, 4, 5, 5)), + ); + }); + + test('toAxisAngle converts quaternion to axis angle representation', () { + expect( + Quaternion(0, 0, sin(pi / 4), cos(pi / 4)).toAxisAngle(), + closeToAxisAngle(AxisAngle(Vector3(0, 0, 1), pi / 2)), + ); + expect( + Quaternion(0, 0, 0, 1).toAxisAngle(), + closeToAxisAngle(AxisAngle(Vector3(0, 0, 0), 0)), + ); + }); + + test('toRotationMatrix converts quaternion to rotation matrix', () { + expect( + Quaternion(1, 0, 0, 0).toRotationMatrix(), + equals(Matrix3(1, 0, 0, 0, -1, 0, 0, 0, -1)), + ); + }); +} diff --git a/test/math/vector3_test.dart b/test/math/vector3_test.dart new file mode 100644 index 0000000..0e71aca --- /dev/null +++ b/test/math/vector3_test.dart @@ -0,0 +1,80 @@ +import 'dart:math'; + +import 'package:flutter_rotation_sensor/flutter_rotation_sensor.dart'; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + test('constructor returns a vector with correct components', () { + final v = Vector3(1, 2, 3); + expect(v.x, 1); + expect(v.y, 2); + expect(v.z, 3); + }); + + test('zero constructor returns a zero vector', () { + expect(Vector3.zero(), equals(Vector3(0, 0, 0))); + }); + + test('equality and hashCode', () { + final v1 = Vector3(1, 2, 3); + final v2 = Vector3(1, 2, 3); + final v3 = Vector3(4, 5, 6); + expect(v1 == v2, isTrue); + expect(v1 == v3, isFalse); + expect(v1.hashCode == v2.hashCode, isTrue); + expect(v1.hashCode == v3.hashCode, isFalse); + }); + + test('toString returns the correct representation', () { + expect(Vector3(1, 2, 3).toString(), equals('[1.0,2.0,3.0]')); + }); + + test('negation changes sign of each component', () { + expect(-Vector3(1, 2, 3), equals(Vector3(-1, -2, -3))); + }); + + test('addition sums corresponding components', () { + expect(Vector3(1, 2, 3) + Vector3(4, 5, 6), equals(Vector3(5, 7, 9))); + }); + + test('subtraction subtracts corresponding components', () { + expect(Vector3(4, 5, 6) - Vector3(1, 2, 3), equals(Vector3(3, 3, 3))); + }); + + test('multiplication scales each component by a scalar', () { + expect(Vector3(1, 2, 3) * 2, equals(Vector3(2, 4, 6))); + }); + + test('division scales each component by a scalar', () { + expect(Vector3(4, 6, 8) / 2, equals(Vector3(2, 3, 4))); + }); + + test('dot product calculates scalar product of two vectors', () { + expect(Vector3(1, 2, 3).dot(Vector3(4, 5, 6)), equals(32)); + }); + + test('cross product calculates perpendicular vector', () { + expect(Vector3(1, 0, 0).cross(Vector3(0, 1, 0)), equals(Vector3(0, 0, 1))); + }); + + test('length and length2 calculate vector magnitude and its square', () { + final v = Vector3(3, 4, 0); + expect(v.length2, equals(25)); + expect(v.length, equals(5)); + }); + + test('normalize scales vector to unit length', () { + expect( + Vector3(3, 4, 0).normalize(), + equals( + // ignore: prefer_int_literals + Vector3(0.6, 0.8, 0.0), + ), + ); + expect(Vector3(0, 0, 0).normalize(), equals(Vector3(0, 0, 0))); + }); + + test('apply function applies function to each component', () { + expect(Vector3(1, 2, 3).apply((x) => min(x * 2, 5)), Vector3(2, 4, 5)); + }); +} diff --git a/test/orientation_event_test.dart b/test/orientation_event_test.dart new file mode 100644 index 0000000..7f640b2 --- /dev/null +++ b/test/orientation_event_test.dart @@ -0,0 +1,271 @@ +// ignore_for_file: prefer_int_literals + +import 'dart:math'; + +import 'package:flutter_rotation_sensor/flutter_rotation_sensor.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'utils.dart'; + +const threshold = 0.000001; + +void main() { + final event1 = eventOf(00.0000000, 00.0000000, 00.0000000, 01.0000000); + final event2 = eventOf(00.4299807, 00.4374203, -0.5786997, 00.5374818); + + test( + 'rotationMatrix returns correct matrix for some known quaternions', + () { + expect( + event1.rotationMatrix, + closeToMatrix3( + matrix( + [01.0000000, 00.0000000, 00.0000000], + [00.0000000, 01.0000000, 00.0000000], + [00.0000000, 00.0000000, 01.0000000], + ), + ), + ); + expect( + event2.rotationMatrix, + closeToMatrix3( + matrix( + [-0.0524597, 00.9982457, -0.0274485], + [-0.2459166, -0.0395536, -0.9684836], + [-0.9678704, -0.0440563, 00.2475601], + ), + ), + ); + }, + ); + + test('eulerAngles returns correct angles for some known quaternions', () { + expect( + event1.eulerAngles, + closeToEulerAngles(EulerAngles(00.0000000, 00.0000000, 00.0000000)), + ); + expect( + event2.eulerAngles, + closeToEulerAngles(EulerAngles(01.6103987, -0.0440705, 01.3203868)), + ); + final event = eventOf(00.7071068, 00.0000000, 00.0000000, 00.7071068); + final eulerAngles = event.eulerAngles; + expect(eulerAngles.pitch, closeTo(pi / 2, threshold)); + expect(eulerAngles.azimuth, closeTo(eulerAngles.roll, threshold)); + }); + + test('remapCoordinateSystem throws error with invalid axes', () { + expect( + () => event1.remapCoordinateSystem(Axis3.X, Axis3.X), + throwsUnsupportedError, + ); + expect( + () => event1.remapCoordinateSystem(Axis3.X, -Axis3.X), + throwsUnsupportedError, + ); + }); + + test( + 'remapCoordinateSystem returns a new OrientationEvent with transformed ' + 'coordinate system', + () { + final event1xy = event1.remapCoordinateSystem(Axis3.X, Axis3.Y); + expect( + event1xy.rotationMatrix, + closeToMatrix3( + matrix( + [01.0000000, 00.0000000, 00.0000000], + [00.0000000, 01.0000000, 00.0000000], + [00.0000000, 00.0000000, 01.0000000], + ), + ), + ); + expect( + event1xy.coordinateSystem, + closeToMatrix3( + matrix( + [01.0000000, 00.0000000, 00.0000000], + [00.0000000, 01.0000000, 00.0000000], + [00.0000000, 00.0000000, 01.0000000], + ), + ), + ); + + final event1xz = event1.remapCoordinateSystem(Axis3.X, Axis3.Z); + expect( + event1xz.rotationMatrix, + closeToMatrix3( + matrix( + [01.0000000, 00.0000000, 00.0000000], + [00.0000000, 00.0000000, -1.0000000], + [00.0000000, 01.0000000, 00.0000000], + ), + ), + ); + expect( + event1xz.coordinateSystem, + closeToMatrix3( + matrix( + [01.0000000, 00.0000000, 00.0000000], + [00.0000000, 00.0000000, -1.0000000], + [00.0000000, 01.0000000, 00.0000000], + ), + ), + ); + + final event1yZ = event1.remapCoordinateSystem(Axis3.Y, -Axis3.Z); + expect( + event1yZ.rotationMatrix, + closeToMatrix3( + matrix( + [00.0000000, 00.0000000, -1.0000000], + [01.0000000, 00.0000000, 00.0000000], + [00.0000000, -1.0000000, 00.0000000], + ), + ), + ); + expect( + event1yZ.coordinateSystem, + closeToMatrix3( + matrix( + [00.0000000, 00.0000000, -1.0000000], + [01.0000000, 00.0000000, 00.0000000], + [00.0000000, -1.0000000, 00.0000000], + ), + ), + ); + + final event1YX = event1.remapCoordinateSystem(-Axis3.Y, -Axis3.X); + expect( + event1YX.rotationMatrix, + closeToMatrix3( + matrix( + [00.0000000, -1.0000000, 00.0000000], + [-1.0000000, 00.0000000, 00.0000000], + [00.0000000, 00.0000000, -1.0000000], + ), + ), + ); + expect( + event1YX.coordinateSystem, + closeToMatrix3( + matrix( + [00.0000000, -1.0000000, 00.0000000], + [-1.0000000, 00.0000000, 00.0000000], + [00.0000000, 00.0000000, -1.0000000], + ), + ), + ); + + expect( + event2.remapCoordinateSystem(Axis3.X, Axis3.Z).rotationMatrix, + closeToMatrix3( + matrix( + [-0.0524597, -0.0274485, -0.9982457], + [-0.2459166, -0.9684836, 00.0395536], + [-0.9678704, 00.2475601, 00.0440563], + ), + ), + ); + + expect( + event2.remapCoordinateSystem(Axis3.Y, -Axis3.Z).rotationMatrix, + closeToMatrix3( + matrix( + [00.9982457, 00.0274485, 00.0524597], + [-0.0395536, 00.9684836, 00.2459166], + [-0.0440563, -0.2475601, 00.9678704], + ), + ), + ); + + expect( + event2.remapCoordinateSystem(-Axis3.Y, -Axis3.X).rotationMatrix, + closeToMatrix3( + matrix( + [-0.9982457, 00.0524597, 00.0274485], + [00.0395536, 00.2459166, 00.9684836], + [00.0440563, 00.9678704, -0.2475601], + ), + ), + ); + }, + ); + + test( + 'should be equivalent to single remapping with different axes when ' + 'remapped twice consecutively', + () { + expect( + event2 + .remapCoordinateSystem(-Axis3.Y, Axis3.Z) + .remapCoordinateSystem(-Axis3.Y, Axis3.Z), + closeToOrientationEvent( + event2.remapCoordinateSystem(-Axis3.Z, -Axis3.X), + ), + ); + }, + ); + + test( + 'should result in a matrix close to the original rotation matrix ' + 'transposed after remapping and multiplying by inverted coordinate system', + () { + final remapped = event2.remapCoordinateSystem(-Axis3.Y, Axis3.Z); + expect( + remapped.rotationMatrix.multiply(remapped.coordinateSystem.invert()), + closeToMatrix3( + event2.rotationMatrix, + ), + ); + }, + ); + + test('toString return the correct representation', () { + expect( + event1.toString(), + equals(''' +OrientationEvent( +quaternion: 0.0, 0.0, 0.0 @ 1.0, +accuracy: -1.0, +timestamp: 0, +coordinateSystem: +⌈1.0,0.0,0.0⌉ +|0.0,1.0,0.0| +⌊0.0,0.0,1.0⌋ +)'''), + ); + expect( + event2.remapCoordinateSystem(-Axis3.Y, -Axis3.X).toString(), + equals(''' +OrientationEvent( +quaternion: -0.02914547175168991, -0.7892594933509827, -0.6133451461791992 @ 0.005260601174086332, +accuracy: -1.0, +timestamp: 0, +coordinateSystem: +⌈-0.0,-1.0,0.0⌉ +|-1.0,-0.0,0.0| +⌊-0.0,-0.0,-1.0⌋ +)'''), + ); + }); +} + +OrientationEvent eventOf(double x, double y, double z, double w) => + OrientationEvent( + quaternion: Quaternion(x, y, z, w).normalize(), + accuracy: -1, + timestamp: 0, + ); + +Matrix3 matrix(List row0, List row1, List row2) => + Matrix3( + row0[0], + row0[1], + row0[2], + row1[0], + row1[1], + row1[2], + row2[0], + row2[1], + row2[2], + ); diff --git a/test/rotation_sensor_method_channel_test.dart b/test/rotation_sensor_method_channel_test.dart new file mode 100644 index 0000000..b886c09 --- /dev/null +++ b/test/rotation_sensor_method_channel_test.dart @@ -0,0 +1,81 @@ +import 'package:flutter_rotation_sensor/flutter_rotation_sensor.dart'; +import 'package:flutter_rotation_sensor/src/rotation_sensor_method_channel.dart'; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + TestWidgetsFlutterBinding.ensureInitialized(); + + final platform = MethodChannelRotationSensor(); + const methodChannel = MethodChannelRotationSensor.methodChannel; + const orientationChannel = MethodChannelRotationSensor.eventChannel; + late int expectedSamplingPeriod; + + setUp(() { + expectedSamplingPeriod = platform.samplingPeriod.inMicroseconds; + TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger + .setMockMethodCallHandler( + methodChannel, + (methodCall) async { + switch (methodCall.method) { + case 'getOrientationStream': + final arguments = methodCall.arguments as Map; + final samplingPeriod = arguments['samplingPeriod'] as int; + expect(samplingPeriod, expectedSamplingPeriod); + return null; + default: + throw UnsupportedError(methodCall.method); + } + }, + ); + TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger + .setMockStreamHandler( + orientationChannel, + MockStreamHandler.inline( + onListen: (args, sink) { + sink.success([ + // Quaternion + 0.0, 0.0, 0.0, 1.0, + // Accuracy + -1.0, + // Timestamp + 123456789, + ]); + }, + ), + ); + }); + + tearDown(() { + TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger + .setMockMethodCallHandler(methodChannel, null); + TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger + .setMockStreamHandler(orientationChannel, null); + }); + + test( + 'orientationStream emits OrientationEvent with default sampling period', + () async { + expect( + await platform.orientationStream.first, + isA(), + ); + }, + ); + + test( + 'orientationStream emits OrientationEvent with a replaced sampling period ' + 'when a reserved value is provided', + () async { + // samplingPeriod should be replaced with 0 since 1-3 is a reserved value + // for Android. + expectedSamplingPeriod = 0; + platform.samplingPeriod = const Duration(microseconds: 1); + expect(platform.samplingPeriod, equals(Duration.zero)); + await Future.microtask(() => null); + expect( + await platform.orientationStream.first, + isA(), + ); + }, + ); +} diff --git a/test/rotation_sensor_test.dart b/test/rotation_sensor_test.dart new file mode 100644 index 0000000..f114ef3 --- /dev/null +++ b/test/rotation_sensor_test.dart @@ -0,0 +1,57 @@ +import 'package:flutter/widgets.dart'; +import 'package:flutter_rotation_sensor/flutter_rotation_sensor.dart'; +import 'package:flutter_rotation_sensor/src/rotation_sensor_method_channel.dart'; +import 'package:flutter_rotation_sensor/src/rotation_sensor_platform_interface.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:plugin_platform_interface/plugin_platform_interface.dart'; + +class MockRotationSensorPlatform extends RotationSensorPlatform + with MockPlatformInterfaceMixin { + @override + Stream get orientationStream => + Stream.fromIterable([ + OrientationEvent( + quaternion: Quaternion.identity(), + accuracy: -1, + timestamp: 0, + ), + ]); +} + +void main() { + WidgetsFlutterBinding.ensureInitialized(); + + final initialPlatform = RotationSensorPlatform.instance; + + test('MethodChannelRotationSensor is the default instance', () { + expect(initialPlatform, isInstanceOf()); + }); + + test('platform is default MethodChannelRotationSensor', () { + expect(RotationSensor.platform, same(initialPlatform)); + }); + + test('orientationStream returns a stream of orientation events', () async { + var fakePlatform = MockRotationSensorPlatform(); + RotationSensorPlatform.instance = fakePlatform; + + expect( + await RotationSensor.orientationStream.first, + isA(), + ); + }); + + test('samplingPeriod return zero duration for reserved value', () { + for (var t = 0; t < 4; t++) { + RotationSensor.samplingPeriod = Duration(microseconds: t); + expect(RotationSensor.samplingPeriod, equals(Duration.zero)); + } + RotationSensor.samplingPeriod = SensorInterval.uiInterval; + expect(RotationSensor.samplingPeriod, equals(SensorInterval.uiInterval)); + }); + + test('coordinateSystem can be set and retrieved correctly', () { + RotationSensor.coordinateSystem = CoordinateSystem.display(); + expect(RotationSensor.coordinateSystem, same(CoordinateSystem.display())); + }); +} diff --git a/test/utils.dart b/test/utils.dart new file mode 100644 index 0000000..f66efd8 --- /dev/null +++ b/test/utils.dart @@ -0,0 +1,59 @@ +import 'package:flutter_rotation_sensor/flutter_rotation_sensor.dart'; +import 'package:flutter_test/flutter_test.dart'; + +const delta = 1e-6; + +Matcher closeToVector3(Vector3 o, [num delta = delta]) => isA() + .having((v) => v.x, 'x', closeTo(o.x, delta)) + .having((v) => v.y, 'y', closeTo(o.y, delta)) + .having((v) => v.z, 'z', closeTo(o.z, delta)); + +Matcher closeToMatrix3(Matrix3 o, [num delta = delta]) => isA() + .having((m) => m.a, 'a', closeTo(o.a, delta)) + .having((m) => m.b, 'b', closeTo(o.b, delta)) + .having((m) => m.c, 'c', closeTo(o.c, delta)) + .having((m) => m.d, 'd', closeTo(o.d, delta)) + .having((m) => m.e, 'e', closeTo(o.e, delta)) + .having((m) => m.f, 'f', closeTo(o.f, delta)) + .having((m) => m.g, 'g', closeTo(o.g, delta)) + .having((m) => m.h, 'h', closeTo(o.h, delta)) + .having((m) => m.i, 'i', closeTo(o.i, delta)); + +Matcher closeToQuaternion(Quaternion o, [num delta = delta]) => + isA() + .having((q) => q.x, 'x', closeTo(o.x, delta)) + .having((q) => q.y, 'y', closeTo(o.y, delta)) + .having((q) => q.z, 'z', closeTo(o.z, delta)) + .having((q) => q.w, 'w', closeTo(o.w, delta)); + +Matcher closeToAxisAngle(AxisAngle o, [num delta = delta]) => isA() + .having((a) => a.axis, 'axis', closeToVector3(o.axis, delta)) + .having((a) => a.angle, 'angle', closeTo(o.angle, delta)); + +Matcher closeToEulerAngles(EulerAngles expected, [num delta = delta]) => + isA() + .having((ea) => ea.azimuth, 'azimuth', closeTo(expected.azimuth, delta)) + .having((ea) => ea.pitch, 'pitch', closeTo(expected.pitch, delta)) + .having((ea) => ea.roll, 'roll', closeTo(expected.roll, delta)); + +Matcher closeToOrientationEvent( + OrientationEvent expected, [ + num delta = delta, +]) => + isA() + .having( + (e) => e.quaternion, + 'quaternion', + closeToQuaternion(expected.quaternion, delta), + ) + .having( + (e) => e.accuracy, + 'accuracy', + closeTo(expected.accuracy, delta), + ) + .having( + (e) => e.coordinateSystem, + 'coordinateSystem', + equals(expected.coordinateSystem), + ) + .having((e) => e.timestamp, 'timestamp', equals(expected.timestamp)); From 55ecf4e6255a5fc81d910311f40dc2ceb92d0798 Mon Sep 17 00:00:00 2001 From: 6y Date: Thu, 25 Jul 2024 00:40:20 +0800 Subject: [PATCH 02/69] chore: bump version to 0.1.0 --- CHANGELOG.md | 4 ++-- example/pubspec.lock | 2 +- pubspec.yaml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 41cc7d8..881d709 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,3 @@ -## 0.0.1 +## [0.1.0] - Initial Release -* TODO: Describe initial release. +* Initial release. diff --git a/example/pubspec.lock b/example/pubspec.lock index ccc914f..f20b6d8 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -81,7 +81,7 @@ packages: path: ".." relative: true source: path - version: "0.0.1" + version: "0.1.0" flutter_test: dependency: "direct dev" description: flutter diff --git a/pubspec.yaml b/pubspec.yaml index 3443a13..7abfe77 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: flutter_rotation_sensor description: > A package provides a stream of device's orientation in three different representations: a rotation matrix, a quaternion, and Euler angles (azimuth, pitch, roll). -version: 0.0.1 +version: 0.1.0 repository: https://github.com/tlserver/flutter_rotation_sensor environment: From be589ad315639f11ee6f1d2b3f8308bfcad2f47f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 26 Aug 2024 01:58:04 +0000 Subject: [PATCH 03/69] chore: bump simple_3d_renderer from 19.1.0 to 20.0.2 in /example Bumps [simple_3d_renderer](https://github.com/MasahideMori-SimpleAppli/simple_3d_renderer) from 19.1.0 to 20.0.2. - [Changelog](https://github.com/MasahideMori-SimpleAppli/simple_3d_renderer/blob/main/CHANGELOG.md) - [Commits](https://github.com/MasahideMori-SimpleAppli/simple_3d_renderer/commits) --- updated-dependencies: - dependency-name: simple_3d_renderer dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- example/pubspec.lock | 48 ++++++++++++++++++++++++++------------------ example/pubspec.yaml | 2 +- 2 files changed, 29 insertions(+), 21 deletions(-) diff --git a/example/pubspec.lock b/example/pubspec.lock index f20b6d8..ea77015 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -57,6 +57,14 @@ packages: url: "https://pub.dev" source: hosted version: "7.0.0" + file_state_manager: + dependency: transitive + description: + name: file_state_manager + sha256: "19ae8a33cf3bf6a9890f7819757531d5840fa6d8bf3a4be2fb89e94e9e5e3304" + url: "https://pub.dev" + source: hosted + version: "1.2.0" flutter: dependency: "direct main" description: flutter @@ -101,18 +109,18 @@ packages: dependency: transitive description: name: leak_tracker - sha256: "7f0df31977cb2c0b88585095d168e689669a2cc9b97c309665e3386f3e9d341a" + sha256: "3f87a60e8c63aecc975dda1ceedbc8f24de75f09e4856ea27daf8958f2f0ce05" url: "https://pub.dev" source: hosted - version: "10.0.4" + version: "10.0.5" leak_tracker_flutter_testing: dependency: transitive description: name: leak_tracker_flutter_testing - sha256: "06e98f569d004c1315b991ded39924b21af84cf14cc94791b8aea337d25b57f8" + sha256: "932549fb305594d82d7183ecd9fa93463e9914e1b67cacc34bc40906594a1806" url: "https://pub.dev" source: hosted - version: "3.0.3" + version: "3.0.5" leak_tracker_testing: dependency: transitive description: @@ -149,18 +157,18 @@ packages: dependency: transitive description: name: material_color_utilities - sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a" + sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec url: "https://pub.dev" source: hosted - version: "0.8.0" + version: "0.11.1" meta: dependency: transitive description: name: meta - sha256: "7687075e408b093f36e6bbf6c91878cc0d4cd10f409506f7bc996f68220b9136" + sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7 url: "https://pub.dev" source: hosted - version: "1.12.0" + version: "1.15.0" native_device_orientation: dependency: transitive description: @@ -181,10 +189,10 @@ packages: dependency: transitive description: name: platform - sha256: "12220bb4b65720483f8fa9450b4332347737cf8213dd2840d8b2c823e47243ec" + sha256: "9b71283fc13df574056616011fb138fd3b793ea47cc509c189a6c3fa5f8a1a65" url: "https://pub.dev" source: hosted - version: "3.1.4" + version: "3.1.5" plugin_platform_interface: dependency: transitive description: @@ -205,18 +213,18 @@ packages: dependency: "direct main" description: name: simple_3d - sha256: "8ab92d87c7be0b1f93c65d49d9f2adcd3c0d7ff16b0af9e5a5ecd4f51f27ce55" + sha256: e1f3763f7b3fa299c7c34067d69d51a55519c8b9d691cd7600976b3daa6102ef url: "https://pub.dev" source: hosted - version: "13.3.0" + version: "14.0.1" simple_3d_renderer: dependency: "direct main" description: name: simple_3d_renderer - sha256: "8ec9bad88f35d643cea038ae3b7593dc7eb490a82488fbe39f10e8ee07fea1b7" + sha256: "5b089b8f652734590b3b8dc32a4dc6dc35ee2c98c47a36f2f9c22f2b76c64d0f" url: "https://pub.dev" source: hosted - version: "19.1.0" + version: "20.0.2" sky_engine: dependency: transitive description: flutter @@ -274,18 +282,18 @@ packages: dependency: transitive description: name: test_api - sha256: "9955ae474176f7ac8ee4e989dadfb411a58c30415bcfb648fa04b2b8a03afa7f" + sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb" url: "https://pub.dev" source: hosted - version: "0.7.0" + version: "0.7.2" util_simple_3d: dependency: "direct main" description: name: util_simple_3d - sha256: "2164a36207dfa1bfbba6e8c064779e7b3842deabd759d40de76454c771620ebc" + sha256: b4e722c9ecf2c1fad346beb47ca4416201a5ed700cd7da2d58d1c9eb89bbb01a url: "https://pub.dev" source: hosted - version: "9.4.1" + version: "10.1.0" vector_math: dependency: transitive description: @@ -298,10 +306,10 @@ packages: dependency: transitive description: name: vm_service - sha256: "3923c89304b715fb1eb6423f017651664a03bf5f4b29983627c4da791f74a4ec" + sha256: "5c5f338a667b4c644744b661f309fb8080bb94b18a7e91ef1dbd343bed00ed6d" url: "https://pub.dev" source: hosted - version: "14.2.1" + version: "14.2.5" webdriver: dependency: transitive description: diff --git a/example/pubspec.yaml b/example/pubspec.yaml index fcf946b..5bbbe8f 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -11,7 +11,7 @@ dependencies: flutter_rotation_sensor: path: ../ simple_3d: any - simple_3d_renderer: ^19.1.0 + simple_3d_renderer: ^20.0.2 util_simple_3d: any dev_dependencies: From 66003280850c54876b2a3298e62d05413e9b5a7a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 1 Sep 2024 01:32:46 +0000 Subject: [PATCH 04/69] chore: bump org.jetbrains.kotlin.android in /example/android Bumps [org.jetbrains.kotlin.android](https://github.com/JetBrains/kotlin) from 2.0.0 to 2.0.20. - [Release notes](https://github.com/JetBrains/kotlin/releases) - [Changelog](https://github.com/JetBrains/kotlin/blob/master/ChangeLog.md) - [Commits](https://github.com/JetBrains/kotlin/compare/v2.0.0...v2.0.20) --- updated-dependencies: - dependency-name: org.jetbrains.kotlin.android dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- example/android/settings.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/example/android/settings.gradle b/example/android/settings.gradle index d0a1b95..25a7e87 100644 --- a/example/android/settings.gradle +++ b/example/android/settings.gradle @@ -19,7 +19,7 @@ pluginManagement { plugins { id "dev.flutter.flutter-plugin-loader" version "1.0.0" id "com.android.application" version "8.5.1" apply false - id "org.jetbrains.kotlin.android" version "2.0.0" apply false + id "org.jetbrains.kotlin.android" version "2.0.20" apply false } include ":app" From 13013f000f5342aeb1284009ebb70a5d8dffb5c8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 3 Sep 2024 00:19:49 +0000 Subject: [PATCH 05/69] chore: bump com.android.application in /example/android Bumps com.android.application from 8.5.1 to 8.6.0. --- updated-dependencies: - dependency-name: com.android.application dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- example/android/settings.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/example/android/settings.gradle b/example/android/settings.gradle index 25a7e87..b58537f 100644 --- a/example/android/settings.gradle +++ b/example/android/settings.gradle @@ -18,7 +18,7 @@ pluginManagement { plugins { id "dev.flutter.flutter-plugin-loader" version "1.0.0" - id "com.android.application" version "8.5.1" apply false + id "com.android.application" version "8.6.0" apply false id "org.jetbrains.kotlin.android" version "2.0.20" apply false } From d40f5f73e238e0239f2f429e514f633192e2c700 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 1 Sep 2024 01:34:41 +0000 Subject: [PATCH 06/69] chore: bump org.jetbrains.kotlin:kotlin-gradle-plugin in /android Bumps [org.jetbrains.kotlin:kotlin-gradle-plugin](https://github.com/JetBrains/kotlin) from 2.0.0 to 2.0.20. - [Release notes](https://github.com/JetBrains/kotlin/releases) - [Changelog](https://github.com/JetBrains/kotlin/blob/master/ChangeLog.md) - [Commits](https://github.com/JetBrains/kotlin/compare/v2.0.0...v2.0.20) --- updated-dependencies: - dependency-name: org.jetbrains.kotlin:kotlin-gradle-plugin dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- android/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/android/build.gradle b/android/build.gradle index 55e2565..414582d 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -3,7 +3,7 @@ version '1.0-SNAPSHOT' buildscript { ext.agp_version = '8.5.1' - ext.kotlin_version = '2.0.0' + ext.kotlin_version = '2.0.20' repositories { google() mavenCentral() From a29e39da49a0ac118e138f775f05416a097ccc70 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 3 Sep 2024 00:21:35 +0000 Subject: [PATCH 07/69] chore: bump com.android.tools.build:gradle in /android Bumps com.android.tools.build:gradle from 8.5.1 to 8.6.0. --- updated-dependencies: - dependency-name: com.android.tools.build:gradle dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- android/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/android/build.gradle b/android/build.gradle index 414582d..11fa52b 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -2,7 +2,7 @@ group 'net.tlserver6y.flutter_rotation_sensor' version '1.0-SNAPSHOT' buildscript { - ext.agp_version = '8.5.1' + ext.agp_version = '8.6.0' ext.kotlin_version = '2.0.20' repositories { google() From d6bb985f7bccaf0b4880943d56d8112fd95031a6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 1 Sep 2024 01:34:46 +0000 Subject: [PATCH 08/69] chore: bump org.mockito:mockito-core from 5.12.0 to 5.13.0 in /android Bumps [org.mockito:mockito-core](https://github.com/mockito/mockito) from 5.12.0 to 5.13.0. - [Release notes](https://github.com/mockito/mockito/releases) - [Commits](https://github.com/mockito/mockito/compare/v5.12.0...v5.13.0) --- updated-dependencies: - dependency-name: org.mockito:mockito-core dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- android/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/android/build.gradle b/android/build.gradle index 11fa52b..5dc5a84 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -52,7 +52,7 @@ android { dependencies { testImplementation 'org.jetbrains.kotlin:kotlin-test' - testImplementation 'org.mockito:mockito-core:5.12.0' + testImplementation 'org.mockito:mockito-core:5.13.0' } testOptions { From 7cf998983297ed7dd9c4d11025e537832f0abb66 Mon Sep 17 00:00:00 2001 From: 6y Date: Wed, 4 Sep 2024 23:54:54 +0800 Subject: [PATCH 09/69] chore: idea --- .idea/.gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.idea/.gitignore b/.idea/.gitignore index 402e09c..b83df14 100644 --- a/.idea/.gitignore +++ b/.idea/.gitignore @@ -1,3 +1,4 @@ +/caches/deviceStreaming.xml # Default ignored files /libraries/ /shelf/ From 3a2f07932338657032768cad321e030ff02b603e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 30 Sep 2024 01:25:14 +0000 Subject: [PATCH 10/69] chore: bump flutter_lints from 4.0.0 to 5.0.0 in /example Bumps [flutter_lints](https://github.com/flutter/packages/tree/main/packages) from 4.0.0 to 5.0.0. - [Release notes](https://github.com/flutter/packages/releases) - [Commits](https://github.com/flutter/packages/commits/flutter_lints-v5.0.0/packages) --- updated-dependencies: - dependency-name: flutter_lints dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- example/pubspec.lock | 8 ++++---- example/pubspec.yaml | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/example/pubspec.lock b/example/pubspec.lock index ea77015..0e74b58 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -79,10 +79,10 @@ packages: dependency: "direct dev" description: name: flutter_lints - sha256: "3f41d009ba7172d5ff9be5f6e6e6abb4300e263aab8866d2a0842ed2a70f8f0c" + sha256: "5398f14efa795ffb7a33e9b6a08798b26a180edac4ad7db3f231e40f82ce11e1" url: "https://pub.dev" source: hosted - version: "4.0.0" + version: "5.0.0" flutter_rotation_sensor: dependency: "direct main" description: @@ -133,10 +133,10 @@ packages: dependency: transitive description: name: lints - sha256: "976c774dd944a42e83e2467f4cc670daef7eed6295b10b36ae8c85bcbf828235" + sha256: "3315600f3fb3b135be672bf4a178c55f274bebe368325ae18462c89ac1e3b413" url: "https://pub.dev" source: hosted - version: "4.0.0" + version: "5.0.0" logging: dependency: transitive description: diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 5bbbe8f..f76e0b2 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -15,7 +15,7 @@ dependencies: util_simple_3d: any dev_dependencies: - flutter_lints: ^4.0.0 + flutter_lints: ^5.0.0 flutter_test: sdk: flutter integration_test: From 8af2925870c8627edca491d0108025b6c737e996 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 30 Sep 2024 01:48:25 +0000 Subject: [PATCH 11/69] chore: bump flutter_lints from 4.0.0 to 5.0.0 Bumps [flutter_lints](https://github.com/flutter/packages/tree/main/packages) from 4.0.0 to 5.0.0. - [Release notes](https://github.com/flutter/packages/releases) - [Commits](https://github.com/flutter/packages/commits/flutter_lints-v5.0.0/packages) --- updated-dependencies: - dependency-name: flutter_lints dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pubspec.yaml b/pubspec.yaml index 7abfe77..296d413 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -27,7 +27,7 @@ dependencies: dev_dependencies: build_runner: ^2.4.11 - flutter_lints: ^4.0.0 + flutter_lints: ">=4.0.0 <6.0.0" flutter_test: sdk: flutter lint: ^2.3.0 From df643a76c9fe0fcaa2a4123bcc461c91866948af Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Oct 2024 01:12:36 +0000 Subject: [PATCH 12/69] chore: bump com.android.application in /example/android Bumps com.android.application from 8.6.0 to 8.6.1. --- updated-dependencies: - dependency-name: com.android.application dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- example/android/settings.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/example/android/settings.gradle b/example/android/settings.gradle index b58537f..a1cbea7 100644 --- a/example/android/settings.gradle +++ b/example/android/settings.gradle @@ -18,7 +18,7 @@ pluginManagement { plugins { id "dev.flutter.flutter-plugin-loader" version "1.0.0" - id "com.android.application" version "8.6.0" apply false + id "com.android.application" version "8.6.1" apply false id "org.jetbrains.kotlin.android" version "2.0.20" apply false } From 311c3aef097eb830ce90df1663a7203910876a2f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Oct 2024 01:25:12 +0000 Subject: [PATCH 13/69] chore: bump com.android.tools.build:gradle in /android Bumps com.android.tools.build:gradle from 8.6.0 to 8.6.1. --- updated-dependencies: - dependency-name: com.android.tools.build:gradle dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- android/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/android/build.gradle b/android/build.gradle index 5dc5a84..1131884 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -2,7 +2,7 @@ group 'net.tlserver6y.flutter_rotation_sensor' version '1.0-SNAPSHOT' buildscript { - ext.agp_version = '8.6.0' + ext.agp_version = '8.6.1' ext.kotlin_version = '2.0.20' repositories { google() From 34b8a1c695b8901401b522d79187e803ada7bb12 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Oct 2024 01:25:16 +0000 Subject: [PATCH 14/69] chore: bump org.mockito:mockito-core from 5.13.0 to 5.14.1 in /android Bumps [org.mockito:mockito-core](https://github.com/mockito/mockito) from 5.13.0 to 5.14.1. - [Release notes](https://github.com/mockito/mockito/releases) - [Commits](https://github.com/mockito/mockito/compare/v5.13.0...v5.14.1) --- updated-dependencies: - dependency-name: org.mockito:mockito-core dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- android/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/android/build.gradle b/android/build.gradle index 1131884..1a155de 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -52,7 +52,7 @@ android { dependencies { testImplementation 'org.jetbrains.kotlin:kotlin-test' - testImplementation 'org.mockito:mockito-core:5.13.0' + testImplementation 'org.mockito:mockito-core:5.14.1' } testOptions { From 753a7b546c32189889878d1aee4bb8333759df31 Mon Sep 17 00:00:00 2001 From: 6y Date: Tue, 22 Oct 2024 00:31:21 +0800 Subject: [PATCH 15/69] fix: FlutterRotationSensorPlugin typo --- ios/Classes/FlutterRotationSensorPlugin.swift | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ios/Classes/FlutterRotationSensorPlugin.swift b/ios/Classes/FlutterRotationSensorPlugin.swift index ef8d55b..4029fb3 100644 --- a/ios/Classes/FlutterRotationSensorPlugin.swift +++ b/ios/Classes/FlutterRotationSensorPlugin.swift @@ -12,7 +12,7 @@ public class FlutterRotationSensorPlugin: NSObject, FlutterPlugin, FlutterStream let eventChannel = FlutterEventChannel(name: "rotation_sensor/orientation", binaryMessenger: registrar.messenger()) let motionManager = CMMotionManager() motionManager.deviceMotionUpdateInterval = 0.2 - let instance = RotationSensorPlugin(eventChannel: eventChannel, motionManager: motionManager) + let instance = FlutterRotationSensorPlugin(eventChannel: eventChannel, motionManager: motionManager) registrar.addMethodCallDelegate(instance, channel: methodChannel) eventChannel.setStreamHandler(instance) } @@ -43,8 +43,8 @@ public class FlutterRotationSensorPlugin: NSObject, FlutterPlugin, FlutterStream return } - let orientation = motion.orientation.quaternion - let rotationVector = [orientation.x, orientation.y, orientation.z, orientation.w, -1.0, Int64((motion.timestamp * 1000000000).rounded())] + let quaternion = motion.attitude.quaternion + let rotationVector = [quaternion.x, quaternion.y, quaternion.z, quaternion.w, -1.0, Int64((motion.timestamp * 1000000000).rounded())] DispatchQueue.main.async { events(rotationVector) } From c04763334bf9ca47405934ea494f78a1d3bfade9 Mon Sep 17 00:00:00 2001 From: 6y Date: Tue, 22 Oct 2024 00:31:36 +0800 Subject: [PATCH 16/69] chore: idea --- example/ios/.idea/workspace.xml | 62 +++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 example/ios/.idea/workspace.xml diff --git a/example/ios/.idea/workspace.xml b/example/ios/.idea/workspace.xml new file mode 100644 index 0000000..f6bbb04 --- /dev/null +++ b/example/ios/.idea/workspace.xml @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1704645071516 + + + + + + \ No newline at end of file From 2da7c3c57f2cb63b5aa61db8f9d37d0adc6baeea Mon Sep 17 00:00:00 2001 From: 6y Date: Tue, 22 Oct 2024 00:38:08 +0800 Subject: [PATCH 17/69] chore: ios files --- example/ios/Flutter/Debug.xcconfig | 1 + example/ios/Flutter/Release.xcconfig | 1 + example/ios/Podfile | 44 +++++++ example/ios/Podfile.lock | 34 ++++++ example/ios/Runner.xcodeproj/project.pbxproj | 111 ++++++++++++++++++ .../contents.xcworkspacedata | 3 + example/pubspec.lock | 2 +- 7 files changed, 195 insertions(+), 1 deletion(-) create mode 100644 example/ios/Podfile create mode 100644 example/ios/Podfile.lock diff --git a/example/ios/Flutter/Debug.xcconfig b/example/ios/Flutter/Debug.xcconfig index 592ceee..ec97fc6 100644 --- a/example/ios/Flutter/Debug.xcconfig +++ b/example/ios/Flutter/Debug.xcconfig @@ -1 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" #include "Generated.xcconfig" diff --git a/example/ios/Flutter/Release.xcconfig b/example/ios/Flutter/Release.xcconfig index 592ceee..c4855bf 100644 --- a/example/ios/Flutter/Release.xcconfig +++ b/example/ios/Flutter/Release.xcconfig @@ -1 +1,2 @@ +#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" #include "Generated.xcconfig" diff --git a/example/ios/Podfile b/example/ios/Podfile new file mode 100644 index 0000000..d97f17e --- /dev/null +++ b/example/ios/Podfile @@ -0,0 +1,44 @@ +# Uncomment this line to define a global platform for your project +# platform :ios, '12.0' + +# CocoaPods analytics sends network stats synchronously affecting flutter build latency. +ENV['COCOAPODS_DISABLE_STATS'] = 'true' + +project 'Runner', { + 'Debug' => :debug, + 'Profile' => :release, + 'Release' => :release, +} + +def flutter_root + generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) + unless File.exist?(generated_xcode_build_settings_path) + raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" + end + + File.foreach(generated_xcode_build_settings_path) do |line| + matches = line.match(/FLUTTER_ROOT\=(.*)/) + return matches[1].strip if matches + end + raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" +end + +require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) + +flutter_ios_podfile_setup + +target 'Runner' do + use_frameworks! + use_modular_headers! + + flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) + target 'RunnerTests' do + inherit! :search_paths + end +end + +post_install do |installer| + installer.pods_project.targets.each do |target| + flutter_additional_ios_build_settings(target) + end +end diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock new file mode 100644 index 0000000..f48ccee --- /dev/null +++ b/example/ios/Podfile.lock @@ -0,0 +1,34 @@ +PODS: + - Flutter (1.0.0) + - flutter_rotation_sensor (0.0.1): + - Flutter + - integration_test (0.0.1): + - Flutter + - native_device_orientation (0.0.1): + - Flutter + +DEPENDENCIES: + - Flutter (from `Flutter`) + - flutter_rotation_sensor (from `.symlinks/plugins/flutter_rotation_sensor/ios`) + - integration_test (from `.symlinks/plugins/integration_test/ios`) + - native_device_orientation (from `.symlinks/plugins/native_device_orientation/ios`) + +EXTERNAL SOURCES: + Flutter: + :path: Flutter + flutter_rotation_sensor: + :path: ".symlinks/plugins/flutter_rotation_sensor/ios" + integration_test: + :path: ".symlinks/plugins/integration_test/ios" + native_device_orientation: + :path: ".symlinks/plugins/native_device_orientation/ios" + +SPEC CHECKSUMS: + Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7 + flutter_rotation_sensor: f37d8d24050572029bdd2d55a93e0f334e2eeac6 + integration_test: 252f60fa39af5e17c3aa9899d35d908a0721b573 + native_device_orientation: 348b10c346a60ebbc62fb235a4fdb5d1b61a8f55 + +PODFILE CHECKSUM: 819463e6a0290f5a72f145ba7cde16e8b6ef0796 + +COCOAPODS: 1.15.2 diff --git a/example/ios/Runner.xcodeproj/project.pbxproj b/example/ios/Runner.xcodeproj/project.pbxproj index 25a96f1..ecbfe6f 100644 --- a/example/ios/Runner.xcodeproj/project.pbxproj +++ b/example/ios/Runner.xcodeproj/project.pbxproj @@ -14,6 +14,8 @@ 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; + BE9F15D2FFB568DE063D9FDF /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 442B0923D7B8436B3CCD8579 /* Pods_RunnerTests.framework */; }; + D4C945C8F30C01C0B409C461 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6DA4B8BD4E05916065997C8B /* Pods_Runner.framework */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -44,10 +46,16 @@ 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; 331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; 331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 35490092DF7A08CA47DE2E4F /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = ""; }; 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; + 442B0923D7B8436B3CCD8579 /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 5147A0FD623FF12CA4A74726 /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = ""; }; + 6DA4B8BD4E05916065997C8B /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 6EEA11D6CD229FBB73080310 /* 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 = ""; }; 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 = ""; }; + 7B4E204954F81176FE283190 /* 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 = ""; }; 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -55,13 +63,24 @@ 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 = ""; }; + E1CE8B3166DC6DEBC3E812ED /* 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 = ""; }; + E5C6E6A22667401C10C44A42 /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ + 5963E9AEB4BC408976824DB7 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + BE9F15D2FFB568DE063D9FDF /* Pods_RunnerTests.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 97C146EB1CF9000F007C117D /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + D4C945C8F30C01C0B409C461 /* Pods_Runner.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -76,6 +95,28 @@ path = RunnerTests; sourceTree = ""; }; + 6B9CF1C70D0CCE82C5F96636 /* Pods */ = { + isa = PBXGroup; + children = ( + 7B4E204954F81176FE283190 /* Pods-Runner.debug.xcconfig */, + E1CE8B3166DC6DEBC3E812ED /* Pods-Runner.release.xcconfig */, + 6EEA11D6CD229FBB73080310 /* Pods-Runner.profile.xcconfig */, + 5147A0FD623FF12CA4A74726 /* Pods-RunnerTests.debug.xcconfig */, + 35490092DF7A08CA47DE2E4F /* Pods-RunnerTests.release.xcconfig */, + E5C6E6A22667401C10C44A42 /* Pods-RunnerTests.profile.xcconfig */, + ); + path = Pods; + sourceTree = ""; + }; + 954DE0A6C29EEC94C5E3B497 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 6DA4B8BD4E05916065997C8B /* Pods_Runner.framework */, + 442B0923D7B8436B3CCD8579 /* Pods_RunnerTests.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; 9740EEB11CF90186004384FC /* Flutter */ = { isa = PBXGroup; children = ( @@ -94,6 +135,8 @@ 97C146F01CF9000F007C117D /* Runner */, 97C146EF1CF9000F007C117D /* Products */, 331C8082294A63A400263BE5 /* RunnerTests */, + 6B9CF1C70D0CCE82C5F96636 /* Pods */, + 954DE0A6C29EEC94C5E3B497 /* Frameworks */, ); sourceTree = ""; }; @@ -128,8 +171,10 @@ isa = PBXNativeTarget; buildConfigurationList = 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; buildPhases = ( + FD44169494515C96F14361D5 /* [CP] Check Pods Manifest.lock */, 331C807D294A63A400263BE5 /* Sources */, 331C807F294A63A400263BE5 /* Resources */, + 5963E9AEB4BC408976824DB7 /* Frameworks */, ); buildRules = ( ); @@ -145,12 +190,14 @@ isa = PBXNativeTarget; buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; buildPhases = ( + 14AC1D42F9EBCD048844FDD9 /* [CP] Check Pods Manifest.lock */, 9740EEB61CF901F6004384FC /* Run Script */, 97C146EA1CF9000F007C117D /* Sources */, 97C146EB1CF9000F007C117D /* Frameworks */, 97C146EC1CF9000F007C117D /* Resources */, 9705A1C41CF9048500538489 /* Embed Frameworks */, 3B06AD1E1E4923F5004D2608 /* Thin Binary */, + 0113537BAB7FAF4E7EC5FB12 /* [CP] Embed Pods Frameworks */, ); buildRules = ( ); @@ -222,6 +269,45 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ + 0113537BAB7FAF4E7EC5FB12 /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Embed Pods Frameworks"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; + 14AC1D42F9EBCD048844FDD9 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + 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; + }; 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { isa = PBXShellScriptBuildPhase; alwaysOutOfDate = 1; @@ -253,6 +339,28 @@ shellPath = /bin/sh; shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; }; + FD44169494515C96F14361D5 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-RunnerTests-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + 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; + }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ @@ -378,6 +486,7 @@ }; 331C8088294A63A400263BE5 /* Debug */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 5147A0FD623FF12CA4A74726 /* Pods-RunnerTests.debug.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; @@ -395,6 +504,7 @@ }; 331C8089294A63A400263BE5 /* Release */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 35490092DF7A08CA47DE2E4F /* Pods-RunnerTests.release.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; @@ -410,6 +520,7 @@ }; 331C808A294A63A400263BE5 /* Profile */ = { isa = XCBuildConfiguration; + baseConfigurationReference = E5C6E6A22667401C10C44A42 /* Pods-RunnerTests.profile.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; diff --git a/example/ios/Runner.xcworkspace/contents.xcworkspacedata b/example/ios/Runner.xcworkspace/contents.xcworkspacedata index 1d526a1..21a3cc1 100644 --- a/example/ios/Runner.xcworkspace/contents.xcworkspacedata +++ b/example/ios/Runner.xcworkspace/contents.xcworkspacedata @@ -4,4 +4,7 @@ + + diff --git a/example/pubspec.lock b/example/pubspec.lock index 0e74b58..9fa63f2 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -319,5 +319,5 @@ packages: source: hosted version: "3.0.3" sdks: - dart: ">=3.3.0 <4.0.0" + dart: ">=3.5.0 <4.0.0" flutter: ">=3.18.0-18.0.pre.54" From 983155af5bf256bf69515b8aa77e482b4ffbb481 Mon Sep 17 00:00:00 2001 From: 6y Date: Tue, 22 Oct 2024 00:42:59 +0800 Subject: [PATCH 18/69] chore: fix readme typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1f928d2..fb5c4c1 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # flutter_rotation_sensor -[![pub package](https://img.shields.io/pub/v/rotation_sensor)](https://pub.dartlang.org/packages/rotation_sensor) +[![pub package](https://img.shields.io/pub/v/flutter_rotation_sensor)](https://pub.dev/packages/flutter_rotation_sensor) [![github tag](https://img.shields.io/github/v/tag/tlserver/flutter_rotation_sensor?include_prereleases&sort=semver)](https://github.com/tlserver/flutter_rotation_sensor) [![license](https://img.shields.io/github/license/tlserver/flutter_rotation_sensor)](https://github.com/tlserver/flutter_rotation_sensor/blob/master/LICENSE) From 1c449db56296f255ddafcb90803d0423eb75f8d7 Mon Sep 17 00:00:00 2001 From: 6y Date: Tue, 22 Oct 2024 00:50:52 +0800 Subject: [PATCH 19/69] chore: bump version to 0.1.1 --- CHANGELOG.md | 4 ++++ example/pubspec.lock | 6 +++--- pubspec.yaml | 2 +- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 881d709..e6262a0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## [0.1.1] - Bug Fix + +* Fixed an issue during the build process on iOS. + ## [0.1.0] - Initial Release * Initial release. diff --git a/example/pubspec.lock b/example/pubspec.lock index 9fa63f2..b220a16 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -89,7 +89,7 @@ packages: path: ".." relative: true source: path - version: "0.1.0" + version: "0.1.1" flutter_test: dependency: "direct dev" description: flutter @@ -141,10 +141,10 @@ packages: dependency: transitive description: name: logging - sha256: "623a88c9594aa774443aa3eb2d41807a48486b5613e67599fb4c41c0ad47c340" + sha256: c8245ada5f1717ed44271ed1c26b8ce85ca3228fd2ffdb75468ab01979309d61 url: "https://pub.dev" source: hosted - version: "1.2.0" + version: "1.3.0" matcher: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 296d413..1814c15 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: flutter_rotation_sensor description: > A package provides a stream of device's orientation in three different representations: a rotation matrix, a quaternion, and Euler angles (azimuth, pitch, roll). -version: 0.1.0 +version: 0.1.1 repository: https://github.com/tlserver/flutter_rotation_sensor environment: From 190b4e20b4ea7302577f085fc6ea84b6052fd9e4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Nov 2024 01:20:15 +0000 Subject: [PATCH 20/69] chore: bump com.android.application in /example/android Bumps com.android.application from 8.6.1 to 8.7.2. --- updated-dependencies: - dependency-name: com.android.application dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- example/android/settings.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/example/android/settings.gradle b/example/android/settings.gradle index a1cbea7..b5660e1 100644 --- a/example/android/settings.gradle +++ b/example/android/settings.gradle @@ -18,7 +18,7 @@ pluginManagement { plugins { id "dev.flutter.flutter-plugin-loader" version "1.0.0" - id "com.android.application" version "8.6.1" apply false + id "com.android.application" version "8.7.2" apply false id "org.jetbrains.kotlin.android" version "2.0.20" apply false } From 2fb4735d40b8b30bf51b2ae5e8a1eef3cda1d6ab Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Nov 2024 01:54:55 +0000 Subject: [PATCH 21/69] chore: bump org.mockito:mockito-core from 5.14.1 to 5.14.2 in /android Bumps [org.mockito:mockito-core](https://github.com/mockito/mockito) from 5.14.1 to 5.14.2. - [Release notes](https://github.com/mockito/mockito/releases) - [Commits](https://github.com/mockito/mockito/compare/v5.14.1...v5.14.2) --- updated-dependencies: - dependency-name: org.mockito:mockito-core dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- android/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/android/build.gradle b/android/build.gradle index 1a155de..ead1515 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -52,7 +52,7 @@ android { dependencies { testImplementation 'org.jetbrains.kotlin:kotlin-test' - testImplementation 'org.mockito:mockito-core:5.14.1' + testImplementation 'org.mockito:mockito-core:5.14.2' } testOptions { From 82fd8fcfe8b685ba0c92e009ae250436ac84d149 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Nov 2024 01:55:27 +0000 Subject: [PATCH 22/69] chore: bump com.android.tools.build:gradle in /android Bumps com.android.tools.build:gradle from 8.6.1 to 8.7.2. --- updated-dependencies: - dependency-name: com.android.tools.build:gradle dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- android/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/android/build.gradle b/android/build.gradle index ead1515..f34ac16 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -2,7 +2,7 @@ group 'net.tlserver6y.flutter_rotation_sensor' version '1.0-SNAPSHOT' buildscript { - ext.agp_version = '8.6.1' + ext.agp_version = '8.7.2' ext.kotlin_version = '2.0.20' repositories { google() From b2dd61aacf9774064632846d347b468bcc4a6309 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 2 Dec 2024 02:07:12 +0000 Subject: [PATCH 23/69] chore: bump simple_3d_renderer from 20.0.2 to 21.0.0 in /example Bumps [simple_3d_renderer](https://github.com/MasahideMori-SimpleAppli/simple_3d_renderer) from 20.0.2 to 21.0.0. - [Changelog](https://github.com/MasahideMori-SimpleAppli/simple_3d_renderer/blob/main/CHANGELOG.md) - [Commits](https://github.com/MasahideMori-SimpleAppli/simple_3d_renderer/commits) --- updated-dependencies: - dependency-name: simple_3d_renderer dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- example/pubspec.lock | 12 ++++++------ example/pubspec.yaml | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/example/pubspec.lock b/example/pubspec.lock index b220a16..23a4836 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -213,18 +213,18 @@ packages: dependency: "direct main" description: name: simple_3d - sha256: e1f3763f7b3fa299c7c34067d69d51a55519c8b9d691cd7600976b3daa6102ef + sha256: "6e13eeb7c4dc4b3faf19e5e07bf79269e59d9a8cf496a6f202d0afd0aa05d471" url: "https://pub.dev" source: hosted - version: "14.0.1" + version: "15.0.0" simple_3d_renderer: dependency: "direct main" description: name: simple_3d_renderer - sha256: "5b089b8f652734590b3b8dc32a4dc6dc35ee2c98c47a36f2f9c22f2b76c64d0f" + sha256: "149e989b27bc78f880ba450d672a9952785046caa4f998671904ac39122a47fa" url: "https://pub.dev" source: hosted - version: "20.0.2" + version: "21.0.0" sky_engine: dependency: transitive description: flutter @@ -290,10 +290,10 @@ packages: dependency: "direct main" description: name: util_simple_3d - sha256: b4e722c9ecf2c1fad346beb47ca4416201a5ed700cd7da2d58d1c9eb89bbb01a + sha256: "7f25a0554f3a6da7a52cde8d5c9f722b41e46b3f918b111eda8ce9b59f96f9a0" url: "https://pub.dev" source: hosted - version: "10.1.0" + version: "11.0.0" vector_math: dependency: transitive description: diff --git a/example/pubspec.yaml b/example/pubspec.yaml index f76e0b2..691053b 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -11,7 +11,7 @@ dependencies: flutter_rotation_sensor: path: ../ simple_3d: any - simple_3d_renderer: ^20.0.2 + simple_3d_renderer: ^21.0.0 util_simple_3d: any dev_dependencies: From 1b23631bf9e780d5b4c711a4316c8b9a45ba92af Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 17 Dec 2024 06:30:31 +0000 Subject: [PATCH 24/69] chore: bump org.jetbrains.kotlin:kotlin-gradle-plugin in /android Bumps [org.jetbrains.kotlin:kotlin-gradle-plugin](https://github.com/JetBrains/kotlin) from 2.0.20 to 2.1.0. - [Release notes](https://github.com/JetBrains/kotlin/releases) - [Changelog](https://github.com/JetBrains/kotlin/blob/v2.1.0/ChangeLog.md) - [Commits](https://github.com/JetBrains/kotlin/compare/v2.0.20...v2.1.0) --- updated-dependencies: - dependency-name: org.jetbrains.kotlin:kotlin-gradle-plugin dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- android/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/android/build.gradle b/android/build.gradle index f34ac16..9297bc2 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -3,7 +3,7 @@ version '1.0-SNAPSHOT' buildscript { ext.agp_version = '8.7.2' - ext.kotlin_version = '2.0.20' + ext.kotlin_version = '2.1.0' repositories { google() mavenCentral() From 91d35ae137d3bb03dcc144ebb5e814c9170c6155 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 17 Dec 2024 06:31:39 +0000 Subject: [PATCH 25/69] chore: bump org.jetbrains.kotlin.android in /example/android Bumps [org.jetbrains.kotlin.android](https://github.com/JetBrains/kotlin) from 2.0.20 to 2.1.0. - [Release notes](https://github.com/JetBrains/kotlin/releases) - [Changelog](https://github.com/JetBrains/kotlin/blob/v2.1.0/ChangeLog.md) - [Commits](https://github.com/JetBrains/kotlin/compare/v2.0.20...v2.1.0) --- updated-dependencies: - dependency-name: org.jetbrains.kotlin.android dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- example/android/settings.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/example/android/settings.gradle b/example/android/settings.gradle index b5660e1..72e8d42 100644 --- a/example/android/settings.gradle +++ b/example/android/settings.gradle @@ -19,7 +19,7 @@ pluginManagement { plugins { id "dev.flutter.flutter-plugin-loader" version "1.0.0" id "com.android.application" version "8.7.2" apply false - id "org.jetbrains.kotlin.android" version "2.0.20" apply false + id "org.jetbrains.kotlin.android" version "2.1.0" apply false } include ":app" From 1844b4d058432403895785283c1c31f00027c076 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 1 Feb 2025 01:22:13 +0000 Subject: [PATCH 26/69] chore: bump org.jetbrains.kotlin.android in /example/android Bumps [org.jetbrains.kotlin.android](https://github.com/JetBrains/kotlin) from 2.1.0 to 2.1.10. - [Release notes](https://github.com/JetBrains/kotlin/releases) - [Changelog](https://github.com/JetBrains/kotlin/blob/master/ChangeLog.md) - [Commits](https://github.com/JetBrains/kotlin/compare/v2.1.0...v2.1.10) --- updated-dependencies: - dependency-name: org.jetbrains.kotlin.android dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- example/android/settings.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/example/android/settings.gradle b/example/android/settings.gradle index 72e8d42..19c0089 100644 --- a/example/android/settings.gradle +++ b/example/android/settings.gradle @@ -19,7 +19,7 @@ pluginManagement { plugins { id "dev.flutter.flutter-plugin-loader" version "1.0.0" id "com.android.application" version "8.7.2" apply false - id "org.jetbrains.kotlin.android" version "2.1.0" apply false + id "org.jetbrains.kotlin.android" version "2.1.10" apply false } include ":app" From 3e4ef8ebf6eb8e929fb8c26a1250e06bbce8f3d6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 1 Feb 2025 01:32:49 +0000 Subject: [PATCH 27/69] chore: bump org.jetbrains.kotlin:kotlin-gradle-plugin in /android Bumps [org.jetbrains.kotlin:kotlin-gradle-plugin](https://github.com/JetBrains/kotlin) from 2.1.0 to 2.1.10. - [Release notes](https://github.com/JetBrains/kotlin/releases) - [Changelog](https://github.com/JetBrains/kotlin/blob/master/ChangeLog.md) - [Commits](https://github.com/JetBrains/kotlin/compare/v2.1.0...v2.1.10) --- updated-dependencies: - dependency-name: org.jetbrains.kotlin:kotlin-gradle-plugin dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- android/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/android/build.gradle b/android/build.gradle index 9297bc2..a86bd0b 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -3,7 +3,7 @@ version '1.0-SNAPSHOT' buildscript { ext.agp_version = '8.7.2' - ext.kotlin_version = '2.1.0' + ext.kotlin_version = '2.1.10' repositories { google() mavenCentral() From d33ea8aef597cd748fb7102d6eff7d5800953b67 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 1 Feb 2025 01:32:55 +0000 Subject: [PATCH 28/69] chore: bump org.mockito:mockito-core from 5.14.2 to 5.15.2 in /android Bumps [org.mockito:mockito-core](https://github.com/mockito/mockito) from 5.14.2 to 5.15.2. - [Release notes](https://github.com/mockito/mockito/releases) - [Commits](https://github.com/mockito/mockito/compare/v5.14.2...v5.15.2) --- updated-dependencies: - dependency-name: org.mockito:mockito-core dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- android/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/android/build.gradle b/android/build.gradle index a86bd0b..cc6d0a7 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -52,7 +52,7 @@ android { dependencies { testImplementation 'org.jetbrains.kotlin:kotlin-test' - testImplementation 'org.mockito:mockito-core:5.14.2' + testImplementation 'org.mockito:mockito-core:5.15.2' } testOptions { From 7233ee0e72ee69fc7cd4e48542c11778f9556a09 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 3 Mar 2025 01:56:07 +0000 Subject: [PATCH 29/69] chore: bump simple_3d_renderer from 21.0.0 to 22.0.0 in /example Bumps [simple_3d_renderer](https://github.com/MasahideMori-SimpleAppli/simple_3d_renderer) from 21.0.0 to 22.0.0. - [Changelog](https://github.com/MasahideMori-SimpleAppli/simple_3d_renderer/blob/main/CHANGELOG.md) - [Commits](https://github.com/MasahideMori-SimpleAppli/simple_3d_renderer/commits) --- updated-dependencies: - dependency-name: simple_3d_renderer dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- example/pubspec.lock | 102 +++++++++++++++++++++---------------------- example/pubspec.yaml | 2 +- 2 files changed, 52 insertions(+), 52 deletions(-) diff --git a/example/pubspec.lock b/example/pubspec.lock index 23a4836..a477d9b 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -5,58 +5,58 @@ packages: dependency: transitive description: name: async - sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" + sha256: d2872f9c19731c2e5f10444b14686eb7cc85c76274bd6c16e1816bff9a3bab63 url: "https://pub.dev" source: hosted - version: "2.11.0" + version: "2.12.0" boolean_selector: dependency: transitive description: name: boolean_selector - sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" + sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea" url: "https://pub.dev" source: hosted - version: "2.1.1" + version: "2.1.2" characters: dependency: transitive description: name: characters - sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605" + sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803 url: "https://pub.dev" source: hosted - version: "1.3.0" + version: "1.4.0" clock: dependency: transitive description: name: clock - sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf + sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b url: "https://pub.dev" source: hosted - version: "1.1.1" + version: "1.1.2" collection: dependency: transitive description: name: collection - sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a + sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76" url: "https://pub.dev" source: hosted - version: "1.18.0" + version: "1.19.1" fake_async: dependency: transitive description: name: fake_async - sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78" + sha256: "6a95e56b2449df2273fd8c45a662d6947ce1ebb7aafe80e550a3f68297f3cacc" url: "https://pub.dev" source: hosted - version: "1.3.1" + version: "1.3.2" file: dependency: transitive description: name: file - sha256: "5fc22d7c25582e38ad9a8515372cd9a93834027aacf1801cf01164dac0ffa08c" + sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4 url: "https://pub.dev" source: hosted - version: "7.0.0" + version: "7.0.1" file_state_manager: dependency: transitive description: @@ -109,18 +109,18 @@ packages: dependency: transitive description: name: leak_tracker - sha256: "3f87a60e8c63aecc975dda1ceedbc8f24de75f09e4856ea27daf8958f2f0ce05" + sha256: c35baad643ba394b40aac41080300150a4f08fd0fd6a10378f8f7c6bc161acec url: "https://pub.dev" source: hosted - version: "10.0.5" + version: "10.0.8" leak_tracker_flutter_testing: dependency: transitive description: name: leak_tracker_flutter_testing - sha256: "932549fb305594d82d7183ecd9fa93463e9914e1b67cacc34bc40906594a1806" + sha256: f8b613e7e6a13ec79cfdc0e97638fddb3ab848452eff057653abd3edba760573 url: "https://pub.dev" source: hosted - version: "3.0.5" + version: "3.0.9" leak_tracker_testing: dependency: transitive description: @@ -149,10 +149,10 @@ packages: dependency: transitive description: name: matcher - sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb + sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2 url: "https://pub.dev" source: hosted - version: "0.12.16+1" + version: "0.12.17" material_color_utilities: dependency: transitive description: @@ -165,10 +165,10 @@ packages: dependency: transitive description: name: meta - sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7 + sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c url: "https://pub.dev" source: hosted - version: "1.15.0" + version: "1.16.0" native_device_orientation: dependency: transitive description: @@ -181,18 +181,18 @@ packages: dependency: transitive description: name: path - sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" + sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5" url: "https://pub.dev" source: hosted - version: "1.9.0" + version: "1.9.1" platform: dependency: transitive description: name: platform - sha256: "9b71283fc13df574056616011fb138fd3b793ea47cc509c189a6c3fa5f8a1a65" + sha256: "5d6b1b0036a5f331ebc77c850ebc8506cbc1e9416c27e59b439f917a902a4984" url: "https://pub.dev" source: hosted - version: "3.1.5" + version: "3.1.6" plugin_platform_interface: dependency: transitive description: @@ -205,63 +205,63 @@ packages: dependency: transitive description: name: process - sha256: "21e54fd2faf1b5bdd5102afd25012184a6793927648ea81eea80552ac9405b32" + sha256: "107d8be718f120bbba9dcd1e95e3bd325b1b4a4f07db64154635ba03f2567a0d" url: "https://pub.dev" source: hosted - version: "5.0.2" + version: "5.0.3" simple_3d: dependency: "direct main" description: name: simple_3d - sha256: "6e13eeb7c4dc4b3faf19e5e07bf79269e59d9a8cf496a6f202d0afd0aa05d471" + sha256: b9c81ecdc73b49c866cce92bedfbac085d71b082ff0b9abde17fd6cc8a3d7ffa url: "https://pub.dev" source: hosted - version: "15.0.0" + version: "16.0.0" simple_3d_renderer: dependency: "direct main" description: name: simple_3d_renderer - sha256: "149e989b27bc78f880ba450d672a9952785046caa4f998671904ac39122a47fa" + sha256: "616526557a6b4ff13d397b84e1f1ec334d26bce40e21f57ad9234fd296f99ee4" url: "https://pub.dev" source: hosted - version: "21.0.0" + version: "22.0.0" sky_engine: dependency: transitive description: flutter source: sdk - version: "0.0.99" + version: "0.0.0" source_span: dependency: transitive description: name: source_span - sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" + sha256: "254ee5351d6cb365c859e20ee823c3bb479bf4a293c22d17a9f1bf144ce86f7c" url: "https://pub.dev" source: hosted - version: "1.10.0" + version: "1.10.1" stack_trace: dependency: transitive description: name: stack_trace - sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b" + sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1" url: "https://pub.dev" source: hosted - version: "1.11.1" + version: "1.12.1" stream_channel: dependency: transitive description: name: stream_channel - sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7 + sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d" url: "https://pub.dev" source: hosted - version: "2.1.2" + version: "2.1.4" string_scanner: dependency: transitive description: name: string_scanner - sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" + sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43" url: "https://pub.dev" source: hosted - version: "1.2.0" + version: "1.4.1" sync_http: dependency: transitive description: @@ -274,26 +274,26 @@ packages: dependency: transitive description: name: term_glyph - sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 + sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e" url: "https://pub.dev" source: hosted - version: "1.2.1" + version: "1.2.2" test_api: dependency: transitive description: name: test_api - sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb" + sha256: fb31f383e2ee25fbbfe06b40fe21e1e458d14080e3c67e7ba0acfde4df4e0bbd url: "https://pub.dev" source: hosted - version: "0.7.2" + version: "0.7.4" util_simple_3d: dependency: "direct main" description: name: util_simple_3d - sha256: "7f25a0554f3a6da7a52cde8d5c9f722b41e46b3f918b111eda8ce9b59f96f9a0" + sha256: ea6b739d5679d2abe981d1ed6e787133436ddaf33d50d4ebbb0147e8f30fed14 url: "https://pub.dev" source: hosted - version: "11.0.0" + version: "12.0.0" vector_math: dependency: transitive description: @@ -306,18 +306,18 @@ packages: dependency: transitive description: name: vm_service - sha256: "5c5f338a667b4c644744b661f309fb8080bb94b18a7e91ef1dbd343bed00ed6d" + sha256: "0968250880a6c5fe7edc067ed0a13d4bae1577fe2771dcf3010d52c4a9d3ca14" url: "https://pub.dev" source: hosted - version: "14.2.5" + version: "14.3.1" webdriver: dependency: transitive description: name: webdriver - sha256: "003d7da9519e1e5f329422b36c4dcdf18d7d2978d1ba099ea4e45ba490ed845e" + sha256: "3d773670966f02a646319410766d3b5e1037efb7f07cc68f844d5e06cd4d61c8" url: "https://pub.dev" source: hosted - version: "3.0.3" + version: "3.0.4" sdks: dart: ">=3.5.0 <4.0.0" flutter: ">=3.18.0-18.0.pre.54" diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 691053b..20ff96b 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -11,7 +11,7 @@ dependencies: flutter_rotation_sensor: path: ../ simple_3d: any - simple_3d_renderer: ^21.0.0 + simple_3d_renderer: ^22.0.0 util_simple_3d: any dev_dependencies: From 3eb4ec566aa3d6e4c64c6a4783caf7724e57df8a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 6 Mar 2025 00:52:43 +0000 Subject: [PATCH 30/69] chore: bump com.android.application in /example/android Bumps com.android.application from 8.7.2 to 8.8.2. --- updated-dependencies: - dependency-name: com.android.application dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- example/android/settings.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/example/android/settings.gradle b/example/android/settings.gradle index 19c0089..18a751a 100644 --- a/example/android/settings.gradle +++ b/example/android/settings.gradle @@ -18,7 +18,7 @@ pluginManagement { plugins { id "dev.flutter.flutter-plugin-loader" version "1.0.0" - id "com.android.application" version "8.7.2" apply false + id "com.android.application" version "8.9.0" apply false id "org.jetbrains.kotlin.android" version "2.1.10" apply false } From 7038a3893bd08156119595fd596e82805e1ba69c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 6 Mar 2025 00:53:59 +0000 Subject: [PATCH 31/69] chore: bump com.android.tools.build:gradle in /android Bumps com.android.tools.build:gradle from 8.7.2 to 8.8.2. --- updated-dependencies: - dependency-name: com.android.tools.build:gradle dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- android/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/android/build.gradle b/android/build.gradle index cc6d0a7..44cb561 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -2,7 +2,7 @@ group 'net.tlserver6y.flutter_rotation_sensor' version '1.0-SNAPSHOT' buildscript { - ext.agp_version = '8.7.2' + ext.agp_version = '8.9.0' ext.kotlin_version = '2.1.10' repositories { google() From 8acc98016aaba316e4453fa680747f3808be5a86 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 24 Mar 2025 02:03:56 +0000 Subject: [PATCH 32/69] chore: bump simple_3d_renderer from 22.0.0 to 22.0.1 in /example Bumps [simple_3d_renderer](https://github.com/MasahideMori-SimpleAppli/simple_3d_renderer) from 22.0.0 to 22.0.1. - [Changelog](https://github.com/MasahideMori-SimpleAppli/simple_3d_renderer/blob/main/CHANGELOG.md) - [Commits](https://github.com/MasahideMori-SimpleAppli/simple_3d_renderer/commits) --- updated-dependencies: - dependency-name: simple_3d_renderer dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- example/pubspec.lock | 12 ++++++------ example/pubspec.yaml | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/example/pubspec.lock b/example/pubspec.lock index a477d9b..d981eca 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -213,18 +213,18 @@ packages: dependency: "direct main" description: name: simple_3d - sha256: b9c81ecdc73b49c866cce92bedfbac085d71b082ff0b9abde17fd6cc8a3d7ffa + sha256: "16388598cd3b864a1f5c9d9f2869e60dc8181bd08a1da8c4c3deb0991174d90e" url: "https://pub.dev" source: hosted - version: "16.0.0" + version: "16.0.1" simple_3d_renderer: dependency: "direct main" description: name: simple_3d_renderer - sha256: "616526557a6b4ff13d397b84e1f1ec334d26bce40e21f57ad9234fd296f99ee4" + sha256: b3f946407b304a85860ed1acd80e11ac2fe142d90caf545896a8f03bc8ae6744 url: "https://pub.dev" source: hosted - version: "22.0.0" + version: "22.0.1" sky_engine: dependency: transitive description: flutter @@ -290,10 +290,10 @@ packages: dependency: "direct main" description: name: util_simple_3d - sha256: ea6b739d5679d2abe981d1ed6e787133436ddaf33d50d4ebbb0147e8f30fed14 + sha256: "95e47e4ead200510993feaddd3ff169d067fb1a638e77a0411d1f5d73d39b2c9" url: "https://pub.dev" source: hosted - version: "12.0.0" + version: "12.0.1" vector_math: dependency: transitive description: diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 20ff96b..c25f345 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -11,7 +11,7 @@ dependencies: flutter_rotation_sensor: path: ../ simple_3d: any - simple_3d_renderer: ^22.0.0 + simple_3d_renderer: ^22.0.1 util_simple_3d: any dev_dependencies: From ee97639b4cebfb5ac786eaff7b0d01ac89e91a34 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Apr 2025 01:32:32 +0000 Subject: [PATCH 33/69] chore: bump org.jetbrains.kotlin.android in /example/android Bumps [org.jetbrains.kotlin.android](https://github.com/JetBrains/kotlin) from 2.1.10 to 2.1.20. - [Release notes](https://github.com/JetBrains/kotlin/releases) - [Changelog](https://github.com/JetBrains/kotlin/blob/master/ChangeLog.md) - [Commits](https://github.com/JetBrains/kotlin/compare/v2.1.10...v2.1.20) --- updated-dependencies: - dependency-name: org.jetbrains.kotlin.android dependency-version: 2.1.20 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- example/android/settings.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/example/android/settings.gradle b/example/android/settings.gradle index 18a751a..143549a 100644 --- a/example/android/settings.gradle +++ b/example/android/settings.gradle @@ -19,7 +19,7 @@ pluginManagement { plugins { id "dev.flutter.flutter-plugin-loader" version "1.0.0" id "com.android.application" version "8.9.0" apply false - id "org.jetbrains.kotlin.android" version "2.1.10" apply false + id "org.jetbrains.kotlin.android" version "2.1.20" apply false } include ":app" From 2377f8191930d2376d9c7a600356b7f9770830cc Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Apr 2025 01:34:31 +0000 Subject: [PATCH 34/69] chore: bump org.jetbrains.kotlin:kotlin-gradle-plugin in /android Bumps [org.jetbrains.kotlin:kotlin-gradle-plugin](https://github.com/JetBrains/kotlin) from 2.1.10 to 2.1.20. - [Release notes](https://github.com/JetBrains/kotlin/releases) - [Changelog](https://github.com/JetBrains/kotlin/blob/master/ChangeLog.md) - [Commits](https://github.com/JetBrains/kotlin/compare/v2.1.10...v2.1.20) --- updated-dependencies: - dependency-name: org.jetbrains.kotlin:kotlin-gradle-plugin dependency-version: 2.1.20 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- android/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/android/build.gradle b/android/build.gradle index 44cb561..af1a200 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -3,7 +3,7 @@ version '1.0-SNAPSHOT' buildscript { ext.agp_version = '8.9.0' - ext.kotlin_version = '2.1.10' + ext.kotlin_version = '2.1.20' repositories { google() mavenCentral() From c640faee500b60b887801409c96a111b555b410c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 16 Apr 2025 11:15:15 +0000 Subject: [PATCH 35/69] chore: bump com.android.application in /example/android Bumps com.android.application from 8.9.0 to 8.9.1. --- updated-dependencies: - dependency-name: com.android.application dependency-version: 8.9.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- example/android/settings.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/example/android/settings.gradle b/example/android/settings.gradle index 143549a..ad3470b 100644 --- a/example/android/settings.gradle +++ b/example/android/settings.gradle @@ -18,7 +18,7 @@ pluginManagement { plugins { id "dev.flutter.flutter-plugin-loader" version "1.0.0" - id "com.android.application" version "8.9.0" apply false + id "com.android.application" version "8.9.1" apply false id "org.jetbrains.kotlin.android" version "2.1.20" apply false } From a9dbc0e4e18b13c9325588afc8597cd8226575a1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 16 Apr 2025 11:15:20 +0000 Subject: [PATCH 36/69] chore: bump com.android.tools.build:gradle in /android Bumps com.android.tools.build:gradle from 8.9.0 to 8.9.1. --- updated-dependencies: - dependency-name: com.android.tools.build:gradle dependency-version: 8.9.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- android/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/android/build.gradle b/android/build.gradle index af1a200..c2ae4ef 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -2,7 +2,7 @@ group 'net.tlserver6y.flutter_rotation_sensor' version '1.0-SNAPSHOT' buildscript { - ext.agp_version = '8.9.0' + ext.agp_version = '8.9.1' ext.kotlin_version = '2.1.20' repositories { google() From 03ed92477963a49ff285ca24a66278bf8ccdbe7e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Apr 2025 01:38:20 +0000 Subject: [PATCH 37/69] chore: bump org.mockito:mockito-core from 5.15.2 to 5.16.1 in /android Bumps [org.mockito:mockito-core](https://github.com/mockito/mockito) from 5.15.2 to 5.16.1. - [Release notes](https://github.com/mockito/mockito/releases) - [Commits](https://github.com/mockito/mockito/compare/v5.15.2...v5.16.1) --- updated-dependencies: - dependency-name: org.mockito:mockito-core dependency-version: 5.16.1 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- android/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/android/build.gradle b/android/build.gradle index c2ae4ef..43dc2d8 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -52,7 +52,7 @@ android { dependencies { testImplementation 'org.jetbrains.kotlin:kotlin-test' - testImplementation 'org.mockito:mockito-core:5.15.2' + testImplementation 'org.mockito:mockito-core:5.16.1' } testOptions { From 09f1a00c393c15e884f19ce23b720fa4135dd175 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 1 May 2025 01:29:48 +0000 Subject: [PATCH 38/69] chore: bump com.android.application in /example/android Bumps com.android.application from 8.9.1 to 8.9.2. --- updated-dependencies: - dependency-name: com.android.application dependency-version: 8.9.2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- example/android/settings.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/example/android/settings.gradle b/example/android/settings.gradle index ad3470b..0395df8 100644 --- a/example/android/settings.gradle +++ b/example/android/settings.gradle @@ -18,7 +18,7 @@ pluginManagement { plugins { id "dev.flutter.flutter-plugin-loader" version "1.0.0" - id "com.android.application" version "8.9.1" apply false + id "com.android.application" version "8.9.2" apply false id "org.jetbrains.kotlin.android" version "2.1.20" apply false } From 1f08b0ebe38d386ebe1e08ed8b8e215f97750160 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 1 May 2025 01:45:46 +0000 Subject: [PATCH 39/69] chore: bump com.android.tools.build:gradle in /android Bumps com.android.tools.build:gradle from 8.9.1 to 8.9.2. --- updated-dependencies: - dependency-name: com.android.tools.build:gradle dependency-version: 8.9.2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- android/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/android/build.gradle b/android/build.gradle index 43dc2d8..015c935 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -2,7 +2,7 @@ group 'net.tlserver6y.flutter_rotation_sensor' version '1.0-SNAPSHOT' buildscript { - ext.agp_version = '8.9.1' + ext.agp_version = '8.9.2' ext.kotlin_version = '2.1.20' repositories { google() From 729c8145eeb5a6bc548d32b5b5b866b3bfc011e4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 1 May 2025 01:45:43 +0000 Subject: [PATCH 40/69] chore: bump org.mockito:mockito-core from 5.16.1 to 5.17.0 in /android Bumps [org.mockito:mockito-core](https://github.com/mockito/mockito) from 5.16.1 to 5.17.0. - [Release notes](https://github.com/mockito/mockito/releases) - [Commits](https://github.com/mockito/mockito/compare/v5.16.1...v5.17.0) --- updated-dependencies: - dependency-name: org.mockito:mockito-core dependency-version: 5.17.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- android/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/android/build.gradle b/android/build.gradle index 015c935..76cb767 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -52,7 +52,7 @@ android { dependencies { testImplementation 'org.jetbrains.kotlin:kotlin-test' - testImplementation 'org.mockito:mockito-core:5.16.1' + testImplementation 'org.mockito:mockito-core:5.17.0' } testOptions { From f0d0623afe2fe0bd3ebc7eb6a6b7262a0642c082 Mon Sep 17 00:00:00 2001 From: 6y Date: Thu, 1 May 2025 12:18:04 +0800 Subject: [PATCH 41/69] chore: recreate flutter project by 3.29.2 - rename gradle files --- example/android/app/{build.gradle => build.gradle.kts} | 0 example/android/{build.gradle => build.gradle.kts} | 0 example/android/{settings.gradle => settings.gradle.kts} | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename example/android/app/{build.gradle => build.gradle.kts} (100%) rename example/android/{build.gradle => build.gradle.kts} (100%) rename example/android/{settings.gradle => settings.gradle.kts} (100%) diff --git a/example/android/app/build.gradle b/example/android/app/build.gradle.kts similarity index 100% rename from example/android/app/build.gradle rename to example/android/app/build.gradle.kts diff --git a/example/android/build.gradle b/example/android/build.gradle.kts similarity index 100% rename from example/android/build.gradle rename to example/android/build.gradle.kts diff --git a/example/android/settings.gradle b/example/android/settings.gradle.kts similarity index 100% rename from example/android/settings.gradle rename to example/android/settings.gradle.kts From 08559cbf8ee93fe96a8d1ed09ebcadd34f908626 Mon Sep 17 00:00:00 2001 From: 6y Date: Thu, 1 May 2025 12:18:04 +0800 Subject: [PATCH 42/69] chore: recreate flutter project by 3.29.2 --- .metadata | 14 +-- analysis_options.yaml | 1 - android/build.gradle | 18 ++- example/android/.gitignore | 3 +- example/android/app/build.gradle.kts | 38 ++---- .../MainActivity.kt | 2 +- example/android/build.gradle.kts | 13 +- example/android/gradle.properties | 2 +- .../gradle/wrapper/gradle-wrapper.properties | 2 +- example/android/settings.gradle.kts | 22 ++-- example/ios/Flutter/Debug.xcconfig | 1 - example/ios/Flutter/Release.xcconfig | 1 - example/ios/Runner.xcodeproj/project.pbxproj | 111 ------------------ .../xcshareddata/xcschemes/Runner.xcscheme | 1 + .../contents.xcworkspacedata | 3 - example/ios/Runner/AppDelegate.swift | 2 +- example/pubspec.lock | 4 +- example/pubspec.yaml | 2 +- ios/Resources/PrivacyInfo.xcprivacy | 14 +++ pubspec.yaml | 4 +- 20 files changed, 72 insertions(+), 186 deletions(-) create mode 100644 ios/Resources/PrivacyInfo.xcprivacy diff --git a/.metadata b/.metadata index 458e07f..cff4c42 100644 --- a/.metadata +++ b/.metadata @@ -4,7 +4,7 @@ # This file should be version controlled and should not be manually edited. version: - revision: "761747bfc538b5af34aa0d3fac380f1bc331ec49" + revision: "c23637390482d4cf9598c3ce3f2be31aa7332daf" channel: "stable" project_type: plugin @@ -13,14 +13,14 @@ project_type: plugin migration: platforms: - platform: root - create_revision: 761747bfc538b5af34aa0d3fac380f1bc331ec49 - base_revision: 761747bfc538b5af34aa0d3fac380f1bc331ec49 + create_revision: c23637390482d4cf9598c3ce3f2be31aa7332daf + base_revision: c23637390482d4cf9598c3ce3f2be31aa7332daf - platform: android - create_revision: 761747bfc538b5af34aa0d3fac380f1bc331ec49 - base_revision: 761747bfc538b5af34aa0d3fac380f1bc331ec49 + create_revision: c23637390482d4cf9598c3ce3f2be31aa7332daf + base_revision: c23637390482d4cf9598c3ce3f2be31aa7332daf - platform: ios - create_revision: 761747bfc538b5af34aa0d3fac380f1bc331ec49 - base_revision: 761747bfc538b5af34aa0d3fac380f1bc331ec49 + create_revision: c23637390482d4cf9598c3ce3f2be31aa7332daf + base_revision: c23637390482d4cf9598c3ce3f2be31aa7332daf # User provided section diff --git a/analysis_options.yaml b/analysis_options.yaml index 1d0804c..fc5887b 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -1,4 +1,3 @@ -# This file configures the analyzer to use the lint rule set from `package:lint` include: package:flutter_lints/flutter.yaml linter: diff --git a/android/build.gradle b/android/build.gradle index 76cb767..59782c0 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -1,5 +1,5 @@ -group 'net.tlserver6y.flutter_rotation_sensor' -version '1.0-SNAPSHOT' +group = "net.tlserver6y.flutter_rotation_sensor" +version = "1.0-SNAPSHOT" buildscript { ext.agp_version = '8.9.2' @@ -26,19 +26,17 @@ apply plugin: 'com.android.library' apply plugin: 'kotlin-android' android { - if (project.android.hasProperty("namespace")) { - namespace 'net.tlserver6y.flutter_rotation_sensor' - } + namespace = 'net.tlserver6y.flutter_rotation_sensor' - compileSdk = 34 + compileSdk = 35 compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 } kotlinOptions { - jvmTarget = '1.8' + jvmTarget = JavaVersion.VERSION_11 } sourceSets { @@ -47,7 +45,7 @@ android { } defaultConfig { - minSdk = 19 + minSdk = 21 } dependencies { diff --git a/example/android/.gitignore b/example/android/.gitignore index 6f56801..be3943c 100644 --- a/example/android/.gitignore +++ b/example/android/.gitignore @@ -5,9 +5,10 @@ gradle-wrapper.jar /gradlew.bat /local.properties GeneratedPluginRegistrant.java +.cxx/ # Remember to never publicly share your keystore. -# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app +# See https://flutter.dev/to/reference-keystore key.properties **/*.keystore **/*.jks diff --git a/example/android/app/build.gradle.kts b/example/android/app/build.gradle.kts index 54d0f7b..e659b55 100644 --- a/example/android/app/build.gradle.kts +++ b/example/android/app/build.gradle.kts @@ -1,26 +1,8 @@ plugins { - id "com.android.application" - id "kotlin-android" + id("com.android.application") + id("kotlin-android") // The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins. - id "dev.flutter.flutter-gradle-plugin" -} - -def localProperties = new Properties() -def localPropertiesFile = rootProject.file("local.properties") -if (localPropertiesFile.exists()) { - localPropertiesFile.withReader("UTF-8") { reader -> - localProperties.load(reader) - } -} - -def flutterVersionCode = localProperties.getProperty("flutter.versionCode") -if (flutterVersionCode == null) { - flutterVersionCode = "1" -} - -def flutterVersionName = localProperties.getProperty("flutter.versionName") -if (flutterVersionName == null) { - flutterVersionName = "1.0" + id("dev.flutter.flutter-gradle-plugin") } android { @@ -29,23 +11,27 @@ android { ndkVersion = flutter.ndkVersion compileOptions { - sourceCompatibility = JavaVersion.VERSION_17 - targetCompatibility = JavaVersion.VERSION_17 + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 + } + + kotlinOptions { + jvmTarget = JavaVersion.VERSION_11.toString() } defaultConfig { applicationId = "net.tlserver6y.flutter_rotation_sensor_example" minSdk = flutter.minSdkVersion targetSdk = flutter.targetSdkVersion - versionCode = flutterVersionCode.toInteger() - versionName = flutterVersionName + versionCode = flutter.versionCode + versionName = flutter.versionName } buildTypes { release { // TODO: Add your own signing config for the release build. // Signing with the debug keys for now, so `flutter run --release` works. - signingConfig = signingConfigs.debug + signingConfig = signingConfigs.getByName("debug") } } } diff --git a/example/android/app/src/main/kotlin/net/tlserver6y/flutter_rotation_sensor_example/MainActivity.kt b/example/android/app/src/main/kotlin/net/tlserver6y/flutter_rotation_sensor_example/MainActivity.kt index 3866d29..d6d9a04 100644 --- a/example/android/app/src/main/kotlin/net/tlserver6y/flutter_rotation_sensor_example/MainActivity.kt +++ b/example/android/app/src/main/kotlin/net/tlserver6y/flutter_rotation_sensor_example/MainActivity.kt @@ -2,4 +2,4 @@ package net.tlserver6y.flutter_rotation_sensor_example import io.flutter.embedding.android.FlutterActivity -class MainActivity: FlutterActivity() +class MainActivity : FlutterActivity() diff --git a/example/android/build.gradle.kts b/example/android/build.gradle.kts index bc157bd..89176ef 100644 --- a/example/android/build.gradle.kts +++ b/example/android/build.gradle.kts @@ -5,14 +5,17 @@ allprojects { } } -rootProject.buildDir = '../build' +val newBuildDir: Directory = rootProject.layout.buildDirectory.dir("../../build").get() +rootProject.layout.buildDirectory.value(newBuildDir) + subprojects { - project.buildDir = "${rootProject.buildDir}/${project.name}" + val newSubprojectBuildDir: Directory = newBuildDir.dir(project.name) + project.layout.buildDirectory.value(newSubprojectBuildDir) } subprojects { - project.evaluationDependsOn(':app') + project.evaluationDependsOn(":app") } -tasks.register("clean", Delete) { - delete rootProject.buildDir +tasks.register("clean") { + delete(rootProject.layout.buildDirectory) } diff --git a/example/android/gradle.properties b/example/android/gradle.properties index 3b5b324..f018a61 100644 --- a/example/android/gradle.properties +++ b/example/android/gradle.properties @@ -1,3 +1,3 @@ -org.gradle.jvmargs=-Xmx4G -XX:+HeapDumpOnOutOfMemoryError +org.gradle.jvmargs=-Xmx8G -XX:MaxMetaspaceSize=4G -XX:ReservedCodeCacheSize=512m -XX:+HeapDumpOnOutOfMemoryError android.useAndroidX=true android.enableJetifier=true diff --git a/example/android/gradle/wrapper/gradle-wrapper.properties b/example/android/gradle/wrapper/gradle-wrapper.properties index 3c85cfe..afa1e8e 100644 --- a/example/android/gradle/wrapper/gradle-wrapper.properties +++ b/example/android/gradle/wrapper/gradle-wrapper.properties @@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-all.zip diff --git a/example/android/settings.gradle.kts b/example/android/settings.gradle.kts index 0395df8..f162c4b 100644 --- a/example/android/settings.gradle.kts +++ b/example/android/settings.gradle.kts @@ -1,11 +1,11 @@ pluginManagement { - def flutterSdkPath = { - def properties = new Properties() - file("local.properties").withInputStream { properties.load(it) } - def flutterSdkPath = properties.getProperty("flutter.sdk") - assert flutterSdkPath != null, "flutter.sdk not set in local.properties" - return flutterSdkPath - }() + val flutterSdkPath = run { + val properties = java.util.Properties() + file("local.properties").inputStream().use { properties.load(it) } + val flutterSdkPath = properties.getProperty("flutter.sdk") + require(flutterSdkPath != null) { "flutter.sdk not set in local.properties" } + flutterSdkPath + } includeBuild("$flutterSdkPath/packages/flutter_tools/gradle") @@ -17,9 +17,9 @@ pluginManagement { } plugins { - id "dev.flutter.flutter-plugin-loader" version "1.0.0" - id "com.android.application" version "8.9.2" apply false - id "org.jetbrains.kotlin.android" version "2.1.20" apply false + id("dev.flutter.flutter-plugin-loader") version "1.0.0" + id("com.android.application") version "8.9.2" apply false + id("org.jetbrains.kotlin.android") version "2.1.20" apply false } -include ":app" +include(":app") diff --git a/example/ios/Flutter/Debug.xcconfig b/example/ios/Flutter/Debug.xcconfig index ec97fc6..592ceee 100644 --- a/example/ios/Flutter/Debug.xcconfig +++ b/example/ios/Flutter/Debug.xcconfig @@ -1,2 +1 @@ -#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" #include "Generated.xcconfig" diff --git a/example/ios/Flutter/Release.xcconfig b/example/ios/Flutter/Release.xcconfig index c4855bf..592ceee 100644 --- a/example/ios/Flutter/Release.xcconfig +++ b/example/ios/Flutter/Release.xcconfig @@ -1,2 +1 @@ -#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" #include "Generated.xcconfig" diff --git a/example/ios/Runner.xcodeproj/project.pbxproj b/example/ios/Runner.xcodeproj/project.pbxproj index ecbfe6f..25a96f1 100644 --- a/example/ios/Runner.xcodeproj/project.pbxproj +++ b/example/ios/Runner.xcodeproj/project.pbxproj @@ -14,8 +14,6 @@ 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; - BE9F15D2FFB568DE063D9FDF /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 442B0923D7B8436B3CCD8579 /* Pods_RunnerTests.framework */; }; - D4C945C8F30C01C0B409C461 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6DA4B8BD4E05916065997C8B /* Pods_Runner.framework */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -46,16 +44,10 @@ 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; 331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; 331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; - 35490092DF7A08CA47DE2E4F /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = ""; }; 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; - 442B0923D7B8436B3CCD8579 /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 5147A0FD623FF12CA4A74726 /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = ""; }; - 6DA4B8BD4E05916065997C8B /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 6EEA11D6CD229FBB73080310 /* 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 = ""; }; 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 = ""; }; - 7B4E204954F81176FE283190 /* 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 = ""; }; 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -63,24 +55,13 @@ 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 = ""; }; - E1CE8B3166DC6DEBC3E812ED /* 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 = ""; }; - E5C6E6A22667401C10C44A42 /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ - 5963E9AEB4BC408976824DB7 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - BE9F15D2FFB568DE063D9FDF /* Pods_RunnerTests.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; 97C146EB1CF9000F007C117D /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - D4C945C8F30C01C0B409C461 /* Pods_Runner.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -95,28 +76,6 @@ path = RunnerTests; sourceTree = ""; }; - 6B9CF1C70D0CCE82C5F96636 /* Pods */ = { - isa = PBXGroup; - children = ( - 7B4E204954F81176FE283190 /* Pods-Runner.debug.xcconfig */, - E1CE8B3166DC6DEBC3E812ED /* Pods-Runner.release.xcconfig */, - 6EEA11D6CD229FBB73080310 /* Pods-Runner.profile.xcconfig */, - 5147A0FD623FF12CA4A74726 /* Pods-RunnerTests.debug.xcconfig */, - 35490092DF7A08CA47DE2E4F /* Pods-RunnerTests.release.xcconfig */, - E5C6E6A22667401C10C44A42 /* Pods-RunnerTests.profile.xcconfig */, - ); - path = Pods; - sourceTree = ""; - }; - 954DE0A6C29EEC94C5E3B497 /* Frameworks */ = { - isa = PBXGroup; - children = ( - 6DA4B8BD4E05916065997C8B /* Pods_Runner.framework */, - 442B0923D7B8436B3CCD8579 /* Pods_RunnerTests.framework */, - ); - name = Frameworks; - sourceTree = ""; - }; 9740EEB11CF90186004384FC /* Flutter */ = { isa = PBXGroup; children = ( @@ -135,8 +94,6 @@ 97C146F01CF9000F007C117D /* Runner */, 97C146EF1CF9000F007C117D /* Products */, 331C8082294A63A400263BE5 /* RunnerTests */, - 6B9CF1C70D0CCE82C5F96636 /* Pods */, - 954DE0A6C29EEC94C5E3B497 /* Frameworks */, ); sourceTree = ""; }; @@ -171,10 +128,8 @@ isa = PBXNativeTarget; buildConfigurationList = 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; buildPhases = ( - FD44169494515C96F14361D5 /* [CP] Check Pods Manifest.lock */, 331C807D294A63A400263BE5 /* Sources */, 331C807F294A63A400263BE5 /* Resources */, - 5963E9AEB4BC408976824DB7 /* Frameworks */, ); buildRules = ( ); @@ -190,14 +145,12 @@ isa = PBXNativeTarget; buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; buildPhases = ( - 14AC1D42F9EBCD048844FDD9 /* [CP] Check Pods Manifest.lock */, 9740EEB61CF901F6004384FC /* Run Script */, 97C146EA1CF9000F007C117D /* Sources */, 97C146EB1CF9000F007C117D /* Frameworks */, 97C146EC1CF9000F007C117D /* Resources */, 9705A1C41CF9048500538489 /* Embed Frameworks */, 3B06AD1E1E4923F5004D2608 /* Thin Binary */, - 0113537BAB7FAF4E7EC5FB12 /* [CP] Embed Pods Frameworks */, ); buildRules = ( ); @@ -269,45 +222,6 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ - 0113537BAB7FAF4E7EC5FB12 /* [CP] Embed Pods Frameworks */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", - ); - name = "[CP] Embed Pods Frameworks"; - outputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; - showEnvVarsInLog = 0; - }; - 14AC1D42F9EBCD048844FDD9 /* [CP] Check Pods Manifest.lock */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - "${PODS_PODFILE_DIR_PATH}/Podfile.lock", - "${PODS_ROOT}/Manifest.lock", - ); - name = "[CP] Check Pods Manifest.lock"; - outputFileListPaths = ( - ); - outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - 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; - }; 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { isa = PBXShellScriptBuildPhase; alwaysOutOfDate = 1; @@ -339,28 +253,6 @@ shellPath = /bin/sh; shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; }; - FD44169494515C96F14361D5 /* [CP] Check Pods Manifest.lock */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - "${PODS_PODFILE_DIR_PATH}/Podfile.lock", - "${PODS_ROOT}/Manifest.lock", - ); - name = "[CP] Check Pods Manifest.lock"; - outputFileListPaths = ( - ); - outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-RunnerTests-checkManifestLockResult.txt", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - 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; - }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ @@ -486,7 +378,6 @@ }; 331C8088294A63A400263BE5 /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 5147A0FD623FF12CA4A74726 /* Pods-RunnerTests.debug.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; @@ -504,7 +395,6 @@ }; 331C8089294A63A400263BE5 /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 35490092DF7A08CA47DE2E4F /* Pods-RunnerTests.release.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; @@ -520,7 +410,6 @@ }; 331C808A294A63A400263BE5 /* Profile */ = { isa = XCBuildConfiguration; - baseConfigurationReference = E5C6E6A22667401C10C44A42 /* Pods-RunnerTests.profile.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; diff --git a/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index 8e3ca5d..15cada4 100644 --- a/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -59,6 +59,7 @@ ignoresPersistentStateOnLaunch = "NO" debugDocumentVersioning = "YES" debugServiceExtension = "internal" + enableGPUValidationMode = "1" allowLocationSimulation = "YES"> diff --git a/example/ios/Runner.xcworkspace/contents.xcworkspacedata b/example/ios/Runner.xcworkspace/contents.xcworkspacedata index 21a3cc1..1d526a1 100644 --- a/example/ios/Runner.xcworkspace/contents.xcworkspacedata +++ b/example/ios/Runner.xcworkspace/contents.xcworkspacedata @@ -4,7 +4,4 @@ - - diff --git a/example/ios/Runner/AppDelegate.swift b/example/ios/Runner/AppDelegate.swift index 9074fee..6266644 100644 --- a/example/ios/Runner/AppDelegate.swift +++ b/example/ios/Runner/AppDelegate.swift @@ -1,7 +1,7 @@ import Flutter import UIKit -@UIApplicationMain +@main @objc class AppDelegate: FlutterAppDelegate { override func application( _ application: UIApplication, diff --git a/example/pubspec.lock b/example/pubspec.lock index d981eca..35aafd9 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -319,5 +319,5 @@ packages: source: hosted version: "3.0.4" sdks: - dart: ">=3.5.0 <4.0.0" - flutter: ">=3.18.0-18.0.pre.54" + dart: ">=3.7.2 <4.0.0" + flutter: ">=3.27.0" diff --git a/example/pubspec.yaml b/example/pubspec.yaml index c25f345..bb56588 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -3,7 +3,7 @@ description: "Demonstrates how to use the flutter_rotation_sensor plugin." publish_to: 'none' environment: - sdk: '>=3.2.3 <4.0.0' + sdk: ^3.7.2 dependencies: flutter: diff --git a/ios/Resources/PrivacyInfo.xcprivacy b/ios/Resources/PrivacyInfo.xcprivacy new file mode 100644 index 0000000..a34b7e2 --- /dev/null +++ b/ios/Resources/PrivacyInfo.xcprivacy @@ -0,0 +1,14 @@ + + + + + NSPrivacyTrackingDomains + + NSPrivacyAccessedAPITypes + + NSPrivacyCollectedDataTypes + + NSPrivacyTracking + + + diff --git a/pubspec.yaml b/pubspec.yaml index 1814c15..570b46f 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -6,7 +6,7 @@ version: 0.1.1 repository: https://github.com/tlserver/flutter_rotation_sensor environment: - sdk: '>=3.2.3 <4.0.0' + sdk: ^3.7.2 flutter: '>=3.3.0' topics: @@ -27,7 +27,7 @@ dependencies: dev_dependencies: build_runner: ^2.4.11 - flutter_lints: ">=4.0.0 <6.0.0" + flutter_lints: ^5.0.0 flutter_test: sdk: flutter lint: ^2.3.0 From 15a0337198ab176013d3a8609311f5a08c39df55 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 1 Jun 2025 01:10:41 +0000 Subject: [PATCH 43/69] chore: bump org.mockito:mockito-core from 5.17.0 to 5.18.0 in /android Bumps [org.mockito:mockito-core](https://github.com/mockito/mockito) from 5.17.0 to 5.18.0. - [Release notes](https://github.com/mockito/mockito/releases) - [Commits](https://github.com/mockito/mockito/compare/v5.17.0...v5.18.0) --- updated-dependencies: - dependency-name: org.mockito:mockito-core dependency-version: 5.18.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- android/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/android/build.gradle b/android/build.gradle index 59782c0..fa2b6af 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -50,7 +50,7 @@ android { dependencies { testImplementation 'org.jetbrains.kotlin:kotlin-test' - testImplementation 'org.mockito:mockito-core:5.17.0' + testImplementation 'org.mockito:mockito-core:5.18.0' } testOptions { From d2ee481e4dbb9d08c738f8f96fe6a4c9f64f387b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 2 Jun 2025 09:28:35 +0800 Subject: [PATCH 44/69] chore: bump flutter_lints from 5.0.0 to 6.0.0 Bumps [flutter_lints](https://github.com/flutter/packages/tree/main/packages) from 5.0.0 to 6.0.0. - [Release notes](https://github.com/flutter/packages/releases) - [Commits](https://github.com/flutter/packages/commits/flutter_lints-v6.0.0/packages) --- updated-dependencies: - dependency-name: flutter_lints dependency-version: 6.0.0 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pubspec.yaml b/pubspec.yaml index 570b46f..8b07089 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -27,7 +27,7 @@ dependencies: dev_dependencies: build_runner: ^2.4.11 - flutter_lints: ^5.0.0 + flutter_lints: ^6.0.0 flutter_test: sdk: flutter lint: ^2.3.0 From 63b6de62dbffeeb6740eab8b41429a802119e75f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 2 Jun 2025 01:49:03 +0000 Subject: [PATCH 45/69] chore: bump flutter_lints from 5.0.0 to 6.0.0 in /example Bumps [flutter_lints](https://github.com/flutter/packages/tree/main/packages) from 5.0.0 to 6.0.0. - [Release notes](https://github.com/flutter/packages/releases) - [Commits](https://github.com/flutter/packages/commits/flutter_lints-v6.0.0/packages) --- updated-dependencies: - dependency-name: flutter_lints dependency-version: 6.0.0 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- example/pubspec.lock | 28 ++++++++++++++-------------- example/pubspec.yaml | 2 +- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/example/pubspec.lock b/example/pubspec.lock index 35aafd9..8e3b7fd 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -5,10 +5,10 @@ packages: dependency: transitive description: name: async - sha256: d2872f9c19731c2e5f10444b14686eb7cc85c76274bd6c16e1816bff9a3bab63 + sha256: "758e6d74e971c3e5aceb4110bfd6698efc7f501675bcfe0c775459a8140750eb" url: "https://pub.dev" source: hosted - version: "2.12.0" + version: "2.13.0" boolean_selector: dependency: transitive description: @@ -45,10 +45,10 @@ packages: dependency: transitive description: name: fake_async - sha256: "6a95e56b2449df2273fd8c45a662d6947ce1ebb7aafe80e550a3f68297f3cacc" + sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44" url: "https://pub.dev" source: hosted - version: "1.3.2" + version: "1.3.3" file: dependency: transitive description: @@ -79,10 +79,10 @@ packages: dependency: "direct dev" description: name: flutter_lints - sha256: "5398f14efa795ffb7a33e9b6a08798b26a180edac4ad7db3f231e40f82ce11e1" + sha256: "3105dc8492f6183fb076ccf1f351ac3d60564bff92e20bfc4af9cc1651f4e7e1" url: "https://pub.dev" source: hosted - version: "5.0.0" + version: "6.0.0" flutter_rotation_sensor: dependency: "direct main" description: @@ -109,10 +109,10 @@ packages: dependency: transitive description: name: leak_tracker - sha256: c35baad643ba394b40aac41080300150a4f08fd0fd6a10378f8f7c6bc161acec + sha256: "6bb818ecbdffe216e81182c2f0714a2e62b593f4a4f13098713ff1685dfb6ab0" url: "https://pub.dev" source: hosted - version: "10.0.8" + version: "10.0.9" leak_tracker_flutter_testing: dependency: transitive description: @@ -133,10 +133,10 @@ packages: dependency: transitive description: name: lints - sha256: "3315600f3fb3b135be672bf4a178c55f274bebe368325ae18462c89ac1e3b413" + sha256: a5e2b223cb7c9c8efdc663ef484fdd95bb243bff242ef5b13e26883547fce9a0 url: "https://pub.dev" source: hosted - version: "5.0.0" + version: "6.0.0" logging: dependency: transitive description: @@ -306,18 +306,18 @@ packages: dependency: transitive description: name: vm_service - sha256: "0968250880a6c5fe7edc067ed0a13d4bae1577fe2771dcf3010d52c4a9d3ca14" + sha256: ddfa8d30d89985b96407efce8acbdd124701f96741f2d981ca860662f1c0dc02 url: "https://pub.dev" source: hosted - version: "14.3.1" + version: "15.0.0" webdriver: dependency: transitive description: name: webdriver - sha256: "3d773670966f02a646319410766d3b5e1037efb7f07cc68f844d5e06cd4d61c8" + sha256: "2f3a14ca026957870cfd9c635b83507e0e51d8091568e90129fbf805aba7cade" url: "https://pub.dev" source: hosted - version: "3.0.4" + version: "3.1.0" sdks: dart: ">=3.7.2 <4.0.0" flutter: ">=3.27.0" diff --git a/example/pubspec.yaml b/example/pubspec.yaml index bb56588..649d005 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -15,7 +15,7 @@ dependencies: util_simple_3d: any dev_dependencies: - flutter_lints: ^5.0.0 + flutter_lints: ^6.0.0 flutter_test: sdk: flutter integration_test: From f0bf81a0ae75999f40788d0213929aee490408bd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Jul 2025 04:52:15 +0000 Subject: [PATCH 46/69] chore: bump org.jetbrains.kotlin:kotlin-gradle-plugin in /android Bumps [org.jetbrains.kotlin:kotlin-gradle-plugin](https://github.com/JetBrains/kotlin) from 2.1.20 to 2.2.0. - [Release notes](https://github.com/JetBrains/kotlin/releases) - [Changelog](https://github.com/JetBrains/kotlin/blob/master/ChangeLog.md) - [Commits](https://github.com/JetBrains/kotlin/compare/v2.1.20...v2.2.0) --- updated-dependencies: - dependency-name: org.jetbrains.kotlin:kotlin-gradle-plugin dependency-version: 2.2.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- android/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/android/build.gradle b/android/build.gradle index fa2b6af..4ddec1f 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -3,7 +3,7 @@ version = "1.0-SNAPSHOT" buildscript { ext.agp_version = '8.9.2' - ext.kotlin_version = '2.1.20' + ext.kotlin_version = '2.2.0' repositories { google() mavenCentral() From 3e495013ffb0cc837d086b6041892a5758459117 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Jul 2025 14:24:30 +0800 Subject: [PATCH 47/69] chore: bump org.jetbrains.kotlin.android in /example/android Bumps [org.jetbrains.kotlin.android](https://github.com/JetBrains/kotlin) from 2.1.20 to 2.2.0. - [Release notes](https://github.com/JetBrains/kotlin/releases) - [Changelog](https://github.com/JetBrains/kotlin/blob/master/ChangeLog.md) - [Commits](https://github.com/JetBrains/kotlin/compare/v2.1.20...v2.2.0) --- updated-dependencies: - dependency-name: org.jetbrains.kotlin.android dependency-version: 2.2.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] # Conflicts: # example/android/settings.gradle --- example/android/settings.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/example/android/settings.gradle.kts b/example/android/settings.gradle.kts index f162c4b..93fcba3 100644 --- a/example/android/settings.gradle.kts +++ b/example/android/settings.gradle.kts @@ -19,7 +19,7 @@ pluginManagement { plugins { id("dev.flutter.flutter-plugin-loader") version "1.0.0" id("com.android.application") version "8.9.2" apply false - id("org.jetbrains.kotlin.android") version "2.1.20" apply false + id("org.jetbrains.kotlin.android") version "2.2.0" apply false } include(":app") From 176f957d6c5e3bd8af2fdab2b9ee16a904e85975 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 8 Jul 2025 12:28:25 +0000 Subject: [PATCH 48/69] chore: bump com.android.tools.build:gradle in /android Bumps com.android.tools.build:gradle from 8.9.2 to 8.11.0. --- updated-dependencies: - dependency-name: com.android.tools.build:gradle dependency-version: 8.11.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- android/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/android/build.gradle b/android/build.gradle index 4ddec1f..ed44404 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -2,7 +2,7 @@ group = "net.tlserver6y.flutter_rotation_sensor" version = "1.0-SNAPSHOT" buildscript { - ext.agp_version = '8.9.2' + ext.agp_version = '8.11.0' ext.kotlin_version = '2.2.0' repositories { google() From b90c0477546965b30f6fe4a06b52f07dcee5b034 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 8 Jul 2025 20:28:38 +0800 Subject: [PATCH 49/69] chore: bump com.android.application in /example/android Bumps com.android.application from 8.9.2 to 8.11.0. --- updated-dependencies: - dependency-name: com.android.application dependency-version: 8.11.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] # Conflicts: # example/android/settings.gradle --- example/android/settings.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/example/android/settings.gradle.kts b/example/android/settings.gradle.kts index 93fcba3..0604b23 100644 --- a/example/android/settings.gradle.kts +++ b/example/android/settings.gradle.kts @@ -18,7 +18,7 @@ pluginManagement { plugins { id("dev.flutter.flutter-plugin-loader") version "1.0.0" - id("com.android.application") version "8.9.2" apply false + id("com.android.application") version "8.11.0" apply false id("org.jetbrains.kotlin.android") version "2.2.0" apply false } From a5856b936aec97e0cc33c753ee4c500a78c8912c Mon Sep 17 00:00:00 2001 From: Eagle Date: Thu, 7 Aug 2025 08:50:09 +0300 Subject: [PATCH 50/69] docs: Fix incorrect class reference in README (OrientationEvent) #62 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index fb5c4c1..2742c22 100644 --- a/README.md +++ b/README.md @@ -67,7 +67,7 @@ For more control, you can subscribe to the stream directly: 1. Initialize the sensor and specify the desired update interval during `initState`: ```dart - late final StreamSubscription orientationSubscription; + late final StreamSubscription orientationSubscription; @override void initState() { From 07da9468c65fc6bcc640d3877134350f35e347e3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 10 Oct 2025 02:35:32 +0000 Subject: [PATCH 51/69] chore: bump simple_3d_renderer from 22.0.1 to 22.0.2 in /example Dependabot couldn't find the original pull request head commit, 3e149057d9f2cfe605d8677d123baa9958f62c67. --- example/pubspec.lock | 36 ++++++++++++++++++------------------ example/pubspec.yaml | 2 +- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/example/pubspec.lock b/example/pubspec.lock index 8e3b7fd..bc313c5 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -61,10 +61,10 @@ packages: dependency: transitive description: name: file_state_manager - sha256: "19ae8a33cf3bf6a9890f7819757531d5840fa6d8bf3a4be2fb89e94e9e5e3304" + sha256: a64f7dfe52e45bb1bb1a0e357ab6d38efddc361f33003c0c0a9b78bf9cf0731d url: "https://pub.dev" source: hosted - version: "1.2.0" + version: "2.0.0" flutter: dependency: "direct main" description: flutter @@ -109,26 +109,26 @@ packages: dependency: transitive description: name: leak_tracker - sha256: "6bb818ecbdffe216e81182c2f0714a2e62b593f4a4f13098713ff1685dfb6ab0" + sha256: "33e2e26bdd85a0112ec15400c8cbffea70d0f9c3407491f672a2fad47915e2de" url: "https://pub.dev" source: hosted - version: "10.0.9" + version: "11.0.2" leak_tracker_flutter_testing: dependency: transitive description: name: leak_tracker_flutter_testing - sha256: f8b613e7e6a13ec79cfdc0e97638fddb3ab848452eff057653abd3edba760573 + sha256: "1dbc140bb5a23c75ea9c4811222756104fbcd1a27173f0c34ca01e16bea473c1" url: "https://pub.dev" source: hosted - version: "3.0.9" + version: "3.0.10" leak_tracker_testing: dependency: transitive description: name: leak_tracker_testing - sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3" + sha256: "8d5a2d49f4a66b49744b23b018848400d23e54caf9463f4eb20df3eb8acb2eb1" url: "https://pub.dev" source: hosted - version: "3.0.1" + version: "3.0.2" lints: dependency: transitive description: @@ -213,18 +213,18 @@ packages: dependency: "direct main" description: name: simple_3d - sha256: "16388598cd3b864a1f5c9d9f2869e60dc8181bd08a1da8c4c3deb0991174d90e" + sha256: f40a14daa88f327ec2807403142aa517aee932fee9d37e98ab71eb42abbf4750 url: "https://pub.dev" source: hosted - version: "16.0.1" + version: "16.0.2" simple_3d_renderer: dependency: "direct main" description: name: simple_3d_renderer - sha256: b3f946407b304a85860ed1acd80e11ac2fe142d90caf545896a8f03bc8ae6744 + sha256: bf94f7e90c9a601072921aa2f27baae09d9a531e41bf849225bb2029845a2e2e url: "https://pub.dev" source: hosted - version: "22.0.1" + version: "22.0.2" sky_engine: dependency: transitive description: flutter @@ -282,26 +282,26 @@ packages: dependency: transitive description: name: test_api - sha256: fb31f383e2ee25fbbfe06b40fe21e1e458d14080e3c67e7ba0acfde4df4e0bbd + sha256: "522f00f556e73044315fa4585ec3270f1808a4b186c936e612cab0b565ff1e00" url: "https://pub.dev" source: hosted - version: "0.7.4" + version: "0.7.6" util_simple_3d: dependency: "direct main" description: name: util_simple_3d - sha256: "95e47e4ead200510993feaddd3ff169d067fb1a638e77a0411d1f5d73d39b2c9" + sha256: "2381db1cab8b79e858407a981c3a34016d0514c94bca8f656524d158b970516b" url: "https://pub.dev" source: hosted - version: "12.0.1" + version: "12.0.2" vector_math: dependency: transitive description: name: vector_math - sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" + sha256: d530bd74fea330e6e364cda7a85019c434070188383e1cd8d9777ee586914c5b url: "https://pub.dev" source: hosted - version: "2.1.4" + version: "2.2.0" vm_service: dependency: transitive description: diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 649d005..1fd24be 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -11,7 +11,7 @@ dependencies: flutter_rotation_sensor: path: ../ simple_3d: any - simple_3d_renderer: ^22.0.1 + simple_3d_renderer: ^22.0.2 util_simple_3d: any dev_dependencies: From 1e1132cebbaa31e73e851cf2ce2770e6aa612312 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 10 Oct 2025 02:39:18 +0000 Subject: [PATCH 52/69] chore: bump org.jetbrains.kotlin:kotlin-gradle-plugin from 2.2.0 to 2.2.20 in /android Dependabot couldn't find the original pull request head commit, da439a98cada2b4da29353a2363d9e45bdfdbb0d. --- android/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/android/build.gradle b/android/build.gradle index ed44404..341052c 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -3,7 +3,7 @@ version = "1.0-SNAPSHOT" buildscript { ext.agp_version = '8.11.0' - ext.kotlin_version = '2.2.0' + ext.kotlin_version = '2.2.20' repositories { google() mavenCentral() From a90c6e478e9c9b2830f0e78463544efd9780ff46 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 10 Oct 2025 02:40:30 +0000 Subject: [PATCH 53/69] chore: bump org.jetbrains.kotlin.android from 2.2.0 to 2.2.20 in /example/android Dependabot couldn't find the original pull request head commit, 92c135dec58b681f84c11b5d81239d1e2ac4cba7. --- example/android/settings.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/example/android/settings.gradle.kts b/example/android/settings.gradle.kts index 0604b23..24c72b6 100644 --- a/example/android/settings.gradle.kts +++ b/example/android/settings.gradle.kts @@ -19,7 +19,7 @@ pluginManagement { plugins { id("dev.flutter.flutter-plugin-loader") version "1.0.0" id("com.android.application") version "8.11.0" apply false - id("org.jetbrains.kotlin.android") version "2.2.0" apply false + id("org.jetbrains.kotlin.android") version "2.2.20" apply false } include(":app") From 34ae6462b2f41d71aab325c3229b845d82aee639 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 10 Oct 2025 02:43:13 +0000 Subject: [PATCH 54/69] chore: bump com.android.tools.build:gradle from 8.11.0 to 8.13.0 in /android Dependabot couldn't find the original pull request head commit, 2b82b363c19987d0e6f33a37c121712212a60ce7. --- android/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/android/build.gradle b/android/build.gradle index 341052c..2263e33 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -2,7 +2,7 @@ group = "net.tlserver6y.flutter_rotation_sensor" version = "1.0-SNAPSHOT" buildscript { - ext.agp_version = '8.11.0' + ext.agp_version = '8.13.0' ext.kotlin_version = '2.2.20' repositories { google() From 8f874dcd7e6e64dfb7593ecd95ccc597f7eeb2e4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 10 Oct 2025 02:45:18 +0000 Subject: [PATCH 55/69] chore: bump com.android.application from 8.11.0 to 8.13.0 in /example/android Dependabot couldn't find the original pull request head commit, d3cac45de212ee8d2a4ba891bebdc95bbbbd475e. --- example/android/settings.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/example/android/settings.gradle.kts b/example/android/settings.gradle.kts index 24c72b6..19a97ee 100644 --- a/example/android/settings.gradle.kts +++ b/example/android/settings.gradle.kts @@ -18,7 +18,7 @@ pluginManagement { plugins { id("dev.flutter.flutter-plugin-loader") version "1.0.0" - id("com.android.application") version "8.11.0" apply false + id("com.android.application") version "8.13.0" apply false id("org.jetbrains.kotlin.android") version "2.2.20" apply false } From 69f321a41065fe6caa2492ad43bd8d3344b2f8ff Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 10 Oct 2025 02:46:20 +0000 Subject: [PATCH 56/69] chore: bump org.mockito:mockito-core from 5.18.0 to 5.20.0 in /android Dependabot couldn't find the original pull request head commit, 85c5b23bc9ade0528ffab2939511528197fb0f0e. --- android/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/android/build.gradle b/android/build.gradle index 2263e33..017d899 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -50,7 +50,7 @@ android { dependencies { testImplementation 'org.jetbrains.kotlin:kotlin-test' - testImplementation 'org.mockito:mockito-core:5.18.0' + testImplementation 'org.mockito:mockito-core:5.20.0' } testOptions { From f97ab7fb96df1f3e3c012c57cc338f0c5cdc8839 Mon Sep 17 00:00:00 2001 From: 6y Date: Fri, 10 Oct 2025 11:21:57 +0800 Subject: [PATCH 57/69] chore: ignore one_member_abstracts warning in CoordinateSystem --- lib/src/coordinate_system.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/src/coordinate_system.dart b/lib/src/coordinate_system.dart index 6afefdf..f076dd0 100644 --- a/lib/src/coordinate_system.dart +++ b/lib/src/coordinate_system.dart @@ -8,6 +8,7 @@ import 'orientation_event.dart'; /// An abstract class representing a standard 3-axis right-handed Cartesian /// coordinate system to express orientation data values. +// ignore: one_member_abstracts abstract class CoordinateSystem { const CoordinateSystem(); From afe1110edc2bad007ffd6b592bcdfb1b5eedaba5 Mon Sep 17 00:00:00 2001 From: 6y Date: Fri, 17 Oct 2025 17:57:08 +0800 Subject: [PATCH 58/69] style: format matrix --- lib/src/math/matrix3.dart | 207 ++++++++++++++++++++++++-------------- 1 file changed, 129 insertions(+), 78 deletions(-) diff --git a/lib/src/math/matrix3.dart b/lib/src/math/matrix3.dart index f2c4862..d78234b 100644 --- a/lib/src/math/matrix3.dart +++ b/lib/src/math/matrix3.dart @@ -16,79 +16,108 @@ class Matrix3 { final Float32List _m3Storage; /// Constructs a Matrix3 with the specified elements. + //@formatter:off Matrix3( - double a, - double b, - double c, - double d, - double e, - double f, - double g, - double h, - double i, - ) : _m3Storage = Float32List.fromList([a, b, c, d, e, f, g, h, i]); + double a, double b, double c, + double d, double e, double f, + double g, double h, double i, + ) : _m3Storage = Float32List.fromList([ + a, b, c, + d, e, f, + g, h, i, + ]); + //@formatter:on /// Constructs a Matrix3 from the given row vectors. Matrix3.rows(Vector3 r0, Vector3 r1, Vector3 r2) - : _m3Storage = Float32List.fromList( - [r0.x, r0.y, r0.z, r1.x, r1.y, r1.z, r2.x, r2.y, r2.z], - ); + : _m3Storage = Float32List.fromList([ + r0.x, r0.y, r0.z, + r1.x, r1.y, r1.z, + r2.x, r2.y, r2.z, + ]); /// Constructs a Matrix3 from the given column vectors. Matrix3.columns(Vector3 c0, Vector3 c1, Vector3 c2) - : _m3Storage = Float32List.fromList( - [c0.x, c1.x, c2.x, c0.y, c1.y, c2.y, c0.z, c1.z, c2.z], - ); + : _m3Storage = Float32List.fromList([ + c0.x, c1.x, c2.x, + c0.y, c1.y, c2.y, + c0.z, c1.z, c2.z, + ]); /// Constructs a Matrix3 with all elements initialized to zero. Matrix3.zero() : _m3Storage = Float32List(9); /// Constructs an identity Matrix3. Matrix3.identity() - : _m3Storage = Float32List.fromList([1, 0, 0, 0, 1, 0, 0, 0, 1]); + : _m3Storage = Float32List.fromList([ + 1, 0, 0, + 0, 1, 0, + 0, 0, 1, + ]); /// Constructs a rotation matrix around the X-axis. factory Matrix3.rotateX(double r) { final cr = cos(r); final sr = sin(r); - return Matrix3(1, 0, 0, 0, cr, -sr, 0, sr, cr); + return Matrix3( + //@formatter:off + 1, 0, 0, + 0, cr, -sr, + 0, sr, cr, + //@formatter:on + ); } /// Constructs a rotation matrix around the Y-axis. factory Matrix3.rotateY(double r) { final cr = cos(r); final sr = sin(r); - return Matrix3(cr, 0, sr, 0, 1, 0, -sr, 0, cr); + return Matrix3( + //@formatter:off + cr, 0, sr, + 0, 1, 0, + -sr, 0, cr, + //@formatter:on + ); } /// Constructs a rotation matrix around the Z-axis. factory Matrix3.rotateZ(double r) { final cr = cos(r); final sr = sin(r); - return Matrix3(cr, -sr, 0, sr, cr, 0, 0, 0, 1); + return Matrix3( + //@formatter:off + cr, -sr, 0, + sr, cr, 0, + 0, 0, 1, + //@formatter:on + ); } /// Determines whether this matrix is equal to another object. Returns true /// if the other object is an Matrix3 with the same elements. @override bool operator ==(Object other) => - identical(this, other) || - other is Matrix3 && - a == other.a && - b == other.b && - c == other.c && - d == other.d && - e == other.e && - f == other.f && - g == other.g && - h == other.h && - i == other.i; + identical(this, other) || other is Matrix3 && + a == other.a && b == other.b && c == other.c && + d == other.d && e == other.e && f == other.f && + g == other.g && h == other.h && i == other.i; @override - int get hashCode => Object.hash(a, b, c, d, e, f, g, h, i); + int get hashCode => + Object.hash( + //@formatter:off + a, b, c, + d, e, f, + g, h, i, + //@formatter:on + ); @override - String toString() => '⌈$a,$b,$c⌉\n|$d,$e,$f|\n⌊$g,$h,$i⌋\n'; + String toString() => '' + '⌈$a,$b,$c⌉\n' + '|$d,$e,$f|\n' + '⌊$g,$h,$i⌋\n'; /// Returns the element at the first row and first column. double get a => _m3Storage[0]; @@ -130,50 +159,66 @@ class Matrix3 { Vector3 column(int c) => Vector3(this[0 + c], this[3 + c], this[6 + c]); /// Returns the negation of this matrix. - Matrix3 operator -() => Matrix3(-a, -b, -c, -d, -e, -f, -g, -h, -i); + Matrix3 operator -() => + Matrix3( + //@formatter:off + -a, -b, -c, + -d, -e, -f, + -g, -h, -i, + //@formatter:on + ); /// Adds the given matrix to this matrix. - Matrix3 operator +(Matrix3 o) => Matrix3( - a + o.a, - b + o.b, - c + o.c, - d + o.d, - e + o.e, - f + o.f, - g + o.g, - h + o.h, - i + o.i, + Matrix3 operator +(Matrix3 o) => + Matrix3( + //@formatter:off + a + o.a, b + o.b, c + o.c, + d + o.d, e + o.e, f + o.f, + g + o.g, h + o.h, i + o.i, + //@formatter:on ); /// Subtracts the given matrix from this matrix. - Matrix3 operator -(Matrix3 o) => Matrix3( - a - o.a, - b - o.b, - c - o.c, - d - o.d, - e - o.e, - f - o.f, - g - o.g, - h - o.h, - i - o.i, + Matrix3 operator -(Matrix3 o) => + Matrix3( + //@formatter:off + a - o.a, b - o.b, c - o.c, + d - o.d, e - o.e, f - o.f, + g - o.g, h - o.h, i - o.i, + //@formatter:on ); /// Multiplies this matrix by the given scalar. Matrix3 operator *(double s) => - Matrix3(a * s, b * s, c * s, d * s, e * s, f * s, g * s, h * s, i * s); + Matrix3( + //@formatter:off + a * s, b * s, c * s, + d * s, e * s, f * s, + g * s, h * s, i * s, + //@formatter:on + ); /// Divides this matrix by the given scalar. Matrix3 operator /(double s) => - Matrix3(a / s, b / s, c / s, d / s, e / s, f / s, g / s, h / s, i / s); + Matrix3( + //@formatter:off + a / s, b / s, c / s, + d / s, e / s, f / s, + g / s, h / s, i / s, + //@formatter:on + ); /// Multiplies this matrix by the given matrix. - Matrix3 multiply(Matrix3 o) => Matrix3( + Matrix3 multiply(Matrix3 o) => + Matrix3( a * o.a + b * o.d + c * o.g, a * o.b + b * o.e + c * o.h, a * o.c + b * o.f + c * o.i, + d * o.a + e * o.d + f * o.g, d * o.b + e * o.e + f * o.h, d * o.c + e * o.f + f * o.i, + g * o.a + h * o.d + i * o.g, g * o.b + h * o.e + i * o.h, g * o.c + h * o.f + i * o.i, @@ -187,19 +232,23 @@ class Matrix3 { a * e * i + b * f * g + c * d * h - a * f * h - b * d * i - c * e * g; /// Returns the transpose of this matrix. - Matrix3 transpose() => Matrix3(a, d, g, b, e, h, c, f, i); + Matrix3 transpose() => + Matrix3( + //@formatter:off + a, d, g, + b, e, h, + c, f, i, + //@formatter:on + ); /// Returns the adjoint of this matrix. - Matrix3 adjoint() => Matrix3( - e * i - f * h, - c * h - b * i, - b * f - c * e, - f * g - d * i, - a * i - c * g, - c * d - a * f, - d * h - e * g, - b * g - a * h, - a * e - b * d, + Matrix3 adjoint() => + Matrix3( + //@formatter:off + e * i - f * h, c * h - b * i, b * f - c * e, + f * g - d * i, a * i - c * g, c * d - a * f, + d * h - e * g, b * g - a * h, a * e - b * d, + //@formatter:on ); /// Returns the inverse of this matrix. @@ -210,22 +259,24 @@ class Matrix3 { return this; } else { return Matrix3( - (e * i - f * h) / t, - (c * h - b * i) / t, - (b * f - c * e) / t, - (f * g - d * i) / t, - (a * i - c * g) / t, - (c * d - a * f) / t, - (d * h - e * g) / t, - (b * g - a * h) / t, - (a * e - b * d) / t, + //@formatter:off + (e * i - f * h) / t, (c * h - b * i) / t, (b * f - c * e) / t, + (f * g - d * i) / t, (a * i - c * g) / t, (c * d - a * f) / t, + (d * h - e * g) / t, (b * g - a * h) / t, (a * e - b * d) / t, + //@formatter:on ); } } /// Applies the given function to each element of the matrix. Matrix3 apply(double Function(double) t) => - Matrix3(t(a), t(b), t(c), t(d), t(e), t(f), t(g), t(h), t(i)); + Matrix3( + //@formatter:off + t(a), t(b), t(c), + t(d), t(e), t(f), + t(g), t(h), t(i), + //@formatter:on + ); /// Converts this matrix to Euler angles. EulerAngles toEulerAngles() { From d5adcabd1f2e141365d41a38fc9454fa5e772573 Mon Sep 17 00:00:00 2001 From: 6y Date: Fri, 17 Oct 2025 17:57:32 +0800 Subject: [PATCH 59/69] style: dart fmt --- lib/src/coordinate_system.dart | 6 +++--- lib/src/math/quaternion.dart | 12 ++++++------ lib/src/math/vector3.dart | 2 +- lib/src/orientation_event.dart | 3 ++- lib/src/rotation_sensor_method_channel.dart | 5 ++--- 5 files changed, 14 insertions(+), 14 deletions(-) diff --git a/lib/src/coordinate_system.dart b/lib/src/coordinate_system.dart index f076dd0..1a30bf5 100644 --- a/lib/src/coordinate_system.dart +++ b/lib/src/coordinate_system.dart @@ -69,8 +69,8 @@ class DisplayCoordinateSystem extends CoordinateSystem { _communicator = value; _orientationStreamSubscription?.cancel(); _orientationStreamSubscription = value.onOrientationChanged().listen( - (o) => orientation = o, - ); + (o) => orientation = o, + ); } StreamSubscription? _orientationStreamSubscription; @@ -120,7 +120,7 @@ class TransformedCoordinateSystem extends CoordinateSystem { final Axis3 newY; TransformedCoordinateSystem(this.newX, this.newY, [CoordinateSystem? base]) - : base = base ?? CoordinateSystem.display(); + : base = base ?? CoordinateSystem.display(); @override OrientationEvent apply(OrientationEvent event) { diff --git a/lib/src/math/quaternion.dart b/lib/src/math/quaternion.dart index 8c9d56e..633678b 100644 --- a/lib/src/math/quaternion.dart +++ b/lib/src/math/quaternion.dart @@ -22,7 +22,7 @@ class Quaternion { /// Constructs a Quaternion with given x, y, z, w components Quaternion(double x, double y, double z, double w) - : _qStorage = Float32List.fromList([x, y, z, w]); + : _qStorage = Float32List.fromList([x, y, z, w]); /// constructs an identity Quaternion (0, 0, 0, 1) factory Quaternion.identity() => Quaternion(0, 0, 0, 1); @@ -76,11 +76,11 @@ class Quaternion { /// Computes the Hamilton product of this quaternion with another /// [Quaternion]. Quaternion multiply(Quaternion o) => Quaternion( - w * o.x + x * o.w + y * o.z - z * o.y, - w * o.y + y * o.w + z * o.x - x * o.z, - w * o.z + z * o.w + x * o.y - y * o.x, - w * o.w - x * o.x - y * o.y - z * o.z, - ); + w * o.x + x * o.w + y * o.z - z * o.y, + w * o.y + y * o.w + z * o.x - x * o.z, + w * o.z + z * o.w + x * o.y - y * o.x, + w * o.w - x * o.x - y * o.y - z * o.z, + ); /// The squared length of this quaternion. double get length2 => x * x + y * y + z * z + w * w; diff --git a/lib/src/math/vector3.dart b/lib/src/math/vector3.dart index 5fbe4c9..7ed770a 100644 --- a/lib/src/math/vector3.dart +++ b/lib/src/math/vector3.dart @@ -11,7 +11,7 @@ class Vector3 { /// Constructs a [Vector3] with the given [x], [y], and [z] components. Vector3(double x, double y, double z) - : _v3Storage = Float32List.fromList([x, y, z]); + : _v3Storage = Float32List.fromList([x, y, z]); /// Constructs a [Vector3] initialized to zero (0, 0, 0). Vector3.zero() : _v3Storage = Float32List(3); diff --git a/lib/src/orientation_event.dart b/lib/src/orientation_event.dart index 5668c4f..225e09b 100644 --- a/lib/src/orientation_event.dart +++ b/lib/src/orientation_event.dart @@ -63,7 +63,8 @@ class OrientationEvent { ); @override - String toString() => 'OrientationEvent(\n' + String toString() => + 'OrientationEvent(\n' 'quaternion: $quaternion,\n' 'accuracy: $accuracy,\n' 'timestamp: $timestamp,\n' diff --git a/lib/src/rotation_sensor_method_channel.dart b/lib/src/rotation_sensor_method_channel.dart index d90a4b1..f59b167 100644 --- a/lib/src/rotation_sensor_method_channel.dart +++ b/lib/src/rotation_sensor_method_channel.dart @@ -1,5 +1,4 @@ import 'package:flutter/foundation.dart'; -import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'math/quaternion.dart'; @@ -29,8 +28,8 @@ class MethodChannelRotationSensor extends RotationSensorPlatform { methodChannel.invokeMethod('getOrientationStream', { 'samplingPeriod': samplingMicroseconds, }); - return _orientationStream = - eventChannel.receiveBroadcastStream().map((event) { + final broadcastStream = eventChannel.receiveBroadcastStream(); + return _orientationStream = broadcastStream.map((event) { final data = event as List; final orientationEvent = OrientationEvent( quaternion: Quaternion(data[0], data[1], data[2], data[3]), From 456c774d305ad3a8888f1a803f612724eaa38cbf Mon Sep 17 00:00:00 2001 From: 6y Date: Mon, 20 Oct 2025 15:26:14 +0800 Subject: [PATCH 60/69] feat: add an indicator for platform support Displays whether the current platform (e.g., Android/iOS) supports rotation sensing. --- lib/src/coordinate_system.dart | 28 ++-- lib/src/environment.dart | 5 + lib/src/rotation_sensor.dart | 14 +- lib/src/rotation_sensor_method_channel.dart | 17 ++- ...ace.dart => rotation_sensor_platform.dart} | 33 +++-- lib/src/rotation_sensor_unsupported.dart | 21 +++ test/coordinate_system_test.dart | 132 ++++++++---------- test/rotation_sensor_method_channel_test.dart | 69 ++++----- test/rotation_sensor_platform_test.dart | 45 ++++++ test/rotation_sensor_test.dart | 23 +-- test/rotation_sensor_unsupported_test.dart | 12 ++ 11 files changed, 246 insertions(+), 153 deletions(-) create mode 100644 lib/src/environment.dart rename lib/src/{rotation_sensor_platform_interface.dart => rotation_sensor_platform.dart} (77%) create mode 100644 lib/src/rotation_sensor_unsupported.dart create mode 100644 test/rotation_sensor_platform_test.dart create mode 100644 test/rotation_sensor_unsupported_test.dart diff --git a/lib/src/coordinate_system.dart b/lib/src/coordinate_system.dart index 1a30bf5..50fdb2f 100644 --- a/lib/src/coordinate_system.dart +++ b/lib/src/coordinate_system.dart @@ -1,8 +1,9 @@ import 'dart:async'; -import 'package:meta/meta.dart'; +import 'package:flutter/foundation.dart'; import 'package:native_device_orientation/native_device_orientation.dart'; +import 'environment.dart'; import 'math/axis3.dart'; import 'orientation_event.dart'; @@ -39,9 +40,9 @@ abstract class CoordinateSystem { /// - Z axis: Points toward the outside of the screen. Coordinates behind the /// screen have negative Z values. class DeviceCoordinateSystem extends CoordinateSystem { - static const DeviceCoordinateSystem instance = DeviceCoordinateSystem._(); + static DeviceCoordinateSystem? _instance; - factory DeviceCoordinateSystem() => instance; + factory DeviceCoordinateSystem() => _instance ??= DeviceCoordinateSystem._(); const DeviceCoordinateSystem._(); @@ -57,18 +58,18 @@ class DeviceCoordinateSystem extends CoordinateSystem { /// - Z axis: Points toward the outside of the screen. Coordinates behind the /// screen have negative Z values. class DisplayCoordinateSystem extends CoordinateSystem { - static final DisplayCoordinateSystem instance = DisplayCoordinateSystem._(); + static DisplayCoordinateSystem? _instance; - late NativeDeviceOrientationCommunicator _communicator; + NativeDeviceOrientationCommunicator? _communicator; @visibleForTesting - NativeDeviceOrientationCommunicator get communicator => _communicator; + NativeDeviceOrientationCommunicator? get communicator => _communicator; @visibleForTesting - set communicator(NativeDeviceOrientationCommunicator value) { + set communicator(NativeDeviceOrientationCommunicator? value) { _communicator = value; _orientationStreamSubscription?.cancel(); - _orientationStreamSubscription = value.onOrientationChanged().listen( + _orientationStreamSubscription = value?.onOrientationChanged().listen( (o) => orientation = o, ); } @@ -78,10 +79,17 @@ class DisplayCoordinateSystem extends CoordinateSystem { @visibleForTesting NativeDeviceOrientation orientation = NativeDeviceOrientation.portraitUp; - factory DisplayCoordinateSystem() => instance; + factory DisplayCoordinateSystem() => + _instance ??= DisplayCoordinateSystem._(); DisplayCoordinateSystem._() { - communicator = NativeDeviceOrientationCommunicator(); + if (!isWeb && + [ + TargetPlatform.android, + TargetPlatform.iOS, + ].contains(defaultTargetPlatform)) { + communicator = NativeDeviceOrientationCommunicator(); + } } @override diff --git a/lib/src/environment.dart b/lib/src/environment.dart new file mode 100644 index 0000000..2e9ee5f --- /dev/null +++ b/lib/src/environment.dart @@ -0,0 +1,5 @@ +import 'package:flutter/foundation.dart'; + +/// A boolean that is true if the application was compiled to run on the web. +/// Can be overridden in tests. +bool isWeb = kIsWeb; diff --git a/lib/src/rotation_sensor.dart b/lib/src/rotation_sensor.dart index ad948aa..0d0345c 100644 --- a/lib/src/rotation_sensor.dart +++ b/lib/src/rotation_sensor.dart @@ -2,7 +2,8 @@ import 'package:meta/meta.dart'; import 'coordinate_system.dart'; import 'orientation_event.dart'; -import 'rotation_sensor_platform_interface.dart'; +import 'rotation_sensor_method_channel.dart'; +import 'rotation_sensor_platform.dart'; import 'sensor_interval.dart'; /// Provides access to the device's rotation sensor, offering a real-time stream @@ -13,8 +14,9 @@ import 'sensor_interval.dart'; /// quaternion, and Euler angles (azimuth, pitch, roll). @sealed class RotationSensor { - @visibleForTesting - static RotationSensorPlatform platform = RotationSensorPlatform.instance; + /// Determines whether the current platform is supported. + static bool get isPlatformSupported => + RotationSensorMethodChannel.isPlatformSupported; /// A broadcast [Stream] of [OrientationEvent]s which emits events containing /// the orientation of the device from the device's rotation sensor. @@ -41,9 +43,5 @@ class RotationSensor { /// Defaults to [DisplayCoordinateSystem]. When changing this value, all /// existing listeners will receive [OrientationEvent] in the new coordinate /// system. - static CoordinateSystem get coordinateSystem => - RotationSensorPlatform.instance.coordinateSystem; - - static set coordinateSystem(CoordinateSystem value) => - RotationSensorPlatform.instance.coordinateSystem = value; + static CoordinateSystem coordinateSystem = DisplayCoordinateSystem(); } diff --git a/lib/src/rotation_sensor_method_channel.dart b/lib/src/rotation_sensor_method_channel.dart index f59b167..173a446 100644 --- a/lib/src/rotation_sensor_method_channel.dart +++ b/lib/src/rotation_sensor_method_channel.dart @@ -1,12 +1,15 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/services.dart'; +import 'environment.dart'; import 'math/quaternion.dart'; import 'orientation_event.dart'; -import 'rotation_sensor_platform_interface.dart'; +import 'rotation_sensor.dart'; +import 'rotation_sensor_platform.dart'; /// An implementation of [RotationSensorPlatform] that uses method channels. -class MethodChannelRotationSensor extends RotationSensorPlatform { +class RotationSensorMethodChannel extends RotationSensorPlatform { + /// The method channel used to interact with the native platform. @visibleForTesting static const methodChannel = MethodChannel('rotation_sensor/method'); @@ -16,6 +19,14 @@ class MethodChannelRotationSensor extends RotationSensorPlatform { @visibleForTesting static const eventChannel = EventChannel('rotation_sensor/orientation'); + /// Determines whether the current platform is supported. + static bool get isPlatformSupported => + !isWeb && + [ + TargetPlatform.android, + TargetPlatform.iOS, + ].contains(defaultTargetPlatform); + Stream? _orientationStream; /// A broadcast [Stream] of [OrientationEvent]s which emits events containing @@ -36,7 +47,7 @@ class MethodChannelRotationSensor extends RotationSensorPlatform { accuracy: data[4], timestamp: data[5], ); - return coordinateSystem.apply(orientationEvent); + return RotationSensor.coordinateSystem.apply(orientationEvent); }); } diff --git a/lib/src/rotation_sensor_platform_interface.dart b/lib/src/rotation_sensor_platform.dart similarity index 77% rename from lib/src/rotation_sensor_platform_interface.dart rename to lib/src/rotation_sensor_platform.dart index aeb337b..cbc208e 100644 --- a/lib/src/rotation_sensor_platform_interface.dart +++ b/lib/src/rotation_sensor_platform.dart @@ -2,29 +2,43 @@ import 'package:logging/logging.dart'; import 'package:meta/meta.dart'; import 'package:plugin_platform_interface/plugin_platform_interface.dart'; -import 'coordinate_system.dart'; import 'orientation_event.dart'; import 'rotation_sensor_method_channel.dart'; +import 'rotation_sensor_unsupported.dart'; import 'sensor_interval.dart'; /// The interface that implementations of rotation_sensor must implement. abstract class RotationSensorPlatform extends PlatformInterface { /// Constructs a RotationSensorPlatform. - RotationSensorPlatform() : super(token: _token); + RotationSensorPlatform() : super(token: _token) { + logger = Logger(runtimeType.toString()); + } static final Object _token = Object(); - /// The default instance of [RotationSensorPlatform] to use. - static RotationSensorPlatform _instance = MethodChannelRotationSensor(); + /// The [RotationSensorPlatform] for current platform. + static RotationSensorPlatform? _instance; - static RotationSensorPlatform get instance => _instance; + static RotationSensorPlatform get instance { + if (_instance != null) return _instance!; + return createPlatformInstance(); + } static set instance(RotationSensorPlatform instance) { PlatformInterface.verifyToken(instance, _token); _instance = instance; } - final logger = Logger('MethodChannelRotationSensor'); + @visibleForTesting + static RotationSensorPlatform createPlatformInstance() { + if (RotationSensorMethodChannel.isPlatformSupported) { + return instance = RotationSensorMethodChannel(); + } + return instance = RotationSensorUnsupported(); + } + + @protected + late final Logger logger; /// A broadcast [Stream] of [OrientationEvent]s which emits events containing /// the orientation of the device from the device's rotation sensor. @@ -61,13 +75,6 @@ abstract class RotationSensorPlatform extends PlatformInterface { updateSamplingPeriod(samplingMicroseconds); } - /// The [coordinateSystem] used for upcoming [OrientationEvent]. - /// - /// Defaults to [DisplayCoordinateSystem]. When changing this value, all - /// existing listeners will receive [OrientationEvent] in the new coordinate - /// system. - CoordinateSystem coordinateSystem = CoordinateSystem.display(); - @protected void updateSamplingPeriod(int value) { // no-op diff --git a/lib/src/rotation_sensor_unsupported.dart b/lib/src/rotation_sensor_unsupported.dart new file mode 100644 index 0000000..d0ee2f6 --- /dev/null +++ b/lib/src/rotation_sensor_unsupported.dart @@ -0,0 +1,21 @@ +import 'package:flutter/foundation.dart'; + +import 'environment.dart'; +import 'orientation_event.dart'; +import 'rotation_sensor_platform.dart'; + +/// A placeholder implementation of [RotationSensorPlatform] for unsupported +/// platforms. Used as a fallback to indicate that device rotation sensing is +/// not available. +class RotationSensorUnsupported extends RotationSensorPlatform { + /// Throws an [UnsupportedError] indicating that the rotation sensor is not + /// supported on the current platform. This getter does not return a + /// functional stream. + @override + Stream get orientationStream { + final platform = isWeb ? 'web' : defaultTargetPlatform.name; + throw UnsupportedError( + 'FlutterRotationSensor does not support the $platform platform.', + ); + } +} diff --git a/test/coordinate_system_test.dart b/test/coordinate_system_test.dart index 3eb8643..339dc97 100644 --- a/test/coordinate_system_test.dart +++ b/test/coordinate_system_test.dart @@ -13,11 +13,11 @@ import 'coordinate_system_test.mocks.dart'; void main() { TestWidgetsFlutterBinding.ensureInitialized(); - final platform = MethodChannelRotationSensor(); + final platform = RotationSensorMethodChannel(); final binaryMessenger = TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger; - const methodChannel = MethodChannelRotationSensor.methodChannel; - const orientationChannel = MethodChannelRotationSensor.eventChannel; + const methodChannel = RotationSensorMethodChannel.methodChannel; + const orientationChannel = RotationSensorMethodChannel.eventChannel; // ignore: close_sinks late StreamController oeStreamController; late int expectedSamplingPeriod; @@ -26,34 +26,32 @@ void main() { oeStreamController = StreamController(); expectedSamplingPeriod = platform.samplingPeriod.inMicroseconds; binaryMessenger - ..setMockMethodCallHandler( - methodChannel, - (methodCall) async { - switch (methodCall.method) { - case 'getOrientationStream': - final arguments = methodCall.arguments as Map; - final samplingPeriod = arguments['samplingPeriod'] as int; - expect(samplingPeriod, expectedSamplingPeriod); - return null; - default: - throw UnsupportedError(methodCall.method); - } - }, - ) + ..setMockMethodCallHandler(methodChannel, (methodCall) async { + switch (methodCall.method) { + case 'getOrientationStream': + final arguments = methodCall.arguments as Map; + final samplingPeriod = arguments['samplingPeriod'] as int; + expect(samplingPeriod, expectedSamplingPeriod); + return null; + default: + throw UnsupportedError(methodCall.method); + } + }) ..setMockStreamHandler( orientationChannel, MockStreamHandler.inline( - onListen: (args, sink) => oeStreamController.stream.listen( - (_) => sink.success([ - // Quaternion - 0.0, 0.0, 0.0, 1.0, - // Accuracy - -1.0, - // Timestamp - 123456789, - ]), - onDone: () => sink.endOfStream(), - ), + onListen: + (args, sink) => oeStreamController.stream.listen( + (_) => sink.success([ + // Quaternion + 0.0, 0.0, 0.0, 1.0, + // Accuracy + -1.0, + // Timestamp + 123456789, + ]), + onDone: () => sink.endOfStream(), + ), ), ); }); @@ -68,13 +66,10 @@ void main() { test( 'orientationStream emit OrientationEvent in device coordinate system', () async { - platform.coordinateSystem = CoordinateSystem.device(); + RotationSensor.coordinateSystem = CoordinateSystem.device(); oeStreamController.sink.add(null); final orientationEvent = await platform.orientationStream.first; - expect( - orientationEvent.coordinateSystem, - equals(Matrix3.identity()), - ); + expect(orientationEvent.coordinateSystem, equals(Matrix3.identity())); }, ); @@ -82,13 +77,13 @@ void main() { 'orientationStream emit OrientationEvent in display coordinate system', () async { final displayCoordinateSystem = DisplayCoordinateSystem(); - platform.coordinateSystem = displayCoordinateSystem; + RotationSensor.coordinateSystem = displayCoordinateSystem; final ndoStreamController = StreamController.broadcast(); final mockCommunicator = MockNativeDeviceOrientationCommunicator(); - when(mockCommunicator.onOrientationChanged()).thenAnswer( - (_) => ndoStreamController.stream, - ); + when( + mockCommunicator.onOrientationChanged(), + ).thenAnswer((_) => ndoStreamController.stream); displayCoordinateSystem.communicator = mockCommunicator; expect(displayCoordinateSystem.communicator, equals(mockCommunicator)); @@ -109,9 +104,11 @@ void main() { } final orientationEvents = await orientationEventsFuture; - for (var t = 0, e = Matrix3.identity(); - t < orientationEvents.length; - t++, e = e.multiply(Matrix3(0, -1, 0, 1, 0, 0, 0, 0, 1))) { + for ( + var t = 0, e = Matrix3.identity(); + t < orientationEvents.length; + t++, e = e.multiply(Matrix3(0, -1, 0, 1, 0, 0, 0, 0, 1)) + ) { final orientationEvent = orientationEvents[t]; expect( orientationEvent.coordinateSystem, @@ -125,44 +122,35 @@ void main() { }, ); - test( - 'orientationStream emit error in display coordinate system', - () async { - final displayCoordinateSystem = DisplayCoordinateSystem(); - platform.coordinateSystem = displayCoordinateSystem; - final ndoStreamController = - StreamController.broadcast(); - final mockCommunicator = MockNativeDeviceOrientationCommunicator(); - when(mockCommunicator.onOrientationChanged()).thenAnswer( - (_) => ndoStreamController.stream, - ); - displayCoordinateSystem.communicator = mockCommunicator; - expect(displayCoordinateSystem.communicator, equals(mockCommunicator)); - - ndoStreamController.sink.add(NativeDeviceOrientation.unknown); - await Future.delayed(const Duration(microseconds: 1), () {}); - oeStreamController.sink.add(null); - await Future.delayed(const Duration(microseconds: 1), () {}); - await expectLater( - () => platform.orientationStream.first, - throwsStateError, - ); - - ndoStreamController.sink.add(NativeDeviceOrientation.portraitUp); - await ndoStreamController.close(); - }, - ); + test('orientationStream emit error in display coordinate system', () async { + final displayCoordinateSystem = DisplayCoordinateSystem(); + RotationSensor.coordinateSystem = displayCoordinateSystem; + final ndoStreamController = + StreamController.broadcast(); + final mockCommunicator = MockNativeDeviceOrientationCommunicator(); + when( + mockCommunicator.onOrientationChanged(), + ).thenAnswer((_) => ndoStreamController.stream); + displayCoordinateSystem.communicator = mockCommunicator; + expect(displayCoordinateSystem.communicator, equals(mockCommunicator)); + + ndoStreamController.sink.add(NativeDeviceOrientation.unknown); + await Future.delayed(const Duration(microseconds: 1), () {}); + oeStreamController.sink.add(null); + await Future.delayed(const Duration(microseconds: 1), () {}); + await expectLater(() => platform.orientationStream.first, throwsStateError); + + ndoStreamController.sink.add(NativeDeviceOrientation.portraitUp); + await ndoStreamController.close(); + }); test( 'orientationStream emit OrientationEvent in transformed coordinate system', () async { - platform.coordinateSystem = CoordinateSystem.transformed( + RotationSensor.coordinateSystem = CoordinateSystem.transformed( Axis3.X, Axis3.Z, - CoordinateSystem.transformed( - Axis3.X, - Axis3.Y, - ), + CoordinateSystem.transformed(Axis3.X, Axis3.Y), ); oeStreamController.sink.add(null); final orientationEvent = await platform.orientationStream.first; diff --git a/test/rotation_sensor_method_channel_test.dart b/test/rotation_sensor_method_channel_test.dart index b886c09..78cbe30 100644 --- a/test/rotation_sensor_method_channel_test.dart +++ b/test/rotation_sensor_method_channel_test.dart @@ -5,44 +5,41 @@ import 'package:flutter_test/flutter_test.dart'; void main() { TestWidgetsFlutterBinding.ensureInitialized(); - final platform = MethodChannelRotationSensor(); - const methodChannel = MethodChannelRotationSensor.methodChannel; - const orientationChannel = MethodChannelRotationSensor.eventChannel; + final platform = RotationSensorMethodChannel(); + const methodChannel = RotationSensorMethodChannel.methodChannel; + const orientationChannel = RotationSensorMethodChannel.eventChannel; late int expectedSamplingPeriod; setUp(() { expectedSamplingPeriod = platform.samplingPeriod.inMicroseconds; TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger - .setMockMethodCallHandler( - methodChannel, - (methodCall) async { - switch (methodCall.method) { - case 'getOrientationStream': - final arguments = methodCall.arguments as Map; - final samplingPeriod = arguments['samplingPeriod'] as int; - expect(samplingPeriod, expectedSamplingPeriod); - return null; - default: - throw UnsupportedError(methodCall.method); - } - }, - ); + .setMockMethodCallHandler(methodChannel, (methodCall) async { + switch (methodCall.method) { + case 'getOrientationStream': + final arguments = methodCall.arguments as Map; + final samplingPeriod = arguments['samplingPeriod'] as int; + expect(samplingPeriod, expectedSamplingPeriod); + return null; + default: + throw UnsupportedError(methodCall.method); + } + }); TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger .setMockStreamHandler( - orientationChannel, - MockStreamHandler.inline( - onListen: (args, sink) { - sink.success([ - // Quaternion - 0.0, 0.0, 0.0, 1.0, - // Accuracy - -1.0, - // Timestamp - 123456789, - ]); - }, - ), - ); + orientationChannel, + MockStreamHandler.inline( + onListen: (args, sink) { + sink.success([ + // Quaternion + 0.0, 0.0, 0.0, 1.0, + // Accuracy + -1.0, + // Timestamp + 123456789, + ]); + }, + ), + ); }); tearDown(() { @@ -55,10 +52,7 @@ void main() { test( 'orientationStream emits OrientationEvent with default sampling period', () async { - expect( - await platform.orientationStream.first, - isA(), - ); + expect(await platform.orientationStream.first, isA()); }, ); @@ -72,10 +66,7 @@ void main() { platform.samplingPeriod = const Duration(microseconds: 1); expect(platform.samplingPeriod, equals(Duration.zero)); await Future.microtask(() => null); - expect( - await platform.orientationStream.first, - isA(), - ); + expect(await platform.orientationStream.first, isA()); }, ); } diff --git a/test/rotation_sensor_platform_test.dart b/test/rotation_sensor_platform_test.dart new file mode 100644 index 0000000..263a4ff --- /dev/null +++ b/test/rotation_sensor_platform_test.dart @@ -0,0 +1,45 @@ +import 'package:flutter/foundation.dart'; +import 'package:flutter_rotation_sensor/src/environment.dart'; +import 'package:flutter_rotation_sensor/src/rotation_sensor_method_channel.dart'; +import 'package:flutter_rotation_sensor/src/rotation_sensor_platform.dart'; +import 'package:flutter_rotation_sensor/src/rotation_sensor_unsupported.dart'; +import 'package:flutter_test/flutter_test.dart'; + +const webImplementation = RotationSensorUnsupported; + +const implementations = { + TargetPlatform.android: RotationSensorMethodChannel, + TargetPlatform.iOS: RotationSensorMethodChannel, + TargetPlatform.fuchsia: RotationSensorUnsupported, + TargetPlatform.linux: RotationSensorUnsupported, + TargetPlatform.macOS: RotationSensorUnsupported, + TargetPlatform.windows: RotationSensorUnsupported, +}; + +void main() { + test('instance returns the implementation for current platform', () { + expect( + RotationSensorPlatform.instance.runtimeType, + equals(implementations[defaultTargetPlatform]), + ); + }); + + test('$webImplementation is used on web platform', () { + isWeb = true; + expect( + RotationSensorPlatform.createPlatformInstance().runtimeType, + equals(webImplementation), + ); + }); + + implementations.forEach((platform, implementation) { + test('$implementation is used on ${platform.name} platform', () { + isWeb = false; + debugDefaultTargetPlatformOverride = platform; + expect( + RotationSensorPlatform.createPlatformInstance().runtimeType, + equals(implementation), + ); + }); + }); +} diff --git a/test/rotation_sensor_test.dart b/test/rotation_sensor_test.dart index f114ef3..310f5aa 100644 --- a/test/rotation_sensor_test.dart +++ b/test/rotation_sensor_test.dart @@ -1,7 +1,8 @@ +import 'package:flutter/foundation.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_rotation_sensor/flutter_rotation_sensor.dart'; -import 'package:flutter_rotation_sensor/src/rotation_sensor_method_channel.dart'; -import 'package:flutter_rotation_sensor/src/rotation_sensor_platform_interface.dart'; +import 'package:flutter_rotation_sensor/src/environment.dart'; +import 'package:flutter_rotation_sensor/src/rotation_sensor_platform.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:plugin_platform_interface/plugin_platform_interface.dart'; @@ -21,14 +22,20 @@ class MockRotationSensorPlatform extends RotationSensorPlatform void main() { WidgetsFlutterBinding.ensureInitialized(); - final initialPlatform = RotationSensorPlatform.instance; - - test('MethodChannelRotationSensor is the default instance', () { - expect(initialPlatform, isInstanceOf()); + test('isPlatformSupported returns true only for Android and iOS platforms', () { + isWeb = false; + for (final platform in TargetPlatform.values) { + debugDefaultTargetPlatformOverride = platform; + expect(RotationSensor.isPlatformSupported, equals([ + TargetPlatform.android, + TargetPlatform.iOS, + ].contains(platform))); + } }); - test('platform is default MethodChannelRotationSensor', () { - expect(RotationSensor.platform, same(initialPlatform)); + test('isPlatformSupported returns false for web platform', () { + isWeb = true; + expect(RotationSensor.isPlatformSupported, isFalse); }); test('orientationStream returns a stream of orientation events', () async { diff --git a/test/rotation_sensor_unsupported_test.dart b/test/rotation_sensor_unsupported_test.dart new file mode 100644 index 0000000..2a9354f --- /dev/null +++ b/test/rotation_sensor_unsupported_test.dart @@ -0,0 +1,12 @@ +import 'package:flutter_rotation_sensor/src/rotation_sensor_unsupported.dart'; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + TestWidgetsFlutterBinding.ensureInitialized(); + + final platform = RotationSensorUnsupported(); + + test('orientationStream', () async { + expect(() => platform.orientationStream.first, throwsUnsupportedError); + }); +} From 74742b6ac1363804e142fc2df238f2a4624b4065 Mon Sep 17 00:00:00 2001 From: 6y Date: Mon, 20 Oct 2025 15:37:26 +0800 Subject: [PATCH 61/69] chore: bump gradle from 8.10.2 to 9.1.0 in /example/android --- example/android/gradle/wrapper/gradle-wrapper.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/example/android/gradle/wrapper/gradle-wrapper.properties b/example/android/gradle/wrapper/gradle-wrapper.properties index afa1e8e..2d428bf 100644 --- a/example/android/gradle/wrapper/gradle-wrapper.properties +++ b/example/android/gradle/wrapper/gradle-wrapper.properties @@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.1.0-all.zip From 9808e47b2dd8b4ff6fa8a42df3e4198b0869148b Mon Sep 17 00:00:00 2001 From: 6y Date: Mon, 20 Oct 2025 16:00:59 +0800 Subject: [PATCH 62/69] chore: bump dart from 3.7.2 to 3.8.0 in /example/android --- example/pubspec.lock | 2 +- example/pubspec.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/example/pubspec.lock b/example/pubspec.lock index bc313c5..de87cb2 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -319,5 +319,5 @@ packages: source: hosted version: "3.1.0" sdks: - dart: ">=3.7.2 <4.0.0" + dart: ">=3.8.0 <4.0.0" flutter: ">=3.27.0" diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 1fd24be..af264f7 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -3,7 +3,7 @@ description: "Demonstrates how to use the flutter_rotation_sensor plugin." publish_to: 'none' environment: - sdk: ^3.7.2 + sdk: ^3.8.0 dependencies: flutter: From 60e57fcd17045baf5f26b783ea9b4c18fde04f4e Mon Sep 17 00:00:00 2001 From: 6y Date: Mon, 20 Oct 2025 16:08:59 +0800 Subject: [PATCH 63/69] chore: bump native_device_orientation from 2.0.3 to 2.0.4 --- example/pubspec.lock | 4 ++-- pubspec.yaml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/example/pubspec.lock b/example/pubspec.lock index de87cb2..53559a6 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -173,10 +173,10 @@ packages: dependency: transitive description: name: native_device_orientation - sha256: "0c330c068575e4be72cce5968ca479a3f8d5d1e5dfce7d89d5c13a1e943b338c" + sha256: bc0bcccc79752048d2235c10545c5fd554a46035fe0a4a4534d1bb9d8bc85e6c url: "https://pub.dev" source: hosted - version: "2.0.3" + version: "2.0.4" path: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 8b07089..3931118 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -22,7 +22,7 @@ dependencies: logging: ^1.2.0 # flutter_test depends on meta, so use any meta: any - native_device_orientation: ^2.0.3 + native_device_orientation: ^2.0.4 plugin_platform_interface: ^2.1.8 dev_dependencies: From 3deb9d2f7c4933c8c4ab36659dfa9c72111e77aa Mon Sep 17 00:00:00 2001 From: 6y Date: Mon, 20 Oct 2025 17:27:04 +0800 Subject: [PATCH 64/69] style: format FlutterRotationSensorPlugin.kt --- .../FlutterRotationSensorPlugin.kt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/android/src/main/kotlin/net/tlserver6y/flutter_rotation_sensor/FlutterRotationSensorPlugin.kt b/android/src/main/kotlin/net/tlserver6y/flutter_rotation_sensor/FlutterRotationSensorPlugin.kt index 1bc1a87..202a835 100644 --- a/android/src/main/kotlin/net/tlserver6y/flutter_rotation_sensor/FlutterRotationSensorPlugin.kt +++ b/android/src/main/kotlin/net/tlserver6y/flutter_rotation_sensor/FlutterRotationSensorPlugin.kt @@ -24,8 +24,8 @@ class FlutterRotationSensorPlugin : FlutterPlugin, MethodCallHandler, StreamHand private var samplingPeriod = 200000 override fun onAttachedToEngine(flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) { - sensorManager = - flutterPluginBinding.applicationContext.getSystemService(Context.SENSOR_SERVICE) as SensorManager + val context = flutterPluginBinding.applicationContext + sensorManager = context.getSystemService(Context.SENSOR_SERVICE) as SensorManager sensor = sensorManager.getDefaultSensor(Sensor.TYPE_ROTATION_VECTOR) setupMethodChannel(flutterPluginBinding.binaryMessenger) setupEventChannel(flutterPluginBinding.binaryMessenger) @@ -61,8 +61,8 @@ class FlutterRotationSensorPlugin : FlutterPlugin, MethodCallHandler, StreamHand if (call.hasArgument("samplingPeriod")) { val samplingPeriod = call.argument("samplingPeriod") if ( - (samplingPeriod != null && - samplingPeriod != this.samplingPeriod) && + samplingPeriod != null && + samplingPeriod != this.samplingPeriod && sensorEventListener != null ) { this.samplingPeriod = samplingPeriod From 8c1ccd1bc3a34acf64202b3339857aa827dabbcc Mon Sep 17 00:00:00 2001 From: 6y Date: Mon, 20 Oct 2025 17:42:58 +0800 Subject: [PATCH 65/69] refactor: delay SensorManager.getDefaultSensor() call --- .../flutter_rotation_sensor/FlutterRotationSensorPlugin.kt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/android/src/main/kotlin/net/tlserver6y/flutter_rotation_sensor/FlutterRotationSensorPlugin.kt b/android/src/main/kotlin/net/tlserver6y/flutter_rotation_sensor/FlutterRotationSensorPlugin.kt index 202a835..c35fee9 100644 --- a/android/src/main/kotlin/net/tlserver6y/flutter_rotation_sensor/FlutterRotationSensorPlugin.kt +++ b/android/src/main/kotlin/net/tlserver6y/flutter_rotation_sensor/FlutterRotationSensorPlugin.kt @@ -26,7 +26,6 @@ class FlutterRotationSensorPlugin : FlutterPlugin, MethodCallHandler, StreamHand override fun onAttachedToEngine(flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) { val context = flutterPluginBinding.applicationContext sensorManager = context.getSystemService(Context.SENSOR_SERVICE) as SensorManager - sensor = sensorManager.getDefaultSensor(Sensor.TYPE_ROTATION_VECTOR) setupMethodChannel(flutterPluginBinding.binaryMessenger) setupEventChannel(flutterPluginBinding.binaryMessenger) } @@ -58,6 +57,9 @@ class FlutterRotationSensorPlugin : FlutterPlugin, MethodCallHandler, StreamHand override fun onMethodCall(call: MethodCall, result: Result) { when (call.method) { "getOrientationStream" -> { + if (sensor == null) { + sensor = sensorManager.getDefaultSensor(Sensor.TYPE_ROTATION_VECTOR) + } if (call.hasArgument("samplingPeriod")) { val samplingPeriod = call.argument("samplingPeriod") if ( From b60168feef3106ca16ef2bc45a2cdf82f7ef6e78 Mon Sep 17 00:00:00 2001 From: 6y Date: Tue, 21 Oct 2025 23:08:11 +0800 Subject: [PATCH 66/69] style: format change log --- CHANGELOG.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e6262a0..a4ad5f2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,11 @@ -## [0.1.1] - Bug Fix +## [0.1.1] (2024-10-22) + +**Bug Fixes** * Fixed an issue during the build process on iOS. -## [0.1.0] - Initial Release +## [0.1.0] (2024-07-25) + +**Features** * Initial release. From 05c4675741bc6738f6f4fd57e4a4f076ed2d26b5 Mon Sep 17 00:00:00 2001 From: 6y Date: Tue, 21 Oct 2025 23:19:14 +0800 Subject: [PATCH 67/69] chore: bump version to 0.2.0 --- CHANGELOG.md | 10 ++++++++++ example/pubspec.lock | 2 +- pubspec.yaml | 2 +- 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a4ad5f2..1a06427 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,13 @@ +## [0.2.0] (2025-10-21) + +**Features** + +* Added an indicator for platform support + +**Bug Fixes** + +* Fixed readme. (#62) + ## [0.1.1] (2024-10-22) **Bug Fixes** diff --git a/example/pubspec.lock b/example/pubspec.lock index 53559a6..91576b4 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -89,7 +89,7 @@ packages: path: ".." relative: true source: path - version: "0.1.1" + version: "0.2.0" flutter_test: dependency: "direct dev" description: flutter diff --git a/pubspec.yaml b/pubspec.yaml index 3931118..3b8f051 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: flutter_rotation_sensor description: > A package provides a stream of device's orientation in three different representations: a rotation matrix, a quaternion, and Euler angles (azimuth, pitch, roll). -version: 0.1.1 +version: 0.2.0 repository: https://github.com/tlserver/flutter_rotation_sensor environment: From fb64d68810f5dbec250a402d414940f329e9a868 Mon Sep 17 00:00:00 2001 From: Camille Riquet Date: Tue, 16 Jun 2026 12:57:17 +0200 Subject: [PATCH 68/69] feat: add configurable reference frame for north-referenced azimuth --- ios/Classes/FlutterRotationSensorPlugin.swift | 81 ++++++++++++++----- lib/flutter_rotation_sensor.dart | 1 + lib/src/reference_frame.dart | 22 +++++ lib/src/rotation_sensor.dart | 13 +++ lib/src/rotation_sensor_method_channel.dart | 12 +++ lib/src/rotation_sensor_platform.dart | 20 +++++ test/rotation_sensor_test.dart | 26 +++--- 7 files changed, 146 insertions(+), 29 deletions(-) create mode 100644 lib/src/reference_frame.dart diff --git a/ios/Classes/FlutterRotationSensorPlugin.swift b/ios/Classes/FlutterRotationSensorPlugin.swift index 4029fb3..95f328e 100644 --- a/ios/Classes/FlutterRotationSensorPlugin.swift +++ b/ios/Classes/FlutterRotationSensorPlugin.swift @@ -6,6 +6,14 @@ public class FlutterRotationSensorPlugin: NSObject, FlutterPlugin, FlutterStream private var eventChannel: FlutterEventChannel private let motionManager: CMMotionManager + private var referenceFrame: CMAttitudeReferenceFrame = .xArbitraryZVertical + private var eventSink: FlutterEventSink? + + // CoreMotion expresses a north reference frame as (north, west, up), while + // this plugin's world convention is (east, north, up) like Android. The two + // differ by a fixed 90° rotation about the vertical axis, applied to the + // attitude quaternion so the azimuth stays 0 = north on every platform. + private let northToEastNorthUp = 0.7071067811865476 // sin(45°) = cos(45°) public static func register(with registrar: FlutterPluginRegistrar) { let methodChannel = FlutterMethodChannel(name: "rotation_sensor/method", binaryMessenger: registrar.messenger()) @@ -25,38 +33,73 @@ public class FlutterRotationSensorPlugin: NSObject, FlutterPlugin, FlutterStream public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { switch call.method { case "getOrientationStream": - if let args = call.arguments as? [String: Any], - let samplingPeriod = args["samplingPeriod"] as? Double { - motionManager.deviceMotionUpdateInterval = samplingPeriod * 0.000001 + let args = call.arguments as? [String: Any] + if let samplingPeriod = args?["samplingPeriod"] as? Double { + motionManager.deviceMotionUpdateInterval = samplingPeriod * 0.000001 } + updateReferenceFrame(args?["referenceFrame"] as? String) result(nil) default: result(FlutterMethodNotImplemented) } } - public func onListen(withArguments arguments: Any?, eventSink events: @escaping FlutterEventSink) -> FlutterError? { - if motionManager.isDeviceMotionAvailable { - motionManager.startDeviceMotionUpdates(to: OperationQueue()) { (motion, error) in - guard let motion = motion, error == nil else { - events(FlutterError(code: "UNAVAILABLE", message: "Device motion updates unavailable", details: nil)) - return - } + private func updateReferenceFrame(_ name: String?) { + let newFrame = attitudeReferenceFrame(from: name) + guard newFrame != referenceFrame else { return } + referenceFrame = newFrame + if motionManager.isDeviceMotionActive, let sink = eventSink { + motionManager.stopDeviceMotionUpdates() + startUpdates(sink) + } + } + + private func attitudeReferenceFrame(from name: String?) -> CMAttitudeReferenceFrame { + switch name { + case "magneticNorth": return .xMagneticNorthZVertical + case "trueNorth": return .xTrueNorthZVertical + default: return .xArbitraryZVertical + } + } + + private func isNorthReferenced(_ frame: CMAttitudeReferenceFrame) -> Bool { + return frame == .xMagneticNorthZVertical || frame == .xTrueNorthZVertical + } - let quaternion = motion.attitude.quaternion - let rotationVector = [quaternion.x, quaternion.y, quaternion.z, quaternion.w, -1.0, Int64((motion.timestamp * 1000000000).rounded())] - DispatchQueue.main.async { - events(rotationVector) - } - } - return nil - } else { - return FlutterError(code: "NO_SENSOR", message: "Rotation vector sensor unavailable", details: nil) + private func startUpdates(_ events: @escaping FlutterEventSink) { + let correctToEastNorthUp = isNorthReferenced(referenceFrame) + motionManager.startDeviceMotionUpdates(using: referenceFrame, to: OperationQueue()) { (motion, error) in + guard let motion = motion, error == nil else { + events(FlutterError(code: "UNAVAILABLE", message: "Device motion updates unavailable", details: nil)) + return } + + let q = motion.attitude.quaternion + let k = self.northToEastNorthUp + let qx = correctToEastNorthUp ? k * (q.x - q.y) : q.x + let qy = correctToEastNorthUp ? k * (q.x + q.y) : q.y + let qz = correctToEastNorthUp ? k * (q.z + q.w) : q.z + let qw = correctToEastNorthUp ? k * (q.w - q.z) : q.w + + let rotationVector = [qx, qy, qz, qw, -1.0, Int64((motion.timestamp * 1000000000).rounded())] as [Any] + DispatchQueue.main.async { + events(rotationVector) + } + } + } + + public func onListen(withArguments arguments: Any?, eventSink events: @escaping FlutterEventSink) -> FlutterError? { + guard motionManager.isDeviceMotionAvailable else { + return FlutterError(code: "NO_SENSOR", message: "Rotation vector sensor unavailable", details: nil) + } + eventSink = events + startUpdates(events) + return nil } public func onCancel(withArguments arguments: Any?) -> FlutterError? { motionManager.stopDeviceMotionUpdates() + eventSink = nil return nil } diff --git a/lib/flutter_rotation_sensor.dart b/lib/flutter_rotation_sensor.dart index 816e0c5..0ad866f 100644 --- a/lib/flutter_rotation_sensor.dart +++ b/lib/flutter_rotation_sensor.dart @@ -6,5 +6,6 @@ export 'src/math/matrix3.dart'; export 'src/math/quaternion.dart'; export 'src/math/vector3.dart'; export 'src/orientation_event.dart'; +export 'src/reference_frame.dart'; export 'src/rotation_sensor.dart'; export 'src/sensor_interval.dart'; diff --git a/lib/src/reference_frame.dart b/lib/src/reference_frame.dart new file mode 100644 index 0000000..a159663 --- /dev/null +++ b/lib/src/reference_frame.dart @@ -0,0 +1,22 @@ +/// The world reference frame the device orientation is expressed against. +/// +/// This controls what the azimuth is measured from. Whatever the value, the +/// orientation is always returned in the package's east-north-up world +/// convention, so an azimuth of 0 means the device points north. +enum ReferenceFrame { + /// The platform default, with no guarantee of a north reference. + /// + /// On iOS the horizontal reference is arbitrary (the direction the device + /// happened to point when the sensor started, no compass). On Android the + /// rotation vector sensor is already referenced to magnetic north. + device, + + /// The azimuth is referenced to magnetic north on both platforms. No + /// dependency on location services. + magneticNorth, + + /// The azimuth is referenced to true (geographic) north. Requires location + /// services to be available. On Android, where the rotation vector is only + /// magnetic, this currently behaves like [magneticNorth]. + trueNorth; +} diff --git a/lib/src/rotation_sensor.dart b/lib/src/rotation_sensor.dart index 0d0345c..37bcc84 100644 --- a/lib/src/rotation_sensor.dart +++ b/lib/src/rotation_sensor.dart @@ -2,6 +2,7 @@ import 'package:meta/meta.dart'; import 'coordinate_system.dart'; import 'orientation_event.dart'; +import 'reference_frame.dart'; import 'rotation_sensor_method_channel.dart'; import 'rotation_sensor_platform.dart'; import 'sensor_interval.dart'; @@ -44,4 +45,16 @@ class RotationSensor { /// existing listeners will receive [OrientationEvent] in the new coordinate /// system. static CoordinateSystem coordinateSystem = DisplayCoordinateSystem(); + + /// The world [ReferenceFrame] the azimuth is measured from. + /// + /// Defaults to [ReferenceFrame.device]. Set it to + /// [ReferenceFrame.magneticNorth] or [ReferenceFrame.trueNorth] to get a real + /// compass heading (azimuth 0 = north). When changing this value, all + /// existing listeners will be affected. + static ReferenceFrame get referenceFrame => + RotationSensorPlatform.instance.referenceFrame; + + static set referenceFrame(ReferenceFrame value) => + RotationSensorPlatform.instance.referenceFrame = value; } diff --git a/lib/src/rotation_sensor_method_channel.dart b/lib/src/rotation_sensor_method_channel.dart index 173a446..b69a303 100644 --- a/lib/src/rotation_sensor_method_channel.dart +++ b/lib/src/rotation_sensor_method_channel.dart @@ -4,6 +4,7 @@ import 'package:flutter/services.dart'; import 'environment.dart'; import 'math/quaternion.dart'; import 'orientation_event.dart'; +import 'reference_frame.dart'; import 'rotation_sensor.dart'; import 'rotation_sensor_platform.dart'; @@ -38,6 +39,7 @@ class RotationSensorMethodChannel extends RotationSensorPlatform { } methodChannel.invokeMethod('getOrientationStream', { 'samplingPeriod': samplingMicroseconds, + 'referenceFrame': referenceFrameValue.name, }); final broadcastStream = eventChannel.receiveBroadcastStream(); return _orientationStream = broadcastStream.map((event) { @@ -56,6 +58,16 @@ class RotationSensorMethodChannel extends RotationSensorPlatform { void updateSamplingPeriod(int value) { methodChannel.invokeMethod('getOrientationStream', { 'samplingPeriod': value, + 'referenceFrame': referenceFrameValue.name, + }); + } + + @override + @protected + void updateReferenceFrame(ReferenceFrame value) { + methodChannel.invokeMethod('getOrientationStream', { + 'samplingPeriod': samplingMicroseconds, + 'referenceFrame': value.name, }); } } diff --git a/lib/src/rotation_sensor_platform.dart b/lib/src/rotation_sensor_platform.dart index cbc208e..4267ff5 100644 --- a/lib/src/rotation_sensor_platform.dart +++ b/lib/src/rotation_sensor_platform.dart @@ -3,6 +3,7 @@ import 'package:meta/meta.dart'; import 'package:plugin_platform_interface/plugin_platform_interface.dart'; import 'orientation_event.dart'; +import 'reference_frame.dart'; import 'rotation_sensor_method_channel.dart'; import 'rotation_sensor_unsupported.dart'; import 'sensor_interval.dart'; @@ -79,4 +80,23 @@ abstract class RotationSensorPlatform extends PlatformInterface { void updateSamplingPeriod(int value) { // no-op } + + @protected + ReferenceFrame referenceFrameValue = ReferenceFrame.device; + + /// The world [ReferenceFrame] the azimuth is measured from. + /// + /// Defaults to [ReferenceFrame.device]. When changing this value, all + /// existing listeners will be affected. + ReferenceFrame get referenceFrame => referenceFrameValue; + + set referenceFrame(ReferenceFrame value) { + referenceFrameValue = value; + updateReferenceFrame(value); + } + + @protected + void updateReferenceFrame(ReferenceFrame value) { + // no-op + } } diff --git a/test/rotation_sensor_test.dart b/test/rotation_sensor_test.dart index 310f5aa..f84d67f 100644 --- a/test/rotation_sensor_test.dart +++ b/test/rotation_sensor_test.dart @@ -22,16 +22,22 @@ class MockRotationSensorPlatform extends RotationSensorPlatform void main() { WidgetsFlutterBinding.ensureInitialized(); - test('isPlatformSupported returns true only for Android and iOS platforms', () { - isWeb = false; - for (final platform in TargetPlatform.values) { - debugDefaultTargetPlatformOverride = platform; - expect(RotationSensor.isPlatformSupported, equals([ - TargetPlatform.android, - TargetPlatform.iOS, - ].contains(platform))); - } - }); + // ignore: lines_longer_than_80_chars + test( + 'isPlatformSupported returns true only for Android and iOS platforms', + () { + isWeb = false; + for (final platform in TargetPlatform.values) { + debugDefaultTargetPlatformOverride = platform; + expect( + RotationSensor.isPlatformSupported, + equals( + [TargetPlatform.android, TargetPlatform.iOS].contains(platform), + ), + ); + } + }, + ); test('isPlatformSupported returns false for web platform', () { isWeb = true; From e7aa8f184113a6a85c55dba4e9a22d34d498de2f Mon Sep 17 00:00:00 2001 From: Camille Riquet Date: Tue, 16 Jun 2026 17:55:13 +0200 Subject: [PATCH 69/69] fix: add tests and update readme --- .idea/material_theme_project_new.xml | 12 ++++++ README.md | 35 ++++++++++++++++- test/rotation_sensor_method_channel_test.dart | 15 ++++++++ test/rotation_sensor_test.dart | 38 +++++++++++-------- 4 files changed, 83 insertions(+), 17 deletions(-) create mode 100644 .idea/material_theme_project_new.xml diff --git a/.idea/material_theme_project_new.xml b/.idea/material_theme_project_new.xml new file mode 100644 index 0000000..4e1fcc7 --- /dev/null +++ b/.idea/material_theme_project_new.xml @@ -0,0 +1,12 @@ + + + + + + \ No newline at end of file diff --git a/README.md b/README.md index 2742c22..22749ce 100644 --- a/README.md +++ b/README.md @@ -74,7 +74,9 @@ For more control, you can subscribe to the stream directly: super.initState(); orientationSubscription = RotationSensor.orientationStream.listen((event) { final azimuth = event.eulerAngles.azimuth; - // Print azimuth: 0 for North, π/2 for East, π for South, -π/2 for West + // Print azimuth: 0 for North, π/2 for East, π for South, -π/2 for West. + // On iOS, an azimuth of 0 only points to north when a north-referenced + // reference frame is set (see the Reference Frame section below). print(azimuth); }); } @@ -101,6 +103,9 @@ void initState() { // Set the sampling period for the rotation sensor RotationSensor.samplingPeriod = SensorInterval.uiInterval; + // Set the reference frame the azimuth is measured from + RotationSensor.referenceFrame = ReferenceFrame.magneticNorth; + // Set the coordinate system for the rotation sensor RotationSensor.coordinateSystem = CoordinateSystem.transformed(Axis3.X, Axis3.Z); } @@ -128,6 +133,34 @@ void config() { Events may arrive at a rate faster or slower than the sampling period, which is only a hint to the system. The actual rate depends on the system's event queue and sensor hardware capabilities. +### Reference Frame + +The [RotationSensor.referenceFrame](https://pub.dev/documentation/flutter_rotation_sensor/latest/flutter_rotation_sensor/RotationSensor/referenceFrame.html) +property controls the world reference the azimuth is measured from. Whatever the value, the +orientation is always returned in the plugin's east-north-up world convention, so an azimuth of 0 +means the device points north. Here are the values you can use: + +- `ReferenceFrame.device`: *(default value)* The platform default, with no guarantee of a north + reference. On iOS the horizontal reference is arbitrary (the direction the device happened to + point when the sensor started, no compass). On Android the rotation vector sensor is already + referenced to magnetic north. +- `ReferenceFrame.magneticNorth`: The azimuth is referenced to magnetic north on both platforms, + without depending on location services. +- `ReferenceFrame.trueNorth`: The azimuth is referenced to true (geographic) north. Requires + location services to be available. + +```dart +void config() { + RotationSensor.referenceFrame = ReferenceFrame.magneticNorth; +} +``` + +> [!NOTE] +> Reference frame selection is currently implemented on iOS only. On Android the rotation vector is +> always referenced to magnetic north, so `device` and `magneticNorth` already behave as expected, +> while `trueNorth` currently behaves like `magneticNorth`. Android support for `trueNorth` is +> tracked in a separate issue. + ### Coordinate System The [RotationSensor.coordinateSystem](https://pub.dev/documentation/flutter_rotation_sensor/latest/flutter_rotation_sensor/RotationSensor/coordinateSystem.html) diff --git a/test/rotation_sensor_method_channel_test.dart b/test/rotation_sensor_method_channel_test.dart index 78cbe30..f3d2a32 100644 --- a/test/rotation_sensor_method_channel_test.dart +++ b/test/rotation_sensor_method_channel_test.dart @@ -9,9 +9,11 @@ void main() { const methodChannel = RotationSensorMethodChannel.methodChannel; const orientationChannel = RotationSensorMethodChannel.eventChannel; late int expectedSamplingPeriod; + late ReferenceFrame expectedReferenceFrame; setUp(() { expectedSamplingPeriod = platform.samplingPeriod.inMicroseconds; + expectedReferenceFrame = platform.referenceFrame; TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger .setMockMethodCallHandler(methodChannel, (methodCall) async { switch (methodCall.method) { @@ -19,6 +21,8 @@ void main() { final arguments = methodCall.arguments as Map; final samplingPeriod = arguments['samplingPeriod'] as int; expect(samplingPeriod, expectedSamplingPeriod); + final referenceFrame = arguments['referenceFrame'] as String; + expect(referenceFrame, expectedReferenceFrame.name); return null; default: throw UnsupportedError(methodCall.method); @@ -69,4 +73,15 @@ void main() { expect(await platform.orientationStream.first, isA()); }, ); + + test( + 'orientationStream forwards the configured reference frame to the platform', + () async { + expectedReferenceFrame = ReferenceFrame.magneticNorth; + platform.referenceFrame = ReferenceFrame.magneticNorth; + expect(platform.referenceFrame, equals(ReferenceFrame.magneticNorth)); + await Future.microtask(() => null); + expect(await platform.orientationStream.first, isA()); + }, + ); } diff --git a/test/rotation_sensor_test.dart b/test/rotation_sensor_test.dart index f84d67f..3fb76c0 100644 --- a/test/rotation_sensor_test.dart +++ b/test/rotation_sensor_test.dart @@ -22,22 +22,16 @@ class MockRotationSensorPlatform extends RotationSensorPlatform void main() { WidgetsFlutterBinding.ensureInitialized(); - // ignore: lines_longer_than_80_chars - test( - 'isPlatformSupported returns true only for Android and iOS platforms', - () { - isWeb = false; - for (final platform in TargetPlatform.values) { - debugDefaultTargetPlatformOverride = platform; - expect( - RotationSensor.isPlatformSupported, - equals( - [TargetPlatform.android, TargetPlatform.iOS].contains(platform), - ), - ); - } - }, - ); + test('isPlatformSupported returns true only for Android and iOS platforms', () { + isWeb = false; + for (final platform in TargetPlatform.values) { + debugDefaultTargetPlatformOverride = platform; + expect(RotationSensor.isPlatformSupported, equals([ + TargetPlatform.android, + TargetPlatform.iOS, + ].contains(platform))); + } + }); test('isPlatformSupported returns false for web platform', () { isWeb = true; @@ -67,4 +61,16 @@ void main() { RotationSensor.coordinateSystem = CoordinateSystem.display(); expect(RotationSensor.coordinateSystem, same(CoordinateSystem.display())); }); + + test('referenceFrame defaults to device', () { + RotationSensorPlatform.instance = MockRotationSensorPlatform(); + expect(RotationSensor.referenceFrame, equals(ReferenceFrame.device)); + }); + + test('referenceFrame can be set and retrieved correctly', () { + RotationSensor.referenceFrame = ReferenceFrame.magneticNorth; + expect(RotationSensor.referenceFrame, equals(ReferenceFrame.magneticNorth)); + RotationSensor.referenceFrame = ReferenceFrame.trueNorth; + expect(RotationSensor.referenceFrame, equals(ReferenceFrame.trueNorth)); + }); }