diff --git a/.gitignore b/.gitignore index bb431f0..79c113f 100644 --- a/.gitignore +++ b/.gitignore @@ -5,9 +5,12 @@ *.swp .DS_Store .atom/ +.build/ .buildlog/ .history .svn/ +.swiftpm/ +migrate_working_dir/ # IntelliJ related *.iml @@ -22,54 +25,21 @@ # Flutter/Dart/Pub related **/doc/api/ +**/ios/Flutter/.last_build_id .dart_tool/ .flutter-plugins .flutter-plugins-dependencies -.packages .pub-cache/ .pub/ -build/ +/build/ -# Android related -**/android/**/gradle-wrapper.jar -**/android/.gradle -**/android/captures/ -**/android/gradlew -**/android/gradlew.bat -**/android/local.properties -**/android/**/GeneratedPluginRegistrant.java +# Symbolication related +app.*.symbols -# iOS/XCode related -**/ios/**/*.mode1v3 -**/ios/**/*.mode2v3 -**/ios/**/*.moved-aside -**/ios/**/*.pbxuser -**/ios/**/*.perspectivev3 -**/ios/**/*sync/ -**/ios/**/.sconsign.dblite -**/ios/**/.tags* -**/ios/**/.vagrant/ -**/ios/**/DerivedData/ -**/ios/**/Icon? -**/ios/**/Pods/ -**/ios/**/.symlinks/ -**/ios/**/profile -**/ios/**/xcuserdata -**/ios/.generated/ -**/ios/Flutter/App.framework -**/ios/Flutter/Flutter.framework -**/ios/Flutter/Flutter.podspec -**/ios/Flutter/Generated.xcconfig -**/ios/Flutter/app.flx -**/ios/Flutter/app.zip -**/ios/Flutter/flutter_assets/ -**/ios/Flutter/flutter_export_environment.sh -**/ios/ServiceDefinitions.json -**/ios/Runner/GeneratedPluginRegistrant.* +# Obfuscation related +app.*.map.json -# Exceptions to above rules. -!**/ios/**/default.mode1v3 -!**/ios/**/default.mode2v3 -!**/ios/**/default.pbxuser -!**/ios/**/default.perspectivev3 -!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages +# Android Studio will place build artifacts here +/android/app/debug +/android/app/profile +/android/app/release diff --git a/example/android/.gitignore b/example/android/.gitignore index bc2100d..be3943c 100644 --- a/example/android/.gitignore +++ b/example/android/.gitignore @@ -5,3 +5,10 @@ gradle-wrapper.jar /gradlew.bat /local.properties GeneratedPluginRegistrant.java +.cxx/ + +# Remember to never publicly share your keystore. +# See https://flutter.dev/to/reference-keystore +key.properties +**/*.keystore +**/*.jks diff --git a/example/android/app/build.gradle b/example/android/app/build.gradle index 0f6a5e5..233902d 100644 --- a/example/android/app/build.gradle +++ b/example/android/app/build.gradle @@ -1,3 +1,9 @@ +plugins { + id "com.android.application" + id "kotlin-android" + id "dev.flutter.flutter-gradle-plugin" +} + def localProperties = new Properties() def localPropertiesFile = rootProject.file('local.properties') if (localPropertiesFile.exists()) { @@ -8,7 +14,7 @@ if (localPropertiesFile.exists()) { def flutterRoot = localProperties.getProperty('flutter.sdk') if (flutterRoot == null) { - throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") + throw GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") } def flutterVersionCode = localProperties.getProperty('flutter.versionCode') @@ -21,12 +27,18 @@ if (flutterVersionName == null) { flutterVersionName = '1.0' } -apply plugin: 'com.android.application' -apply plugin: 'kotlin-android' -apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" - android { - compileSdkVersion 28 + namespace "com.example.example" + compileSdkVersion flutter.compileSdkVersion + + compileOptions { + sourceCompatibility JavaVersion.VERSION_11 + targetCompatibility JavaVersion.VERSION_11 + } + + kotlinOptions { + jvmTarget = JavaVersion.VERSION_11.toString() + } sourceSets { main.java.srcDirs += 'src/main/kotlin' @@ -39,8 +51,8 @@ android { defaultConfig { // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). applicationId "com.example.example" - minSdkVersion 16 - targetSdkVersion 28 + minSdkVersion flutter.minSdkVersion + targetSdkVersion flutter.targetSdkVersion versionCode flutterVersionCode.toInteger() versionName flutterVersionName testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" @@ -60,7 +72,6 @@ flutter { } dependencies { - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" testImplementation 'junit:junit:4.12' androidTestImplementation 'androidx.test:runner:1.1.1' androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1' diff --git a/example/android/app/src/debug/AndroidManifest.xml b/example/android/app/src/debug/AndroidManifest.xml index c208884..f880684 100644 --- a/example/android/app/src/debug/AndroidManifest.xml +++ b/example/android/app/src/debug/AndroidManifest.xml @@ -1,5 +1,4 @@ - + diff --git a/example/android/app/src/main/AndroidManifest.xml b/example/android/app/src/main/AndroidManifest.xml index 8bc6007..55a7314 100644 --- a/example/android/app/src/main/AndroidManifest.xml +++ b/example/android/app/src/main/AndroidManifest.xml @@ -1,16 +1,16 @@ - + + diff --git a/example/android/build.gradle b/example/android/build.gradle index 3100ad2..bc157bd 100644 --- a/example/android/build.gradle +++ b/example/android/build.gradle @@ -1,20 +1,7 @@ -buildscript { - ext.kotlin_version = '1.3.50' - repositories { - google() - jcenter() - } - - dependencies { - classpath 'com.android.tools.build:gradle:3.5.0' - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" - } -} - allprojects { repositories { google() - jcenter() + mavenCentral() } } @@ -26,6 +13,6 @@ subprojects { project.evaluationDependsOn(':app') } -task clean(type: Delete) { +tasks.register("clean", Delete) { delete rootProject.buildDir } diff --git a/example/android/gradle.properties b/example/android/gradle.properties index 38c8d45..f018a61 100644 --- a/example/android/gradle.properties +++ b/example/android/gradle.properties @@ -1,4 +1,3 @@ -org.gradle.jvmargs=-Xmx1536M -android.enableR8=true +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 296b146..db18181 100644 --- a/example/android/gradle/wrapper/gradle-wrapper.properties +++ b/example/android/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-all.zip diff --git a/example/android/settings.gradle b/example/android/settings.gradle index 5a2f14f..a120fc8 100644 --- a/example/android/settings.gradle +++ b/example/android/settings.gradle @@ -1,15 +1,25 @@ -include ':app' +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 + }() -def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + includeBuild("$flutterSdkPath/packages/flutter_tools/gradle") -def plugins = new Properties() -def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') -if (pluginsFile.exists()) { - pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } + repositories { + google() + mavenCentral() + gradlePluginPortal() + } } -plugins.each { name, path -> - def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() - include ":$name" - project(":$name").projectDir = pluginDirectory +plugins { + id "dev.flutter.flutter-plugin-loader" version "1.0.0" + id "com.android.application" version '8.7.0' apply false + id "org.jetbrains.kotlin.android" version "1.8.22" apply false } + +include ':app' diff --git a/example/lib/main.dart b/example/lib/main.dart index 3958947..e912fd4 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -45,15 +45,16 @@ class _MyHomePageState extends State { }); } - Widget hotspotButton({String? text, IconData? icon, VoidCallback? onPressed}) { + Widget hotspotButton( + {String? text, IconData? icon, VoidCallback? onPressed}) { return Column( mainAxisAlignment: MainAxisAlignment.center, children: [ TextButton( style: ButtonStyle( - shape: MaterialStateProperty.all(CircleBorder()), - backgroundColor: MaterialStateProperty.all(Colors.black38), - foregroundColor: MaterialStateProperty.all(Colors.white), + shape: WidgetStateProperty.all(CircleBorder()), + backgroundColor: WidgetStateProperty.all(Colors.black38), + foregroundColor: WidgetStateProperty.all(Colors.white), ), child: Icon(icon), onPressed: onPressed, @@ -61,7 +62,9 @@ class _MyHomePageState extends State { text != null ? Container( padding: EdgeInsets.all(4.0), - decoration: BoxDecoration(color: Colors.black38, borderRadius: BorderRadius.all(Radius.circular(4))), + decoration: BoxDecoration( + color: Colors.black38, + borderRadius: BorderRadius.all(Radius.circular(4))), child: Center(child: Text(text)), ) : Container(), @@ -78,10 +81,14 @@ class _MyHomePageState extends State { animSpeed: 1.0, sensorControl: SensorControl.Orientation, onViewChanged: onViewChanged, - onTap: (longitude, latitude, tilt) => print('onTap: $longitude, $latitude, $tilt'), - onLongPressStart: (longitude, latitude, tilt) => print('onLongPressStart: $longitude, $latitude, $tilt'), - onLongPressMoveUpdate: (longitude, latitude, tilt) => print('onLongPressMoveUpdate: $longitude, $latitude, $tilt'), - onLongPressEnd: (longitude, latitude, tilt) => print('onLongPressEnd: $longitude, $latitude, $tilt'), + onTap: (longitude, latitude, tilt) => + print('onTap: $longitude, $latitude, $tilt'), + onLongPressStart: (longitude, latitude, tilt) => + print('onLongPressStart: $longitude, $latitude, $tilt'), + onLongPressMoveUpdate: (longitude, latitude, tilt) => + print('onLongPressMoveUpdate: $longitude, $latitude, $tilt'), + onLongPressEnd: (longitude, latitude, tilt) => + print('onLongPressEnd: $longitude, $latitude, $tilt'), child: Image.asset('assets/panorama.jpg'), hotspots: [ Hotspot( @@ -89,14 +96,19 @@ class _MyHomePageState extends State { longitude: -129.0, width: 90, height: 75, - widget: hotspotButton(text: "Next scene", icon: Icons.open_in_browser, onPressed: () => setState(() => _panoId++)), + widget: hotspotButton( + text: "Next scene", + icon: Icons.open_in_browser, + onPressed: () => setState(() => _panoId++)), ), Hotspot( latitude: -42.0, longitude: -46.0, width: 60.0, height: 60.0, - widget: hotspotButton(icon: Icons.search, onPressed: () => setState(() => _panoId = 2)), + widget: hotspotButton( + icon: Icons.search, + onPressed: () => setState(() => _panoId = 2)), ), Hotspot( latitude: -33.0, @@ -123,7 +135,10 @@ class _MyHomePageState extends State { longitude: -46.0, width: 90.0, height: 75.0, - widget: hotspotButton(text: "Next scene", icon: Icons.double_arrow, onPressed: () => setState(() => _panoId++)), + widget: hotspotButton( + text: "Next scene", + icon: Icons.double_arrow, + onPressed: () => setState(() => _panoId++)), ), ], ); @@ -140,7 +155,10 @@ class _MyHomePageState extends State { longitude: 160.0, width: 90.0, height: 75.0, - widget: hotspotButton(text: "Next scene", icon: Icons.double_arrow, onPressed: () => setState(() => _panoId++)), + widget: hotspotButton( + text: "Next scene", + icon: Icons.double_arrow, + onPressed: () => setState(() => _panoId++)), ), ], ); @@ -152,13 +170,15 @@ class _MyHomePageState extends State { body: Stack( children: [ panorama, - Text('${_lon.toStringAsFixed(3)}, ${_lat.toStringAsFixed(3)}, ${_tilt.toStringAsFixed(3)}'), + Text( + '${_lon.toStringAsFixed(3)}, ${_lat.toStringAsFixed(3)}, ${_tilt.toStringAsFixed(3)}'), ], ), floatingActionButton: FloatingActionButton( mini: true, onPressed: () async { - final pickedFile = await picker.getImage(source: ImageSource.gallery); + final pickedFile = + await picker.pickImage(source: ImageSource.gallery); setState(() { if (pickedFile != null) { panoImages.add(Image.file(File(pickedFile.path))); diff --git a/example/pubspec.lock b/example/pubspec.lock index 8900253..0860caa 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -5,51 +5,98 @@ packages: dependency: transitive description: name: async - url: "https://pub.dartlang.org" + sha256: d2872f9c19731c2e5f10444b14686eb7cc85c76274bd6c16e1816bff9a3bab63 + url: "https://pub.dev" source: hosted - version: "2.5.0" + version: "2.12.0" boolean_selector: dependency: transitive description: name: boolean_selector - url: "https://pub.dartlang.org" + sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea" + url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.1.2" characters: dependency: transitive description: name: characters - url: "https://pub.dartlang.org" + sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803 + url: "https://pub.dev" source: hosted - version: "1.1.0" - charcode: - dependency: transitive - description: - name: charcode - url: "https://pub.dartlang.org" - source: hosted - version: "1.2.0" + version: "1.4.0" clock: dependency: transitive description: name: clock - url: "https://pub.dartlang.org" + sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b + url: "https://pub.dev" source: hosted - version: "1.1.0" + version: "1.1.2" collection: dependency: transitive description: name: collection - url: "https://pub.dartlang.org" + sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76" + url: "https://pub.dev" + source: hosted + version: "1.19.1" + cross_file: + dependency: transitive + description: + name: cross_file + sha256: "7caf6a750a0c04effbb52a676dce9a4a592e10ad35c34d6d2d0e4811160d5670" + url: "https://pub.dev" source: hosted - version: "1.15.0" + version: "0.3.4+2" + dchs_motion_sensors: + dependency: transitive + description: + name: dchs_motion_sensors + sha256: "2a6eec0c47fd59d0f923aa758286ded0d74ae79519dec560d003e6d0797877e2" + url: "https://pub.dev" + source: hosted + version: "2.0.1" fake_async: dependency: transitive description: name: fake_async - url: "https://pub.dartlang.org" + sha256: "6a95e56b2449df2273fd8c45a662d6947ce1ebb7aafe80e550a3f68297f3cacc" + url: "https://pub.dev" + source: hosted + version: "1.3.2" + file_selector_linux: + dependency: transitive + description: + name: file_selector_linux + sha256: "54cbbd957e1156d29548c7d9b9ec0c0ebb6de0a90452198683a7d23aed617a33" + url: "https://pub.dev" + source: hosted + version: "0.9.3+2" + file_selector_macos: + dependency: transitive + description: + name: file_selector_macos + sha256: "271ab9986df0c135d45c3cdb6bd0faa5db6f4976d3e4b437cf7d0f258d941bfc" + url: "https://pub.dev" + source: hosted + version: "0.9.4+2" + file_selector_platform_interface: + dependency: transitive + description: + name: file_selector_platform_interface + sha256: a3994c26f10378a039faa11de174d7b78eb8f79e4dd0af2a451410c1a5c3f66b + url: "https://pub.dev" source: hosted - version: "1.2.0" + version: "2.6.2" + file_selector_windows: + dependency: transitive + description: + name: file_selector_windows + sha256: "320fcfb6f33caa90f0b58380489fc5ac05d99ee94b61aa96ec2bff0ba81d3c2b" + url: "https://pub.dev" + source: hosted + version: "0.9.3+4" flutter: dependency: "direct main" description: flutter @@ -59,159 +106,272 @@ packages: dependency: transitive description: name: flutter_cube - url: "https://pub.dartlang.org" + sha256: "71cf679a251166eb97f86751c56582b09abdbf859485fbf60524948813914c3b" + url: "https://pub.dev" source: hosted version: "0.1.1" flutter_plugin_android_lifecycle: dependency: transitive description: name: flutter_plugin_android_lifecycle - url: "https://pub.dartlang.org" + sha256: "5a1e6fb2c0561958d7e4c33574674bda7b77caaca7a33b758876956f2902eea3" + url: "https://pub.dev" source: hosted - version: "2.0.0" + version: "2.0.27" flutter_test: dependency: "direct dev" description: flutter source: sdk version: "0.0.0" + flutter_web_plugins: + dependency: transitive + description: flutter + source: sdk + version: "0.0.0" http: dependency: transitive description: name: http - url: "https://pub.dartlang.org" + sha256: fe7ab022b76f3034adc518fb6ea04a82387620e19977665ea18d30a1cf43442f + url: "https://pub.dev" source: hosted - version: "0.13.0" + version: "1.3.0" http_parser: dependency: transitive description: name: http_parser - url: "https://pub.dartlang.org" + sha256: "178d74305e7866013777bab2c3d8726205dc5a4dd935297175b19a23a2e66571" + url: "https://pub.dev" source: hosted - version: "4.0.0" + version: "4.1.2" image_picker: dependency: "direct main" description: name: image_picker - url: "https://pub.dartlang.org" + sha256: "021834d9c0c3de46bf0fe40341fa07168407f694d9b2bb18d532dc1261867f7a" + url: "https://pub.dev" + source: hosted + version: "1.1.2" + image_picker_android: + dependency: transitive + description: + name: image_picker_android + sha256: "8bd392ba8b0c8957a157ae0dc9fcf48c58e6c20908d5880aea1d79734df090e9" + url: "https://pub.dev" + source: hosted + version: "0.8.12+22" + image_picker_for_web: + dependency: transitive + description: + name: image_picker_for_web + sha256: "717eb042ab08c40767684327be06a5d8dbb341fe791d514e4b92c7bbe1b7bb83" + url: "https://pub.dev" + source: hosted + version: "3.0.6" + image_picker_ios: + dependency: transitive + description: + name: image_picker_ios + sha256: "05da758e67bc7839e886b3959848aa6b44ff123ab4b28f67891008afe8ef9100" + url: "https://pub.dev" source: hosted - version: "0.7.2+1" + version: "0.8.12+2" + image_picker_linux: + dependency: transitive + description: + name: image_picker_linux + sha256: "34a65f6740df08bbbeb0a1abd8e6d32107941fd4868f67a507b25601651022c9" + url: "https://pub.dev" + source: hosted + version: "0.2.1+2" + image_picker_macos: + dependency: transitive + description: + name: image_picker_macos + sha256: "1b90ebbd9dcf98fb6c1d01427e49a55bd96b5d67b8c67cf955d60a5de74207c1" + url: "https://pub.dev" + source: hosted + version: "0.2.1+2" image_picker_platform_interface: dependency: transitive description: name: image_picker_platform_interface - url: "https://pub.dartlang.org" + sha256: "886d57f0be73c4b140004e78b9f28a8914a09e50c2d816bdd0520051a71236a0" + url: "https://pub.dev" source: hosted - version: "2.0.1" + version: "2.10.1" + image_picker_windows: + dependency: transitive + description: + name: image_picker_windows + sha256: "6ad07afc4eb1bc25f3a01084d28520496c4a3bb0cb13685435838167c9dcedeb" + url: "https://pub.dev" + source: hosted + version: "0.2.1+1" + leak_tracker: + dependency: transitive + description: + name: leak_tracker + sha256: c35baad643ba394b40aac41080300150a4f08fd0fd6a10378f8f7c6bc161acec + url: "https://pub.dev" + source: hosted + version: "10.0.8" + leak_tracker_flutter_testing: + dependency: transitive + description: + name: leak_tracker_flutter_testing + sha256: f8b613e7e6a13ec79cfdc0e97638fddb3ab848452eff057653abd3edba760573 + url: "https://pub.dev" + source: hosted + version: "3.0.9" + leak_tracker_testing: + dependency: transitive + description: + name: leak_tracker_testing + sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3" + url: "https://pub.dev" + source: hosted + version: "3.0.1" matcher: dependency: transitive description: name: matcher - url: "https://pub.dartlang.org" + sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2 + url: "https://pub.dev" source: hosted - version: "0.12.10" + version: "0.12.17" + material_color_utilities: + dependency: transitive + description: + name: material_color_utilities + sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec + url: "https://pub.dev" + source: hosted + version: "0.11.1" meta: dependency: transitive description: name: meta - url: "https://pub.dartlang.org" + sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c + url: "https://pub.dev" source: hosted - version: "1.3.0" - motion_sensors: + version: "1.16.0" + mime: dependency: transitive description: - name: motion_sensors - url: "https://pub.dartlang.org" + name: mime + sha256: "41a20518f0cb1256669420fdba0cd90d21561e560ac240f26ef8322e45bb7ed6" + url: "https://pub.dev" source: hosted - version: "0.1.0" + version: "2.0.0" panorama: dependency: "direct main" description: path: ".." relative: true source: path - version: "0.4.0" + version: "0.4.1" path: dependency: transitive description: name: path - url: "https://pub.dartlang.org" - source: hosted - version: "1.8.0" - pedantic: - dependency: transitive - description: - name: pedantic - url: "https://pub.dartlang.org" + sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5" + url: "https://pub.dev" source: hosted - version: "1.11.0" + version: "1.9.1" plugin_platform_interface: dependency: transitive description: name: plugin_platform_interface - url: "https://pub.dartlang.org" + sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02" + url: "https://pub.dev" source: hosted - version: "2.0.0" + version: "2.1.8" sky_engine: dependency: transitive description: flutter source: sdk - version: "0.0.99" + version: "0.0.0" source_span: dependency: transitive description: name: source_span - url: "https://pub.dartlang.org" + sha256: "254ee5351d6cb365c859e20ee823c3bb479bf4a293c22d17a9f1bf144ce86f7c" + url: "https://pub.dev" source: hosted - version: "1.8.0" + version: "1.10.1" stack_trace: dependency: transitive description: name: stack_trace - url: "https://pub.dartlang.org" + sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1" + url: "https://pub.dev" source: hosted - version: "1.10.0" + version: "1.12.1" stream_channel: dependency: transitive description: name: stream_channel - url: "https://pub.dartlang.org" + sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d" + url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.1.4" string_scanner: dependency: transitive description: name: string_scanner - url: "https://pub.dartlang.org" + sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43" + url: "https://pub.dev" source: hosted - version: "1.1.0" + version: "1.4.1" term_glyph: dependency: transitive description: name: term_glyph - url: "https://pub.dartlang.org" + sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e" + url: "https://pub.dev" source: hosted - version: "1.2.0" + version: "1.2.2" test_api: dependency: transitive description: name: test_api - url: "https://pub.dartlang.org" + sha256: fb31f383e2ee25fbbfe06b40fe21e1e458d14080e3c67e7ba0acfde4df4e0bbd + url: "https://pub.dev" source: hosted - version: "0.2.19" + version: "0.7.4" typed_data: dependency: transitive description: name: typed_data - url: "https://pub.dartlang.org" + sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006 + url: "https://pub.dev" source: hosted - version: "1.3.0" + version: "1.4.0" vector_math: dependency: transitive description: name: vector_math - url: "https://pub.dartlang.org" + sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" + url: "https://pub.dev" + source: hosted + version: "2.1.4" + vm_service: + dependency: transitive + description: + name: vm_service + sha256: "0968250880a6c5fe7edc067ed0a13d4bae1577fe2771dcf3010d52c4a9d3ca14" + url: "https://pub.dev" + source: hosted + version: "14.3.1" + web: + dependency: transitive + description: + name: web + sha256: "868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a" + url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "1.1.1" sdks: - dart: ">=2.12.0 <3.0.0" - flutter: ">=1.20.0" + dart: ">=3.7.0-0 <4.0.0" + flutter: ">=3.27.0" diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 038725f..e14a88a 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -3,14 +3,14 @@ description: A new Flutter project. version: 1.0.0+1 environment: - sdk: '>=2.12.0 <3.0.0' + sdk: '>=2.14.0 <3.0.0' dependencies: flutter: sdk: flutter panorama: path: ../ - image_picker: ^0.7.2+1 + image_picker: ^1.1.2 dev_dependencies: flutter_test: diff --git a/lib/panorama.dart b/lib/panorama.dart index a82d87d..7fd47b3 100644 --- a/lib/panorama.dart +++ b/lib/panorama.dart @@ -5,7 +5,7 @@ import 'dart:ui' as ui; import 'dart:math' as math; import 'package:flutter/material.dart'; import 'package:flutter_cube/flutter_cube.dart'; -import 'package:motion_sensors/motion_sensors.dart'; +import 'package:dchs_motion_sensors/dchs_motion_sensors.dart'; enum SensorControl { /// No sensor used. @@ -114,14 +114,17 @@ class Panorama extends StatefulWidget { final Function(double longitude, double latitude, double tilt)? onTap; /// This event will be called when the user has started a long press, it contains latitude and longitude about where the user pressed. - final Function(double longitude, double latitude, double tilt)? onLongPressStart; + final Function(double longitude, double latitude, double tilt)? + onLongPressStart; /// This event will be called when the user has drag-moved after a long press, it contains latitude and longitude about where the user pressed. - final Function(double longitude, double latitude, double tilt)? onLongPressMoveUpdate; + final Function(double longitude, double latitude, double tilt)? + onLongPressMoveUpdate; /// This event will be called when the user has stopped a long presses, it contains latitude and longitude about where the user pressed. - final Function(double longitude, double latitude, double tilt)? onLongPressEnd; - + final Function(double longitude, double latitude, double tilt)? + onLongPressEnd; + /// This event will be called when provided image is loaded on texture. final Function()? onImageLoad; @@ -135,7 +138,8 @@ class Panorama extends StatefulWidget { _PanoramaState createState() => _PanoramaState(); } -class _PanoramaState extends State with SingleTickerProviderStateMixin { +class _PanoramaState extends State + with SingleTickerProviderStateMixin { Scene? scene; Object? surface; late double latitude; @@ -158,22 +162,26 @@ class _PanoramaState extends State with SingleTickerProviderStateMixin ImageStream? _imageStream; void _handleTapUp(TapUpDetails details) { - final Vector3 o = positionToLatLon(details.localPosition.dx, details.localPosition.dy); + final Vector3 o = + positionToLatLon(details.localPosition.dx, details.localPosition.dy); widget.onTap!(degrees(o.x), degrees(-o.y), degrees(o.z)); } void _handleLongPressStart(LongPressStartDetails details) { - final Vector3 o = positionToLatLon(details.localPosition.dx, details.localPosition.dy); + final Vector3 o = + positionToLatLon(details.localPosition.dx, details.localPosition.dy); widget.onLongPressStart!(degrees(o.x), degrees(-o.y), degrees(o.z)); } void _handleLongPressMoveUpdate(LongPressMoveUpdateDetails details) { - final Vector3 o = positionToLatLon(details.localPosition.dx, details.localPosition.dy); + final Vector3 o = + positionToLatLon(details.localPosition.dx, details.localPosition.dy); widget.onLongPressMoveUpdate!(degrees(o.x), degrees(-o.y), degrees(o.z)); } void _handleLongPressEnd(LongPressEndDetails details) { - final Vector3 o = positionToLatLon(details.localPosition.dx, details.localPosition.dy); + final Vector3 o = + positionToLatLon(details.localPosition.dx, details.localPosition.dy); widget.onLongPressEnd!(degrees(o.x), degrees(-o.y), degrees(o.z)); } @@ -185,13 +193,23 @@ class _PanoramaState extends State with SingleTickerProviderStateMixin void _handleScaleUpdate(ScaleUpdateDetails details) { final offset = details.localFocalPoint - _lastFocalPoint; _lastFocalPoint = details.localFocalPoint; - latitudeDelta += widget.sensitivity * 0.5 * math.pi * offset.dy / scene!.camera.viewportHeight; - longitudeDelta -= widget.sensitivity * _animateDirection * 0.5 * math.pi * offset.dx / scene!.camera.viewportHeight; + latitudeDelta += widget.sensitivity * + 0.5 * + math.pi * + offset.dy / + scene!.camera.viewportHeight; + longitudeDelta -= widget.sensitivity * + _animateDirection * + 0.5 * + math.pi * + offset.dx / + scene!.camera.viewportHeight; if (_lastZoom == null) { _lastZoom = scene!.camera.zoom; } zoomDelta += _lastZoom! * details.scale - (scene!.camera.zoom + zoomDelta); - if (widget.sensorControl == SensorControl.None && !_controller.isAnimating) { + if (widget.sensorControl == SensorControl.None && + !_controller.isAnimating) { _controller.reset(); if (widget.animSpeed != 0) { _controller.repeat(); @@ -208,7 +226,10 @@ class _PanoramaState extends State with SingleTickerProviderStateMixin latitude += latitudeDelta * _dampingFactor * widget.sensitivity; latitudeDelta *= 1 - _dampingFactor * widget.sensitivity; // animate horizontal rotating - longitude += _animateDirection * longitudeDelta * _dampingFactor * widget.sensitivity; + longitude += _animateDirection * + longitudeDelta * + _dampingFactor * + widget.sensitivity; longitudeDelta *= 1 - _dampingFactor * widget.sensitivity; // animate zomming final double zoom = scene!.camera.zoom + zoomDelta * _dampingFactor; @@ -263,7 +284,8 @@ class _PanoramaState extends State with SingleTickerProviderStateMixin // rotate around the local X axis q = Quaternion.axisAngle(Vector3(1, 0, 0), -latitude) * q; - o = quaternionToOrientation(q * Quaternion.axisAngle(Vector3(0, 1, 0), math.pi * 0.5)); + o = quaternionToOrientation( + q * Quaternion.axisAngle(Vector3(0, 1, 0), math.pi * 0.5)); widget.onViewChanged?.call(degrees(o.x), degrees(-o.y), degrees(o.z)); q.rotate(scene!.camera.target..setFrom(Vector3(0, 0, -_radius))); @@ -276,14 +298,18 @@ class _PanoramaState extends State with SingleTickerProviderStateMixin _orientationSubscription?.cancel(); switch (widget.sensorControl) { case SensorControl.Orientation: - motionSensors.orientationUpdateInterval = Duration.microsecondsPerSecond ~/ 60; - _orientationSubscription = motionSensors.orientation.listen((OrientationEvent event) { + motionSensors.orientationUpdateInterval = + Duration.microsecondsPerSecond ~/ 60; + _orientationSubscription = + motionSensors.orientation.listen((OrientationEvent event) { orientation.setValues(event.yaw, event.pitch, event.roll); }); break; case SensorControl.AbsoluteOrientation: - motionSensors.absoluteOrientationUpdateInterval = Duration.microsecondsPerSecond ~/ 60; - _orientationSubscription = motionSensors.absoluteOrientation.listen((AbsoluteOrientationEvent event) { + motionSensors.absoluteOrientationUpdateInterval = + Duration.microsecondsPerSecond ~/ 60; + _orientationSubscription = motionSensors.absoluteOrientation + .listen((AbsoluteOrientationEvent event) { orientation.setValues(event.yaw, event.pitch, event.roll); }); break; @@ -292,7 +318,8 @@ class _PanoramaState extends State with SingleTickerProviderStateMixin _screenOrientSubscription?.cancel(); if (widget.sensorControl != SensorControl.None) { - _screenOrientSubscription = motionSensors.screenOrientation.listen((ScreenOrientationEvent event) { + _screenOrientSubscription = motionSensors.screenOrientation + .listen((ScreenOrientationEvent event) { screenOrientation = radians(event.angle!); }); } @@ -300,7 +327,8 @@ class _PanoramaState extends State with SingleTickerProviderStateMixin void _updateTexture(ImageInfo imageInfo, bool synchronousCall) { surface?.mesh.texture = imageInfo.image; - surface?.mesh.textureRect = Rect.fromLTWH(0, 0, imageInfo.image.width.toDouble(), imageInfo.image.height.toDouble()); + surface?.mesh.textureRect = Rect.fromLTWH(0, 0, + imageInfo.image.width.toDouble(), imageInfo.image.height.toDouble()); scene!.texture = imageInfo.image; scene!.update(); widget.onImageLoad?.call(); @@ -322,7 +350,13 @@ class _PanoramaState extends State with SingleTickerProviderStateMixin scene.camera.zoom = widget.zoom; scene.camera.position.setFrom(Vector3(0, 0, 0.1)); if (widget.child != null) { - final Mesh mesh = generateSphereMesh(radius: _radius, latSegments: widget.latSegments, lonSegments: widget.lonSegments, croppedArea: widget.croppedArea, croppedFullWidth: widget.croppedFullWidth, croppedFullHeight: widget.croppedFullHeight); + final Mesh mesh = generateSphereMesh( + radius: _radius, + latSegments: widget.latSegments, + lonSegments: widget.lonSegments, + croppedArea: widget.croppedArea, + croppedFullWidth: widget.croppedFullWidth, + croppedFullHeight: widget.croppedFullHeight); surface = Object(name: 'surface', mesh: mesh, backfaceCulling: false); _loadTexture(widget.child!.image); scene.world.add(surface!); @@ -336,23 +370,29 @@ class _PanoramaState extends State with SingleTickerProviderStateMixin Vector3 positionToLatLon(double x, double y) { // transform viewport coordinate to NDC, values between -1 and 1 - final Vector4 v = Vector4(2.0 * x / scene!.camera.viewportWidth - 1.0, 1.0 - 2.0 * y / scene!.camera.viewportHeight, 1.0, 1.0); + final Vector4 v = Vector4(2.0 * x / scene!.camera.viewportWidth - 1.0, + 1.0 - 2.0 * y / scene!.camera.viewportHeight, 1.0, 1.0); // create projection matrix - final Matrix4 m = scene!.camera.projectionMatrix * scene!.camera.lookAtMatrix; + final Matrix4 m = + scene!.camera.projectionMatrix * scene!.camera.lookAtMatrix; // apply inversed projection matrix m.invert(); v.applyMatrix4(m); // apply perspective division v.scale(1 / v.w); // get rotation from two vectors - final Quaternion q = Quaternion.fromTwoVectors(v.xyz, Vector3(0.0, 0.0, -_radius)); + final Quaternion q = + Quaternion.fromTwoVectors(v.xyz, Vector3(0.0, 0.0, -_radius)); // get euler angles from rotation - return quaternionToOrientation(q * Quaternion.axisAngle(Vector3(0, 1, 0), math.pi * 0.5)); + return quaternionToOrientation( + q * Quaternion.axisAngle(Vector3(0, 1, 0), math.pi * 0.5)); } Vector3 positionFromLatLon(double lat, double lon) { // create projection matrix - final Matrix4 m = scene!.camera.projectionMatrix * scene!.camera.lookAtMatrix * matrixFromLatLon(lat, lon); + final Matrix4 m = scene!.camera.projectionMatrix * + scene!.camera.lookAtMatrix * + matrixFromLatLon(lat, lon); // apply projection matrix final Vector4 v = Vector4(0.0, 0.0, -_radius, 1.0)..applyMatrix4(m); // apply perspective division and transform NDC to the viewport coordinate @@ -367,9 +407,12 @@ class _PanoramaState extends State with SingleTickerProviderStateMixin final List widgets = []; if (hotspots != null && scene != null) { for (Hotspot hotspot in hotspots) { - final Vector3 pos = positionFromLatLon(hotspot.latitude, hotspot.longitude); - final Offset orgin = Offset(hotspot.width * hotspot.orgin.dx, hotspot.height * hotspot.orgin.dy); - final Matrix4 transform = scene!.camera.lookAtMatrix * matrixFromLatLon(hotspot.latitude, hotspot.longitude); + final Vector3 pos = + positionFromLatLon(hotspot.latitude, hotspot.longitude); + final Offset orgin = Offset(hotspot.width * hotspot.orgin.dx, + hotspot.height * hotspot.orgin.dy); + final Matrix4 transform = scene!.camera.lookAtMatrix * + matrixFromLatLon(hotspot.latitude, hotspot.longitude); final Widget child = Positioned( left: pos.x - orgin.dx, top: pos.y - orgin.dy, @@ -400,8 +443,11 @@ class _PanoramaState extends State with SingleTickerProviderStateMixin _updateSensorControl(); - _controller = AnimationController(duration: Duration(milliseconds: 60000), vsync: this)..addListener(_updateView); - if (widget.sensorControl != SensorControl.None || widget.animSpeed != 0) _controller.repeat(); + _controller = AnimationController( + duration: Duration(milliseconds: 60000), vsync: this) + ..addListener(_updateView); + if (widget.sensorControl != SensorControl.None || widget.animSpeed != 0) + _controller.repeat(); } @override @@ -418,8 +464,18 @@ class _PanoramaState extends State with SingleTickerProviderStateMixin void didUpdateWidget(Panorama oldWidget) { super.didUpdateWidget(oldWidget); if (surface == null) return; - if (widget.latSegments != oldWidget.latSegments || widget.lonSegments != oldWidget.lonSegments || widget.croppedArea != oldWidget.croppedArea || widget.croppedFullWidth != oldWidget.croppedFullWidth || widget.croppedFullHeight != oldWidget.croppedFullHeight) { - surface!.mesh = generateSphereMesh(radius: _radius, latSegments: widget.latSegments, lonSegments: widget.lonSegments, croppedArea: widget.croppedArea, croppedFullWidth: widget.croppedFullWidth, croppedFullHeight: widget.croppedFullHeight); + if (widget.latSegments != oldWidget.latSegments || + widget.lonSegments != oldWidget.lonSegments || + widget.croppedArea != oldWidget.croppedArea || + widget.croppedFullWidth != oldWidget.croppedFullWidth || + widget.croppedFullHeight != oldWidget.croppedFullHeight) { + surface!.mesh = generateSphereMesh( + radius: _radius, + latSegments: widget.latSegments, + lonSegments: widget.lonSegments, + croppedArea: widget.croppedArea, + croppedFullWidth: widget.croppedFullWidth, + croppedFullHeight: widget.croppedFullHeight); } if (widget.child?.image != oldWidget.child?.image) { _loadTexture(widget.child?.image); @@ -448,9 +504,13 @@ class _PanoramaState extends State with SingleTickerProviderStateMixin onScaleStart: _handleScaleStart, onScaleUpdate: _handleScaleUpdate, onTapUp: widget.onTap == null ? null : _handleTapUp, - onLongPressStart: widget.onLongPressStart == null ? null : _handleLongPressStart, - onLongPressMoveUpdate: widget.onLongPressMoveUpdate == null ? null : _handleLongPressMoveUpdate, - onLongPressEnd: widget.onLongPressEnd == null ? null : _handleLongPressEnd, + onLongPressStart: + widget.onLongPressStart == null ? null : _handleLongPressStart, + onLongPressMoveUpdate: widget.onLongPressMoveUpdate == null + ? null + : _handleLongPressMoveUpdate, + onLongPressEnd: + widget.onLongPressEnd == null ? null : _handleLongPressEnd, child: pano, ) : pano; @@ -489,22 +549,33 @@ class Hotspot { Widget? widget; } -Mesh generateSphereMesh({num radius = 1.0, int latSegments = 16, int lonSegments = 16, ui.Image? texture, Rect croppedArea = const Rect.fromLTWH(0.0, 0.0, 1.0, 1.0), double croppedFullWidth = 1.0, double croppedFullHeight = 1.0}) { +Mesh generateSphereMesh( + {num radius = 1.0, + int latSegments = 16, + int lonSegments = 16, + ui.Image? texture, + Rect croppedArea = const Rect.fromLTWH(0.0, 0.0, 1.0, 1.0), + double croppedFullWidth = 1.0, + double croppedFullHeight = 1.0}) { int count = (latSegments + 1) * (lonSegments + 1); List vertices = List.filled(count, Vector3.zero()); List texcoords = List.filled(count, Offset.zero); - List indices = List.filled(latSegments * lonSegments * 2, Polygon(0, 0, 0)); + List indices = + List.filled(latSegments * lonSegments * 2, Polygon(0, 0, 0)); int i = 0; for (int y = 0; y <= latSegments; ++y) { final double tv = y / latSegments; - final double v = (croppedArea.top + croppedArea.height * tv) / croppedFullHeight; + final double v = + (croppedArea.top + croppedArea.height * tv) / croppedFullHeight; final double sv = math.sin(v * math.pi); final double cv = math.cos(v * math.pi); for (int x = 0; x <= lonSegments; ++x) { final double tu = x / lonSegments; - final double u = (croppedArea.left + croppedArea.width * tu) / croppedFullWidth; - vertices[i] = Vector3(radius * math.cos(u * math.pi * 2.0) * sv, radius * cv, radius * math.sin(u * math.pi * 2.0) * sv); + final double u = + (croppedArea.left + croppedArea.width * tu) / croppedFullWidth; + vertices[i] = Vector3(radius * math.cos(u * math.pi * 2.0) * sv, + radius * cv, radius * math.sin(u * math.pi * 2.0) * sv); texcoords[i] = Offset(tu, 1.0 - tv); i++; } @@ -520,7 +591,11 @@ Mesh generateSphereMesh({num radius = 1.0, int latSegments = 16, int lonSegments } } - final Mesh mesh = Mesh(vertices: vertices, texcoords: texcoords, indices: indices, texture: texture); + final Mesh mesh = Mesh( + vertices: vertices, + texcoords: texcoords, + indices: indices, + texture: texture); return mesh; } @@ -533,9 +608,11 @@ Vector3 quaternionToOrientation(Quaternion q) { final double y = storage[1]; final double z = storage[2]; final double w = storage[3]; - final double roll = math.atan2(-2 * (x * y - w * z), 1.0 - 2 * (x * x + z * z)); + final double roll = + math.atan2(-2 * (x * y - w * z), 1.0 - 2 * (x * x + z * z)); final double pitch = math.asin(2 * (y * z + w * x)); - final double yaw = math.atan2(-2 * (x * z - w * y), 1.0 - 2 * (x * x + y * y)); + final double yaw = + math.atan2(-2 * (x * z - w * y), 1.0 - 2 * (x * x + y * y)); return Vector3(yaw, pitch, roll); } diff --git a/pubspec.lock b/pubspec.lock deleted file mode 100644 index ae41e5e..0000000 --- a/pubspec.lock +++ /dev/null @@ -1,161 +0,0 @@ -# Generated by pub -# See https://dart.dev/tools/pub/glossary#lockfile -packages: - async: - dependency: transitive - description: - name: async - url: "https://pub.dartlang.org" - source: hosted - version: "2.5.0" - boolean_selector: - dependency: transitive - description: - name: boolean_selector - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.0" - characters: - dependency: transitive - description: - name: characters - url: "https://pub.dartlang.org" - source: hosted - version: "1.1.0" - charcode: - dependency: transitive - description: - name: charcode - url: "https://pub.dartlang.org" - source: hosted - version: "1.2.0" - clock: - dependency: transitive - description: - name: clock - url: "https://pub.dartlang.org" - source: hosted - version: "1.1.0" - collection: - dependency: transitive - description: - name: collection - url: "https://pub.dartlang.org" - source: hosted - version: "1.15.0" - fake_async: - dependency: transitive - description: - name: fake_async - url: "https://pub.dartlang.org" - source: hosted - version: "1.2.0" - flutter: - dependency: "direct main" - description: flutter - source: sdk - version: "0.0.0" - flutter_cube: - dependency: "direct main" - description: - name: flutter_cube - url: "https://pub.dartlang.org" - source: hosted - version: "0.1.1" - flutter_test: - dependency: "direct dev" - description: flutter - source: sdk - version: "0.0.0" - matcher: - dependency: transitive - description: - name: matcher - url: "https://pub.dartlang.org" - source: hosted - version: "0.12.10" - meta: - dependency: transitive - description: - name: meta - url: "https://pub.dartlang.org" - source: hosted - version: "1.3.0" - motion_sensors: - dependency: "direct main" - description: - name: motion_sensors - url: "https://pub.dartlang.org" - source: hosted - version: "0.1.0" - path: - dependency: transitive - description: - name: path - url: "https://pub.dartlang.org" - source: hosted - version: "1.8.0" - sky_engine: - dependency: transitive - description: flutter - source: sdk - version: "0.0.99" - source_span: - dependency: transitive - description: - name: source_span - url: "https://pub.dartlang.org" - source: hosted - version: "1.8.0" - stack_trace: - dependency: transitive - description: - name: stack_trace - url: "https://pub.dartlang.org" - source: hosted - version: "1.10.0" - stream_channel: - dependency: transitive - description: - name: stream_channel - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.0" - string_scanner: - dependency: transitive - description: - name: string_scanner - url: "https://pub.dartlang.org" - source: hosted - version: "1.1.0" - term_glyph: - dependency: transitive - description: - name: term_glyph - url: "https://pub.dartlang.org" - source: hosted - version: "1.2.0" - test_api: - dependency: transitive - description: - name: test_api - url: "https://pub.dartlang.org" - source: hosted - version: "0.2.19" - typed_data: - dependency: transitive - description: - name: typed_data - url: "https://pub.dartlang.org" - source: hosted - version: "1.3.0" - vector_math: - dependency: transitive - description: - name: vector_math - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.0" -sdks: - dart: ">=2.12.0 <3.0.0" - flutter: ">=1.10.0" diff --git a/pubspec.yaml b/pubspec.yaml index c734ac5..5bd47b7 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -4,13 +4,13 @@ version: 0.4.1 homepage: https://github.com/zesage/panorama environment: - sdk: '>=2.12.0 <3.0.0' + sdk: '>=2.14.0 <3.0.0' dependencies: flutter: sdk: flutter flutter_cube: ^0.1.1 - motion_sensors: ^0.1.0 + dchs_motion_sensors: ^2.0.1 dev_dependencies: flutter_test: