Compare commits

..

13 commits
master ... aves

Author SHA1 Message Date
Thibault Deckers
e55ab2e47e upgraded toolchain to JDK 21 (transitive via motion_sensors) 2026-02-24 23:43:52 +01:00
Thibault Deckers
65daf8a846 minor 2026-02-17 19:15:32 +01:00
Thibault Deckers
a4f4584dd6 upgrades 2026-02-17 00:07:19 +01:00
Thibault Deckers
56de42183e upgrades 2024-07-09 01:25:26 +02:00
Thibault Deckers
60feae7253 upgrades 2024-04-24 23:11:40 +02:00
Thibault Deckers
baada67586 upgrades 2023-08-17 22:41:31 +02:00
Thibault Deckers
dfde64310e upgrade 2023-05-08 12:39:41 +02:00
Thibault Deckers
3f43082a0c example: use flutter minSdkVersion 2023-04-30 00:13:22 +02:00
Thibault Deckers
7ed465f893 updated gradle 2023-04-20 10:12:31 +02:00
Thibault Deckers
89fbc3f1ec modified damping strategy 2023-01-14 16:23:00 +01:00
Thibault Deckers
47442e5102 updated gradle 2022-10-02 16:44:17 +02:00
Thibault Deckers
0050dc1aee fixed #25 Orientation with sensors is not working 2022-06-19 17:10:38 +09:00
Thibault Deckers
f8f8e905d9 fixed latitude / longitude initialization 2022-06-19 17:00:36 +09:00
54 changed files with 703 additions and 1468 deletions

47
analysis_options.yaml Normal file
View file

@ -0,0 +1,47 @@
include: package:flutter_lints/flutter.yaml
analyzer:
exclude:
- lib/generated_plugin_registrant.dart
# strong-mode:
# implicit-casts: false
# implicit-dynamic: false
# cf https://github.com/dart-lang/dart_style/wiki/Configuration
formatter:
page_width: 240
trailing_commas: preserve
linter:
rules:
# from 'flutter_lints', excluded
use_build_context_synchronously: false # no alternative
# from 'lints / recommended', excluded
no_leading_underscores_for_local_identifiers: false # useful for null checked variable variants
# from 'effective dart', excluded
avoid_classes_with_only_static_members: false # too strict
avoid_function_literals_in_foreach_calls: false # benefit?
lines_longer_than_80_chars: false # nope
public_member_api_docs: false # this project is not a library
# from 'effective dart', undecided
prefer_relative_imports: false # check IDE support (auto import, file move)
# from 'effective dart', included
avoid_types_on_closure_parameters: true
prefer_interpolation_to_compose_strings: true
unnecessary_lambdas: true
# from 'pedantic', included
always_declare_return_types: true
prefer_single_quotes: true
sort_child_properties_last: true
unawaited_futures: true
# `const` related, included
prefer_const_constructors: true
prefer_const_literals_to_create_immutables: true
prefer_const_declarations: true

20
example/.gitignore vendored
View file

@ -5,9 +5,12 @@
*.swp *.swp
.DS_Store .DS_Store
.atom/ .atom/
.build/
.buildlog/ .buildlog/
.history .history
.svn/ .svn/
.swiftpm/
migrate_working_dir/
# IntelliJ related # IntelliJ related
*.iml *.iml
@ -22,16 +25,21 @@
# Flutter/Dart/Pub related # Flutter/Dart/Pub related
**/doc/api/ **/doc/api/
**/ios/Flutter/.last_build_id
.dart_tool/ .dart_tool/
.flutter-plugins
.flutter-plugins-dependencies .flutter-plugins-dependencies
.packages
.pub-cache/ .pub-cache/
.pub/ .pub/
/build/ /build/
/coverage/
# Web related # Symbolication related
lib/generated_plugin_registrant.dart app.*.symbols
# Exceptions to above rules. # Obfuscation related
!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages app.*.map.json
# Android Studio will place build artifacts here
/android/app/debug
/android/app/profile
/android/app/release

View file

@ -5,3 +5,10 @@ gradle-wrapper.jar
/gradlew.bat /gradlew.bat
/local.properties /local.properties
GeneratedPluginRegistrant.java GeneratedPluginRegistrant.java
.cxx/
# Remember to never publicly share your keystore.
# See https://flutter.dev/to/reference-keystore
key.properties
**/*.keystore
**/*.jks

View file

@ -1,67 +0,0 @@
def localProperties = new Properties()
def localPropertiesFile = rootProject.file('local.properties')
if (localPropertiesFile.exists()) {
localPropertiesFile.withReader('UTF-8') { reader ->
localProperties.load(reader)
}
}
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.")
}
def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
if (flutterVersionCode == null) {
flutterVersionCode = '1'
}
def flutterVersionName = localProperties.getProperty('flutter.versionName')
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
sourceSets {
main.java.srcDirs += 'src/main/kotlin'
}
lintOptions {
disable 'InvalidPackage'
}
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
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
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 '../..'
}
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'
}

View file

@ -0,0 +1,42 @@
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")
}
android {
namespace = "com.example.example"
compileSdk = flutter.compileSdkVersion
ndkVersion = flutter.ndkVersion
compileOptions {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
kotlinOptions {
jvmTarget = JavaVersion.VERSION_17.toString()
}
defaultConfig {
applicationId = "com.example.example"
// You can update the following values to match your application needs.
// For more information, see: https://flutter.dev/to/review-gradle-config.
minSdk = flutter.minSdkVersion
targetSdk = flutter.targetSdkVersion
versionCode = flutter.versionCode
versionName = flutter.versionName
}
buildTypes {
release {
// Signing with the debug keys for now, so `flutter run --release` works.
signingConfig = signingConfigs.getByName("debug")
}
}
}
flutter {
source = "../.."
}

View file

@ -1,16 +1,11 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android">
package="com.example.example">
<!-- io.flutter.app.FlutterApplication is an android.app.Application that
calls FlutterMain.startInitialization(this); in its onCreate method.
In most cases you can leave this as-is, but you if you want to provide
additional functionality it is fine to subclass or reimplement
FlutterApplication and put your custom class here. -->
<application <application
android:name="io.flutter.app.FlutterApplication" android:name="${applicationName}"
android:label="example" android:label="example"
android:icon="@mipmap/ic_launcher"> android:icon="@mipmap/ic_launcher">
<activity <activity
android:name=".MainActivity" android:name="io.flutter.embedding.android.FlutterActivity"
android:exported="true"
android:launchMode="singleTop" android:launchMode="singleTop"
android:theme="@style/LaunchTheme" android:theme="@style/LaunchTheme"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode" android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"

View file

@ -1,12 +0,0 @@
package com.example.example
import androidx.annotation.NonNull;
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugins.GeneratedPluginRegistrant
class MainActivity: FlutterActivity() {
override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) {
GeneratedPluginRegistrant.registerWith(flutterEngine);
}
}

View file

@ -1,31 +0,0 @@
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()
}
}
rootProject.buildDir = '../build'
subprojects {
project.buildDir = "${rootProject.buildDir}/${project.name}"
}
subprojects {
project.evaluationDependsOn(':app')
}
task clean(type: Delete) {
delete rootProject.buildDir
}

View file

@ -0,0 +1,24 @@
allprojects {
repositories {
google()
mavenCentral()
}
}
val newBuildDir: Directory =
rootProject.layout.buildDirectory
.dir("../../build")
.get()
rootProject.layout.buildDirectory.value(newBuildDir)
subprojects {
val newSubprojectBuildDir: Directory = newBuildDir.dir(project.name)
project.layout.buildDirectory.value(newSubprojectBuildDir)
}
subprojects {
project.evaluationDependsOn(":app")
}
tasks.register<Delete>("clean") {
delete(rootProject.layout.buildDirectory)
}

View file

@ -1,4 +1,2 @@
org.gradle.jvmargs=-Xmx1536M org.gradle.jvmargs=-Xmx8G -XX:MaxMetaspaceSize=4G -XX:ReservedCodeCacheSize=512m -XX:+HeapDumpOnOutOfMemoryError
android.enableR8=true
android.useAndroidX=true android.useAndroidX=true
android.enableJetifier=true

View file

@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip distributionUrl=https\://services.gradle.org/distributions/gradle-8.14-all.zip

View file

@ -1,15 +0,0 @@
include ':app'
def flutterProjectRoot = rootProject.projectDir.parentFile.toPath()
def plugins = new Properties()
def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins')
if (pluginsFile.exists()) {
pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) }
}
plugins.each { name, path ->
def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile()
include ":$name"
project(":$name").projectDir = pluginDirectory
}

View file

@ -0,0 +1,26 @@
pluginManagement {
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")
repositories {
google()
mavenCentral()
gradlePluginPortal()
}
}
plugins {
id("dev.flutter.flutter-plugin-loader") version "1.0.0"
id("com.android.application") version "8.11.1" apply false
id("org.jetbrains.kotlin.android") version "2.2.20" apply false
}
include(":app")

View file

@ -1,32 +0,0 @@
*.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/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

View file

@ -1,26 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>App</string>
<key>CFBundleIdentifier</key>
<string>io.flutter.flutter.app</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>App</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1.0</string>
<key>MinimumOSVersion</key>
<string>8.0</string>
</dict>
</plist>

View file

@ -1,2 +0,0 @@
#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
#include "Generated.xcconfig"

View file

@ -1,2 +0,0 @@
#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
#include "Generated.xcconfig"

View file

@ -1,90 +0,0 @@
# Uncomment this line to define a global platform for your project
# platform :ios, '9.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 parse_KV_file(file, separator='=')
file_abs_path = File.expand_path(file)
if !File.exists? file_abs_path
return [];
end
generated_key_values = {}
skip_line_start_symbols = ["#", "/"]
File.foreach(file_abs_path) do |line|
next if skip_line_start_symbols.any? { |symbol| line =~ /^\s*#{symbol}/ }
plugin = line.split(pattern=separator)
if plugin.length == 2
podname = plugin[0].strip()
path = plugin[1].strip()
podpath = File.expand_path("#{path}", file_abs_path)
generated_key_values[podname] = podpath
else
puts "Invalid plugin specification: #{line}"
end
end
generated_key_values
end
target 'Runner' do
use_frameworks!
use_modular_headers!
# Flutter Pod
copied_flutter_dir = File.join(__dir__, 'Flutter')
copied_framework_path = File.join(copied_flutter_dir, 'Flutter.framework')
copied_podspec_path = File.join(copied_flutter_dir, 'Flutter.podspec')
unless File.exist?(copied_framework_path) && File.exist?(copied_podspec_path)
# Copy Flutter.framework and Flutter.podspec to Flutter/ to have something to link against if the xcode backend script has not run yet.
# That script will copy the correct debug/profile/release version of the framework based on the currently selected Xcode configuration.
# CocoaPods will not embed the framework on pod install (before any build phases can generate) if the dylib does not exist.
generated_xcode_build_settings_path = File.join(copied_flutter_dir, 'Generated.xcconfig')
unless File.exist?(generated_xcode_build_settings_path)
raise "Generated.xcconfig must exist. If you're running pod install manually, make sure flutter pub get is executed first"
end
generated_xcode_build_settings = parse_KV_file(generated_xcode_build_settings_path)
cached_framework_dir = generated_xcode_build_settings['FLUTTER_FRAMEWORK_DIR'];
unless File.exist?(copied_framework_path)
FileUtils.cp_r(File.join(cached_framework_dir, 'Flutter.framework'), copied_flutter_dir)
end
unless File.exist?(copied_podspec_path)
FileUtils.cp(File.join(cached_framework_dir, 'Flutter.podspec'), copied_flutter_dir)
end
end
# Keep pod path relative so it can be checked into Podfile.lock.
pod 'Flutter', :path => 'Flutter'
# Plugin Pods
# Prepare symlinks folder. We use symlinks to avoid having Podfile.lock
# referring to absolute paths on developers' machines.
system('rm -rf .symlinks')
system('mkdir -p .symlinks/plugins')
plugin_pods = parse_KV_file('../.flutter-plugins')
plugin_pods.each do |name, path|
symlink = File.join('.symlinks', 'plugins', name)
File.symlink(path, symlink)
pod name, :path => File.join(symlink, 'ios')
end
end
# Prevent Cocoapods from embedding a second Flutter framework and causing an error with the new Xcode build system.
install! 'cocoapods', :disable_input_output_paths => true
post_install do |installer|
installer.pods_project.targets.each do |target|
target.build_configurations.each do |config|
config.build_settings['ENABLE_BITCODE'] = 'NO'
end
end
end

View file

@ -1,518 +0,0 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 46;
objects = {
/* Begin PBXBuildFile section */
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
3B80C3941E831B6300D905FE /* App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; };
3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; };
9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
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 PBXCopyFilesBuildPhase section */
9705A1C41CF9048500538489 /* Embed Frameworks */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = "";
dstSubfolderSpec = 10;
files = (
3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */,
9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */,
);
name = "Embed Frameworks";
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; };
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
3B80C3931E831B6300D905FE /* App.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = App.framework; path = Flutter/App.framework; sourceTree = "<group>"; };
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = "<group>"; };
74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; };
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = "<group>"; };
9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = "<group>"; };
9740EEBA1CF902C7004384FC /* Flutter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Flutter.framework; path = Flutter/Flutter.framework; sourceTree = "<group>"; };
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 = "<group>"; };
97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
97C146EB1CF9000F007C117D /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */,
3B80C3941E831B6300D905FE /* App.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
9740EEB11CF90186004384FC /* Flutter */ = {
isa = PBXGroup;
children = (
3B80C3931E831B6300D905FE /* App.framework */,
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */,
9740EEBA1CF902C7004384FC /* Flutter.framework */,
9740EEB21CF90195004384FC /* Debug.xcconfig */,
7AFA3C8E1D35360C0083082E /* Release.xcconfig */,
9740EEB31CF90195004384FC /* Generated.xcconfig */,
);
name = Flutter;
sourceTree = "<group>";
};
97C146E51CF9000F007C117D = {
isa = PBXGroup;
children = (
9740EEB11CF90186004384FC /* Flutter */,
97C146F01CF9000F007C117D /* Runner */,
97C146EF1CF9000F007C117D /* Products */,
);
sourceTree = "<group>";
};
97C146EF1CF9000F007C117D /* Products */ = {
isa = PBXGroup;
children = (
97C146EE1CF9000F007C117D /* Runner.app */,
);
name = Products;
sourceTree = "<group>";
};
97C146F01CF9000F007C117D /* Runner */ = {
isa = PBXGroup;
children = (
97C146FA1CF9000F007C117D /* Main.storyboard */,
97C146FD1CF9000F007C117D /* Assets.xcassets */,
97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */,
97C147021CF9000F007C117D /* Info.plist */,
97C146F11CF9000F007C117D /* Supporting Files */,
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */,
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */,
74858FAE1ED2DC5600515810 /* AppDelegate.swift */,
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */,
);
path = Runner;
sourceTree = "<group>";
};
97C146F11CF9000F007C117D /* Supporting Files */ = {
isa = PBXGroup;
children = (
);
name = "Supporting Files";
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
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 = {
LastUpgradeCheck = 1020;
ORGANIZATIONNAME = "The Chromium Authors";
TargetAttributes = {
97C146ED1CF9000F007C117D = {
CreatedOnToolsVersion = 7.3.1;
LastSwiftMigration = 1100;
};
};
};
buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */;
compatibilityVersion = "Xcode 3.2";
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = 97C146E51CF9000F007C117D;
productRefGroup = 97C146EF1CF9000F007C117D /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
97C146ED1CF9000F007C117D /* Runner */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
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;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "Thin Binary";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" thin";
};
9740EEB61CF901F6004384FC /* Run Script */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "Run Script";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
};
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
97C146EA1CF9000F007C117D /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */,
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXVariantGroup section */
97C146FA1CF9000F007C117D /* Main.storyboard */ = {
isa = PBXVariantGroup;
children = (
97C146FB1CF9000F007C117D /* Base */,
);
name = Main.storyboard;
sourceTree = "<group>";
};
97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = {
isa = PBXVariantGroup;
children = (
97C147001CF9000F007C117D /* Base */,
);
name = LaunchScreen.storyboard;
sourceTree = "<group>";
};
/* End PBXVariantGroup section */
/* Begin XCBuildConfiguration section */
249021D3217E4FDB00AE95B9 /* Profile */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
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;
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 = 8.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;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
);
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
LIBRARY_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
);
PRODUCT_BUNDLE_IDENTIFIER = com.example.example;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 5.0;
VERSIONING_SYSTEM = "apple-generic";
};
name = Profile;
};
97C147031CF9000F007C117D /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
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;
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 = 8.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Debug;
};
97C147041CF9000F007C117D /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
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;
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 = 8.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SUPPORTED_PLATFORMS = iphoneos;
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
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;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
);
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
LIBRARY_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
);
PRODUCT_BUNDLE_IDENTIFIER = com.example.example;
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;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
);
INFOPLIST_FILE = Runner/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
LIBRARY_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
);
PRODUCT_BUNDLE_IDENTIFIER = com.example.example;
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 */
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 */;
}

View file

@ -1,7 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "group:Runner.xcodeproj">
</FileRef>
</Workspace>

View file

@ -1,91 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1020"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Profile"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

View file

@ -1,7 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "group:Runner.xcodeproj">
</FileRef>
</Workspace>

View file

@ -1,13 +0,0 @@
import UIKit
import Flutter
@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)
}
}

View file

@ -1,122 +0,0 @@
{
"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"
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 564 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

View file

@ -1,23 +0,0 @@
{
"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"
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 68 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 68 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 68 B

View file

@ -1,5 +0,0 @@
# 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.

View file

@ -1,37 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="12121" systemVersion="16G29" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="12089"/>
</dependencies>
<scenes>
<!--View Controller-->
<scene sceneID="EHf-IW-A2E">
<objects>
<viewController id="01J-lp-oVM" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="Ydg-fD-yQy"/>
<viewControllerLayoutGuide type="bottom" id="xbc-2k-c8Z"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<imageView opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" image="LaunchImage" translatesAutoresizingMaskIntoConstraints="NO" id="YRO-k0-Ey4">
</imageView>
</subviews>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="YRO-k0-Ey4" firstAttribute="centerX" secondItem="Ze5-6b-2t3" secondAttribute="centerX" id="1a2-6s-vTC"/>
<constraint firstItem="YRO-k0-Ey4" firstAttribute="centerY" secondItem="Ze5-6b-2t3" secondAttribute="centerY" id="4X2-HB-R7a"/>
</constraints>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="53" y="375"/>
</scene>
</scenes>
<resources>
<image name="LaunchImage" width="168" height="185"/>
</resources>
</document>

View file

@ -1,26 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="10117" systemVersion="15F34" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="BYZ-38-t0r">
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="10085"/>
</dependencies>
<scenes>
<!--Flutter View Controller-->
<scene sceneID="tne-QT-ifu">
<objects>
<viewController id="BYZ-38-t0r" customClass="FlutterViewController" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="y3c-jy-aDJ"/>
<viewControllerLayoutGuide type="bottom" id="wfy-db-euE"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
</objects>
</scene>
</scenes>
</document>

View file

@ -1,45 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>example</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>$(FLUTTER_BUILD_NAME)</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>$(FLUTTER_BUILD_NUMBER)</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIMainStoryboardFile</key>
<string>Main</string>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UIViewControllerBasedStatusBarAppearance</key>
<false/>
</dict>
</plist>

View file

@ -1 +0,0 @@
#import "GeneratedPluginRegistrant.h"

View file

@ -1,28 +1,31 @@
import 'dart:io'; import 'dart:io';
import 'package:flutter/material.dart';
import 'package:panorama/panorama.dart';
import 'package:image_picker/image_picker.dart';
void main() => runApp(MyApp()); import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
import 'package:panorama/panorama.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget { class MyApp extends StatelessWidget {
const MyApp({super.key});
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return MaterialApp( return MaterialApp(
title: 'Flutter Panorama', title: 'Flutter Panorama',
theme: ThemeData.dark(), theme: ThemeData.dark(),
home: MyHomePage(title: 'Flutter Panorama'), home: const MyHomePage(title: 'Flutter Panorama'),
); );
} }
} }
class MyHomePage extends StatefulWidget { class MyHomePage extends StatefulWidget {
MyHomePage({Key? key, this.title}) : super(key: key); const MyHomePage({super.key, this.title});
final String? title; final String? title;
@override @override
_MyHomePageState createState() => _MyHomePageState(); State<MyHomePage> createState() => _MyHomePageState();
} }
class _MyHomePageState extends State<MyHomePage> { class _MyHomePageState extends State<MyHomePage> {
@ -37,7 +40,7 @@ class _MyHomePageState extends State<MyHomePage> {
]; ];
ImagePicker picker = ImagePicker(); ImagePicker picker = ImagePicker();
void onViewChanged(longitude, latitude, tilt) { void onViewChanged(double longitude, double latitude, double tilt) {
setState(() { setState(() {
_lon = longitude; _lon = longitude;
_lat = latitude; _lat = latitude;
@ -51,17 +54,17 @@ class _MyHomePageState extends State<MyHomePage> {
children: [ children: [
TextButton( TextButton(
style: ButtonStyle( style: ButtonStyle(
shape: MaterialStateProperty.all(CircleBorder()), shape: WidgetStateProperty.all(const CircleBorder()),
backgroundColor: MaterialStateProperty.all(Colors.black38), backgroundColor: WidgetStateProperty.all(Colors.black38),
foregroundColor: MaterialStateProperty.all(Colors.white), foregroundColor: WidgetStateProperty.all(Colors.white),
), ),
child: Icon(icon),
onPressed: onPressed, onPressed: onPressed,
child: Icon(icon),
), ),
text != null text != null
? Container( ? Container(
padding: EdgeInsets.all(4.0), padding: const EdgeInsets.all(4.0),
decoration: BoxDecoration(color: Colors.black38, borderRadius: BorderRadius.all(Radius.circular(4))), decoration: const BoxDecoration(color: Colors.black38, borderRadius: BorderRadius.all(Radius.circular(4))),
child: Center(child: Text(text)), child: Center(child: Text(text)),
) )
: Container(), : Container(),
@ -75,21 +78,19 @@ class _MyHomePageState extends State<MyHomePage> {
switch (_panoId % panoImages.length) { switch (_panoId % panoImages.length) {
case 0: case 0:
panorama = Panorama( panorama = Panorama(
animSpeed: 1.0, sensorControl: SensorControl.orientation,
sensorControl: SensorControl.Orientation,
onViewChanged: onViewChanged, onViewChanged: onViewChanged,
onTap: (longitude, latitude, tilt) => print('onTap: $longitude, $latitude, $tilt'), onTap: (longitude, latitude, tilt) => debugPrint('onTap: $longitude, $latitude, $tilt'),
onLongPressStart: (longitude, latitude, tilt) => print('onLongPressStart: $longitude, $latitude, $tilt'), onLongPressStart: (longitude, latitude, tilt) => debugPrint('onLongPressStart: $longitude, $latitude, $tilt'),
onLongPressMoveUpdate: (longitude, latitude, tilt) => print('onLongPressMoveUpdate: $longitude, $latitude, $tilt'), onLongPressMoveUpdate: (longitude, latitude, tilt) => debugPrint('onLongPressMoveUpdate: $longitude, $latitude, $tilt'),
onLongPressEnd: (longitude, latitude, tilt) => print('onLongPressEnd: $longitude, $latitude, $tilt'), onLongPressEnd: (longitude, latitude, tilt) => debugPrint('onLongPressEnd: $longitude, $latitude, $tilt'),
child: Image.asset('assets/panorama.jpg'),
hotspots: [ hotspots: [
Hotspot( Hotspot(
latitude: -15.0, latitude: -15.0,
longitude: -129.0, longitude: -129.0,
width: 90, width: 90,
height: 75, 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( Hotspot(
latitude: -42.0, latitude: -42.0,
@ -106,43 +107,42 @@ class _MyHomePageState extends State<MyHomePage> {
widget: hotspotButton(icon: Icons.arrow_upward, onPressed: () {}), widget: hotspotButton(icon: Icons.arrow_upward, onPressed: () {}),
), ),
], ],
child: Image.asset('assets/panorama.jpg'),
); );
break; break;
case 2: case 2:
panorama = Panorama( panorama = Panorama(
animSpeed: 1.0, sensorControl: SensorControl.orientation,
sensorControl: SensorControl.Orientation,
onViewChanged: onViewChanged, onViewChanged: onViewChanged,
croppedArea: Rect.fromLTWH(2533.0, 1265.0, 5065.0, 2533.0), croppedArea: const Rect.fromLTWH(2533.0, 1265.0, 5065.0, 2533.0),
croppedFullWidth: 10132.0, croppedFullWidth: 10132.0,
croppedFullHeight: 5066.0, croppedFullHeight: 5066.0,
child: Image.asset('assets/panorama_cropped.jpg'),
hotspots: [ hotspots: [
Hotspot( Hotspot(
latitude: 0.0, latitude: 0.0,
longitude: -46.0, longitude: -46.0,
width: 90.0, width: 90.0,
height: 75.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++)),
), ),
], ],
child: Image.asset('assets/panorama_cropped.jpg'),
); );
break; break;
default: default:
panorama = Panorama( panorama = Panorama(
animSpeed: 1.0, sensorControl: SensorControl.orientation,
sensorControl: SensorControl.Orientation,
onViewChanged: onViewChanged, onViewChanged: onViewChanged,
child: panoImages[_panoId % panoImages.length],
hotspots: [ hotspots: [
Hotspot( Hotspot(
latitude: 0.0, latitude: 0.0,
longitude: 160.0, longitude: 160.0,
width: 90.0, width: 90.0,
height: 75.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++)),
), ),
], ],
child: panoImages[_panoId % panoImages.length],
); );
} }
return Scaffold( return Scaffold(
@ -158,7 +158,7 @@ class _MyHomePageState extends State<MyHomePage> {
floatingActionButton: FloatingActionButton( floatingActionButton: FloatingActionButton(
mini: true, mini: true,
onPressed: () async { onPressed: () async {
final pickedFile = await picker.getImage(source: ImageSource.gallery); final pickedFile = await picker.pickImage(source: ImageSource.gallery);
setState(() { setState(() {
if (pickedFile != null) { if (pickedFile != null) {
panoImages.add(Image.file(File(pickedFile.path))); panoImages.add(Image.file(File(pickedFile.path)));
@ -166,7 +166,7 @@ class _MyHomePageState extends State<MyHomePage> {
} }
}); });
}, },
child: Icon(Icons.panorama), child: const Icon(Icons.panorama),
), ),
); );
} }

View file

@ -5,51 +5,90 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: async name: async
url: "https://pub.dartlang.org" sha256: "758e6d74e971c3e5aceb4110bfd6698efc7f501675bcfe0c775459a8140750eb"
url: "https://pub.dev"
source: hosted source: hosted
version: "2.5.0" version: "2.13.0"
boolean_selector: boolean_selector:
dependency: transitive dependency: transitive
description: description:
name: boolean_selector name: boolean_selector
url: "https://pub.dartlang.org" sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea"
url: "https://pub.dev"
source: hosted source: hosted
version: "2.1.0" version: "2.1.2"
characters: characters:
dependency: transitive dependency: transitive
description: description:
name: characters name: characters
url: "https://pub.dartlang.org" sha256: faf38497bda5ead2a8c7615f4f7939df04333478bf32e4173fcb06d428b5716b
url: "https://pub.dev"
source: hosted source: hosted
version: "1.1.0" version: "1.4.1"
charcode:
dependency: transitive
description:
name: charcode
url: "https://pub.dartlang.org"
source: hosted
version: "1.2.0"
clock: clock:
dependency: transitive dependency: transitive
description: description:
name: clock name: clock
url: "https://pub.dartlang.org" sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b
url: "https://pub.dev"
source: hosted source: hosted
version: "1.1.0" version: "1.1.2"
collection: collection:
dependency: transitive dependency: transitive
description: description:
name: collection name: collection
url: "https://pub.dartlang.org" sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76"
url: "https://pub.dev"
source: hosted source: hosted
version: "1.15.0" version: "1.19.1"
cross_file:
dependency: transitive
description:
name: cross_file
sha256: "28bb3ae56f117b5aec029d702a90f57d285cd975c3c5c281eaca38dbc47c5937"
url: "https://pub.dev"
source: hosted
version: "0.3.5+2"
fake_async: fake_async:
dependency: transitive dependency: transitive
description: description:
name: fake_async name: fake_async
url: "https://pub.dartlang.org" sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44"
url: "https://pub.dev"
source: hosted source: hosted
version: "1.2.0" version: "1.3.3"
file_selector_linux:
dependency: transitive
description:
name: file_selector_linux
sha256: "2567f398e06ac72dcf2e98a0c95df2a9edd03c2c2e0cacd4780f20cdf56263a0"
url: "https://pub.dev"
source: hosted
version: "0.9.4"
file_selector_macos:
dependency: transitive
description:
name: file_selector_macos
sha256: "5e0bbe9c312416f1787a68259ea1505b52f258c587f12920422671807c4d618a"
url: "https://pub.dev"
source: hosted
version: "0.9.5"
file_selector_platform_interface:
dependency: transitive
description:
name: file_selector_platform_interface
sha256: "35e0bd61ebcdb91a3505813b055b09b79dfdc7d0aee9c09a7ba59ae4bb13dc85"
url: "https://pub.dev"
source: hosted
version: "2.7.0"
file_selector_windows:
dependency: transitive
description:
name: file_selector_windows
sha256: "62197474ae75893a62df75939c777763d39c2bc5f73ce5b88497208bc269abfd"
url: "https://pub.dev"
source: hosted
version: "0.9.3+5"
flutter: flutter:
dependency: "direct main" dependency: "direct main"
description: flutter description: flutter
@ -59,69 +98,172 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: flutter_cube name: flutter_cube
url: "https://pub.dartlang.org" sha256: "71cf679a251166eb97f86751c56582b09abdbf859485fbf60524948813914c3b"
url: "https://pub.dev"
source: hosted source: hosted
version: "0.1.1" version: "0.1.1"
flutter_plugin_android_lifecycle: flutter_plugin_android_lifecycle:
dependency: transitive dependency: transitive
description: description:
name: flutter_plugin_android_lifecycle name: flutter_plugin_android_lifecycle
url: "https://pub.dartlang.org" sha256: ee8068e0e1cd16c4a82714119918efdeed33b3ba7772c54b5d094ab53f9b7fd1
url: "https://pub.dev"
source: hosted source: hosted
version: "2.0.0" version: "2.0.33"
flutter_test: flutter_test:
dependency: "direct dev" dependency: "direct dev"
description: flutter description: flutter
source: sdk source: sdk
version: "0.0.0" version: "0.0.0"
flutter_web_plugins:
dependency: transitive
description: flutter
source: sdk
version: "0.0.0"
http: http:
dependency: transitive dependency: transitive
description: description:
name: http name: http
url: "https://pub.dartlang.org" sha256: "87721a4a50b19c7f1d49001e51409bddc46303966ce89a65af4f4e6004896412"
url: "https://pub.dev"
source: hosted source: hosted
version: "0.13.0" version: "1.6.0"
http_parser: http_parser:
dependency: transitive dependency: transitive
description: description:
name: http_parser name: http_parser
url: "https://pub.dartlang.org" sha256: "178d74305e7866013777bab2c3d8726205dc5a4dd935297175b19a23a2e66571"
url: "https://pub.dev"
source: hosted source: hosted
version: "4.0.0" version: "4.1.2"
image_picker: image_picker:
dependency: "direct main" dependency: "direct main"
description: description:
name: image_picker name: image_picker
url: "https://pub.dartlang.org" sha256: "784210112be18ea55f69d7076e2c656a4e24949fa9e76429fe53af0c0f4fa320"
url: "https://pub.dev"
source: hosted source: hosted
version: "0.7.2+1" version: "1.2.1"
image_picker_android:
dependency: transitive
description:
name: image_picker_android
sha256: eda9b91b7e266d9041084a42d605a74937d996b87083395c5e47835916a86156
url: "https://pub.dev"
source: hosted
version: "0.8.13+14"
image_picker_for_web:
dependency: transitive
description:
name: image_picker_for_web
sha256: "66257a3191ab360d23a55c8241c91a6e329d31e94efa7be9cf7a212e65850214"
url: "https://pub.dev"
source: hosted
version: "3.1.1"
image_picker_ios:
dependency: transitive
description:
name: image_picker_ios
sha256: b9c4a438a9ff4f60808c9cf0039b93a42bb6c2211ef6ebb647394b2b3fa84588
url: "https://pub.dev"
source: hosted
version: "0.8.13+6"
image_picker_linux:
dependency: transitive
description:
name: image_picker_linux
sha256: "1f81c5f2046b9ab724f85523e4af65be1d47b038160a8c8deed909762c308ed4"
url: "https://pub.dev"
source: hosted
version: "0.2.2"
image_picker_macos:
dependency: transitive
description:
name: image_picker_macos
sha256: "86f0f15a309de7e1a552c12df9ce5b59fe927e71385329355aec4776c6a8ec91"
url: "https://pub.dev"
source: hosted
version: "0.2.2+1"
image_picker_platform_interface: image_picker_platform_interface:
dependency: transitive dependency: transitive
description: description:
name: image_picker_platform_interface name: image_picker_platform_interface
url: "https://pub.dartlang.org" sha256: "567e056716333a1647c64bb6bd873cff7622233a5c3f694be28a583d4715690c"
url: "https://pub.dev"
source: hosted source: hosted
version: "2.0.1" version: "2.11.1"
image_picker_windows:
dependency: transitive
description:
name: image_picker_windows
sha256: d248c86554a72b5495a31c56f060cf73a41c7ff541689327b1a7dbccc33adfae
url: "https://pub.dev"
source: hosted
version: "0.2.2"
leak_tracker:
dependency: transitive
description:
name: leak_tracker
sha256: "33e2e26bdd85a0112ec15400c8cbffea70d0f9c3407491f672a2fad47915e2de"
url: "https://pub.dev"
source: hosted
version: "11.0.2"
leak_tracker_flutter_testing:
dependency: transitive
description:
name: leak_tracker_flutter_testing
sha256: "1dbc140bb5a23c75ea9c4811222756104fbcd1a27173f0c34ca01e16bea473c1"
url: "https://pub.dev"
source: hosted
version: "3.0.10"
leak_tracker_testing:
dependency: transitive
description:
name: leak_tracker_testing
sha256: "8d5a2d49f4a66b49744b23b018848400d23e54caf9463f4eb20df3eb8acb2eb1"
url: "https://pub.dev"
source: hosted
version: "3.0.2"
matcher: matcher:
dependency: transitive dependency: transitive
description: description:
name: matcher name: matcher
url: "https://pub.dartlang.org" sha256: "12956d0ad8390bbcc63ca2e1469c0619946ccb52809807067a7020d57e647aa6"
url: "https://pub.dev"
source: hosted source: hosted
version: "0.12.10" version: "0.12.18"
material_color_utilities:
dependency: transitive
description:
name: material_color_utilities
sha256: "9c337007e82b1889149c82ed242ed1cb24a66044e30979c44912381e9be4c48b"
url: "https://pub.dev"
source: hosted
version: "0.13.0"
meta: meta:
dependency: transitive dependency: transitive
description: description:
name: meta name: meta
url: "https://pub.dartlang.org" sha256: "23f08335362185a5ea2ad3a4e597f1375e78bce8a040df5c600c8d3552ef2394"
url: "https://pub.dev"
source: hosted source: hosted
version: "1.3.0" version: "1.17.0"
mime:
dependency: transitive
description:
name: mime
sha256: "41a20518f0cb1256669420fdba0cd90d21561e560ac240f26ef8322e45bb7ed6"
url: "https://pub.dev"
source: hosted
version: "2.0.0"
motion_sensors: motion_sensors:
dependency: transitive dependency: transitive
description: description:
name: motion_sensors path: "."
url: "https://pub.dartlang.org" ref: aves
source: hosted resolved-ref: "400fa42826e22a156b69a5d52926ce5681ab9b45"
url: "https://github.com/deckerst/aves_panorama_motion_sensors.git"
source: git
version: "0.1.0" version: "0.1.0"
panorama: panorama:
dependency: "direct main" dependency: "direct main"
@ -129,89 +271,108 @@ packages:
path: ".." path: ".."
relative: true relative: true
source: path source: path
version: "0.4.0" version: "0.4.1"
path: path:
dependency: transitive dependency: transitive
description: description:
name: path name: path
url: "https://pub.dartlang.org" sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5"
url: "https://pub.dev"
source: hosted source: hosted
version: "1.8.0" version: "1.9.1"
pedantic:
dependency: transitive
description:
name: pedantic
url: "https://pub.dartlang.org"
source: hosted
version: "1.11.0"
plugin_platform_interface: plugin_platform_interface:
dependency: transitive dependency: transitive
description: description:
name: plugin_platform_interface name: plugin_platform_interface
url: "https://pub.dartlang.org" sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02"
url: "https://pub.dev"
source: hosted source: hosted
version: "2.0.0" version: "2.1.8"
sky_engine: sky_engine:
dependency: transitive dependency: transitive
description: flutter description: flutter
source: sdk source: sdk
version: "0.0.99" version: "0.0.0"
source_span: source_span:
dependency: transitive dependency: transitive
description: description:
name: source_span name: source_span
url: "https://pub.dartlang.org" sha256: "56a02f1f4cd1a2d96303c0144c93bd6d909eea6bee6bf5a0e0b685edbd4c47ab"
url: "https://pub.dev"
source: hosted source: hosted
version: "1.8.0" version: "1.10.2"
stack_trace: stack_trace:
dependency: transitive dependency: transitive
description: description:
name: stack_trace name: stack_trace
url: "https://pub.dartlang.org" sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1"
url: "https://pub.dev"
source: hosted source: hosted
version: "1.10.0" version: "1.12.1"
stream_channel: stream_channel:
dependency: transitive dependency: transitive
description: description:
name: stream_channel name: stream_channel
url: "https://pub.dartlang.org" sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d"
url: "https://pub.dev"
source: hosted source: hosted
version: "2.1.0" version: "2.1.4"
string_scanner: string_scanner:
dependency: transitive dependency: transitive
description: description:
name: string_scanner name: string_scanner
url: "https://pub.dartlang.org" sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43"
url: "https://pub.dev"
source: hosted source: hosted
version: "1.1.0" version: "1.4.1"
term_glyph: term_glyph:
dependency: transitive dependency: transitive
description: description:
name: term_glyph name: term_glyph
url: "https://pub.dartlang.org" sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e"
url: "https://pub.dev"
source: hosted source: hosted
version: "1.2.0" version: "1.2.2"
test_api: test_api:
dependency: transitive dependency: transitive
description: description:
name: test_api name: test_api
url: "https://pub.dartlang.org" sha256: "93167629bfc610f71560ab9312acdda4959de4df6fac7492c89ff0d3886f6636"
url: "https://pub.dev"
source: hosted source: hosted
version: "0.2.19" version: "0.7.9"
typed_data: typed_data:
dependency: transitive dependency: transitive
description: description:
name: typed_data name: typed_data
url: "https://pub.dartlang.org" sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006
url: "https://pub.dev"
source: hosted source: hosted
version: "1.3.0" version: "1.4.0"
vector_math: vector_math:
dependency: transitive dependency: transitive
description: description:
name: vector_math name: vector_math
url: "https://pub.dartlang.org" sha256: d530bd74fea330e6e364cda7a85019c434070188383e1cd8d9777ee586914c5b
url: "https://pub.dev"
source: hosted source: hosted
version: "2.1.0" version: "2.2.0"
vm_service:
dependency: transitive
description:
name: vm_service
sha256: "45caa6c5917fa127b5dbcfbd1fa60b14e583afdc08bfc96dda38886ca252eb60"
url: "https://pub.dev"
source: hosted
version: "15.0.2"
web:
dependency: transitive
description:
name: web
sha256: "868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a"
url: "https://pub.dev"
source: hosted
version: "1.1.1"
sdks: sdks:
dart: ">=2.12.0 <3.0.0" dart: ">=3.11.0 <4.0.0"
flutter: ">=1.20.0" flutter: ">=3.38.0"

View file

@ -1,25 +1,23 @@
name: example name: example
description: A new Flutter project. description: A new Flutter project.
version: 1.0.0+1 version: 1.0.0+1
publish_to: none
environment: environment:
sdk: '>=2.12.0 <3.0.0' sdk: ">=3.11.0 <4.0.0"
dependencies: dependencies:
flutter: flutter:
sdk: flutter sdk: flutter
panorama: panorama:
path: ../ path: ../
image_picker: ^0.7.2+1 image_picker:
dev_dependencies: dev_dependencies:
flutter_test: flutter_test:
sdk: flutter sdk: flutter
flutter: flutter:
uses-material-design: true uses-material-design: true
assets: assets:
- assets/ - assets/
publish_to: none

View file

@ -1,26 +1,25 @@
library panorama;
import 'dart:async'; import 'dart:async';
import 'dart:ui' as ui;
import 'dart:math' as math; import 'dart:math' as math;
import 'dart:ui' as ui;
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_cube/flutter_cube.dart'; import 'package:flutter_cube/flutter_cube.dart';
import 'package:motion_sensors/motion_sensors.dart'; import 'package:motion_sensors/motion_sensors.dart';
enum SensorControl { enum SensorControl {
/// No sensor used. /// No sensor used.
None, none,
/// Use gyroscope and accelerometer. /// Use gyroscope and accelerometer.
Orientation, orientation,
/// Use magnetometer and accelerometer. The logitude 0 points to north. /// Use magnetometer and accelerometer. The longitude 0 points to north.
AbsoluteOrientation, absoluteOrientation,
} }
class Panorama extends StatefulWidget { class Panorama extends StatefulWidget {
Panorama({ const Panorama({
Key? key, super.key,
this.latitude = 0, this.latitude = 0,
this.longitude = 0, this.longitude = 0,
this.zoom = 1.0, this.zoom = 1.0,
@ -30,13 +29,12 @@ class Panorama extends StatefulWidget {
this.maxLongitude = 180.0, this.maxLongitude = 180.0,
this.minZoom = 1.0, this.minZoom = 1.0,
this.maxZoom = 5.0, this.maxZoom = 5.0,
this.sensitivity = 1.0, this.panInertia = 0.05,
this.animSpeed = 0.0,
this.animReverse = true, this.animReverse = true,
this.latSegments = 32, this.latSegments = 32,
this.lonSegments = 64, this.lonSegments = 64,
this.interactive = true, this.interactive = true,
this.sensorControl = SensorControl.None, this.sensorControl = SensorControl.none,
this.croppedArea = const Rect.fromLTWH(0.0, 0.0, 1.0, 1.0), this.croppedArea = const Rect.fromLTWH(0.0, 0.0, 1.0, 1.0),
this.croppedFullWidth = 1.0, this.croppedFullWidth = 1.0,
this.croppedFullHeight = 1.0, this.croppedFullHeight = 1.0,
@ -48,7 +46,7 @@ class Panorama extends StatefulWidget {
this.onImageLoad, this.onImageLoad,
this.child, this.child,
this.hotspots, this.hotspots,
}) : super(key: key); });
/// The initial latitude, in degrees, between -90 and 90. default to 0 (the vertical center of the image). /// The initial latitude, in degrees, between -90 and 90. default to 0 (the vertical center of the image).
final double latitude; final double latitude;
@ -71,17 +69,14 @@ class Panorama extends StatefulWidget {
/// The maximal longitude to show. default to 180.0 /// The maximal longitude to show. default to 180.0
final double maxLongitude; final double maxLongitude;
/// The minimal zomm. default to 1.0 /// The minimal zoom. default to 1.0
final double minZoom; final double minZoom;
/// The maximal zomm. default to 5.0 /// The maximal zoom. default to 5.0
final double maxZoom; final double maxZoom;
/// The sensitivity of the gesture. default to 1.0 /// default to 0.05
final double sensitivity; final double panInertia;
/// The Speed of rotation by animation. default to 0.0
final double animSpeed;
/// Reverse rotation when the current longitude reaches the minimal or maximum. default to true /// Reverse rotation when the current longitude reaches the minimal or maximum. default to true
final bool animReverse; final bool animReverse;
@ -132,30 +127,34 @@ class Panorama extends StatefulWidget {
final List<Hotspot>? hotspots; final List<Hotspot>? hotspots;
@override @override
_PanoramaState createState() => _PanoramaState(); State<Panorama> createState() => _PanoramaState();
} }
class _PanoramaState extends State<Panorama> with SingleTickerProviderStateMixin { class _PanoramaState extends State<Panorama> with SingleTickerProviderStateMixin {
Scene? scene; Scene? scene;
Object? surface; Object? surface;
late double latitude; late double latitudeRad;
late double longitude; late double longitudeRad;
double latitudeDelta = 0; double latitudeDelta = 0;
double longitudeDelta = 0; double longitudeDelta = 0;
double zoomDelta = 0; double zoomDelta = 0;
late Offset _lastFocalPoint; late Offset _lastFocalPoint;
double? _lastZoom; double? _lastZoom;
double _radius = 500; final double _animateDirection = 1.0;
double _dampingFactor = 0.05;
double _animateDirection = 1.0;
late AnimationController _controller; late AnimationController _controller;
double screenOrientation = 0.0; double screenOrientationRad = 0.0;
Vector3 orientation = Vector3(0, radians(90), 0); Vector3 orientation = Vector3(0, radians(90), 0);
StreamSubscription? _orientationSubscription; StreamSubscription? _orientationSubscription;
StreamSubscription? _screenOrientSubscription; StreamSubscription? _screenOrientSubscription;
late StreamController<Null> _streamController; late StreamController<Null> _streamController;
Stream<Null>? _stream; Stream<Null>? _stream;
ImageStream? _imageStream; ImageStream? _imageStream;
bool _scaling = false;
static const double _halfPi = math.pi * .5;
static const double _epsilon = .001;
static const double _radius = 500;
static const double _panReactivity = .8;
void _handleTapUp(TapUpDetails details) { void _handleTapUp(TapUpDetails details) {
final Vector3 o = positionToLatLon(details.localPosition.dx, details.localPosition.dy); final Vector3 o = positionToLatLon(details.localPosition.dx, details.localPosition.dy);
@ -180,55 +179,71 @@ class _PanoramaState extends State<Panorama> with SingleTickerProviderStateMixin
void _handleScaleStart(ScaleStartDetails details) { void _handleScaleStart(ScaleStartDetails details) {
_lastFocalPoint = details.localFocalPoint; _lastFocalPoint = details.localFocalPoint;
_lastZoom = null; _lastZoom = null;
_scaling = true;
} }
void _handleScaleUpdate(ScaleUpdateDetails details) { void _handleScaleUpdate(ScaleUpdateDetails details) {
final offset = details.localFocalPoint - _lastFocalPoint; final offset = details.localFocalPoint - _lastFocalPoint;
_lastFocalPoint = details.localFocalPoint; _lastFocalPoint = details.localFocalPoint;
latitudeDelta += widget.sensitivity * 0.5 * math.pi * offset.dy / scene!.camera.viewportHeight; _updatePositionDeltaForOffset(offset);
longitudeDelta -= widget.sensitivity * _animateDirection * 0.5 * math.pi * offset.dx / scene!.camera.viewportHeight;
if (_lastZoom == null) { final zoom = scene!.camera.zoom;
_lastZoom = scene!.camera.zoom; _lastZoom ??= zoom;
} zoomDelta += _lastZoom! * details.scale - (zoom + zoomDelta);
zoomDelta += _lastZoom! * details.scale - (scene!.camera.zoom + zoomDelta);
if (widget.sensorControl == SensorControl.None && !_controller.isAnimating) { if (widget.sensorControl == SensorControl.none && !_controller.isAnimating) {
_controller.reset(); _controller.reset();
if (widget.animSpeed != 0) { _controller.forward();
_controller.repeat();
} else
_controller.forward();
} }
} }
void _handleScaleEnd(ScaleEndDetails details) {
final offset = details.velocity.pixelsPerSecond / 10;
_updatePositionDeltaForOffset(offset);
_scaling = false;
}
void _updatePositionDeltaForOffset(ui.Offset offset) {
final camera = scene!.camera;
final sensitivity = 1 / camera.zoom;
final viewportHeight = camera.viewportHeight;
latitudeDelta += sensitivity * _halfPi * offset.dy / viewportHeight;
longitudeDelta -= sensitivity * _animateDirection * _halfPi * offset.dx / viewportHeight;
}
void _updateView() { void _updateView() {
if (scene == null) return; if (scene == null) return;
// auto rotate
longitudeDelta += 0.001 * widget.animSpeed; final camera = scene!.camera;
final damping = _scaling ? _panReactivity : widget.panInertia;
// animate vertical rotating // animate vertical rotating
latitude += latitudeDelta * _dampingFactor * widget.sensitivity; latitudeRad += latitudeDelta * damping;
latitudeDelta *= 1 - _dampingFactor * widget.sensitivity; latitudeDelta *= 1 - damping;
// animate horizontal rotating // animate horizontal rotating
longitude += _animateDirection * longitudeDelta * _dampingFactor * widget.sensitivity; longitudeRad += _animateDirection * longitudeDelta * damping;
longitudeDelta *= 1 - _dampingFactor * widget.sensitivity; longitudeDelta *= 1 - damping;
// animate zomming
final double zoom = scene!.camera.zoom + zoomDelta * _dampingFactor; // animate zooming
zoomDelta *= 1 - _dampingFactor; final double zoom = camera.zoom + zoomDelta * damping;
scene!.camera.zoom = zoom.clamp(widget.minZoom, widget.maxZoom); zoomDelta *= 1 - damping;
camera.zoom = zoom.clamp(widget.minZoom, widget.maxZoom);
// stop animation if not needed // stop animation if not needed
if (latitudeDelta.abs() < 0.001 && if (latitudeDelta.abs() < _epsilon && longitudeDelta.abs() < _epsilon && zoomDelta.abs() < _epsilon) {
longitudeDelta.abs() < 0.001 && if (widget.sensorControl == SensorControl.none && _controller.isAnimating) {
zoomDelta.abs() < 0.001) { _controller.stop();
if (widget.sensorControl == SensorControl.None && }
widget.animSpeed == 0 &&
_controller.isAnimating) _controller.stop();
} }
// rotate for screen orientation // rotate for screen orientation
Quaternion q = Quaternion.axisAngle(Vector3(0, 0, 1), screenOrientation); Quaternion q = Quaternion.axisAngle(Vector3(0, 0, 1), screenOrientationRad);
// rotate for device orientation // rotate for device orientation
q *= Quaternion.euler(-orientation.z, -orientation.y, -orientation.x); q *= Quaternion.euler(-orientation.z, -orientation.y, -orientation.x);
// rotate to latitude zero // rotate to latitude zero
q *= Quaternion.axisAngle(Vector3(1, 0, 0), math.pi * 0.5); q *= Quaternion.axisAngle(Vector3(1, 0, 0), _halfPi);
// check and limit the rotation range // check and limit the rotation range
Vector3 o = quaternionToOrientation(q); Vector3 o = quaternionToOrientation(q);
@ -238,18 +253,11 @@ class _PanoramaState extends State<Panorama> with SingleTickerProviderStateMixin
final double maxLon = radians(widget.maxLongitude); final double maxLon = radians(widget.maxLongitude);
final double lat = (-o.y).clamp(minLat, maxLat); final double lat = (-o.y).clamp(minLat, maxLat);
final double lon = o.x.clamp(minLon, maxLon); final double lon = o.x.clamp(minLon, maxLon);
if (lat + latitude < minLat) latitude = minLat - lat; if (lat + latitudeRad < minLat) latitudeRad = minLat - lat;
if (lat + latitude > maxLat) latitude = maxLat - lat; if (lat + latitudeRad > maxLat) latitudeRad = maxLat - lat;
if (maxLon - minLon < math.pi * 2) { if (maxLon - minLon < math.pi * 2) {
if (lon + longitude < minLon || lon + longitude > maxLon) { if (lon + longitudeRad < minLon || lon + longitudeRad > maxLon) {
longitude = (lon + longitude < minLon ? minLon : maxLon) - lon; longitudeRad = (lon + longitudeRad < minLon ? minLon : maxLon) - lon;
// reverse rotation when reaching the boundary
if (widget.animSpeed != 0) {
if (widget.animReverse)
_animateDirection *= -1.0;
else
_controller.stop();
}
} }
} }
o.x = lon; o.x = lon;
@ -257,17 +265,17 @@ class _PanoramaState extends State<Panorama> with SingleTickerProviderStateMixin
q = orientationToQuaternion(o); q = orientationToQuaternion(o);
// rotate to longitude zero // rotate to longitude zero
q *= Quaternion.axisAngle(Vector3(0, 1, 0), -math.pi * 0.5); q *= Quaternion.axisAngle(Vector3(0, 1, 0), -_halfPi);
// rotate around the global Y axis // rotate around the global Y axis
q *= Quaternion.axisAngle(Vector3(0, 1, 0), longitude); q *= Quaternion.axisAngle(Vector3(0, 1, 0), longitudeRad);
// rotate around the local X axis // rotate around the local X axis
q = Quaternion.axisAngle(Vector3(1, 0, 0), -latitude) * q; q = Quaternion.axisAngle(Vector3(1, 0, 0), -latitudeRad) * q;
o = quaternionToOrientation(q * Quaternion.axisAngle(Vector3(0, 1, 0), math.pi * 0.5)); o = quaternionToOrientation(q * Quaternion.axisAngle(Vector3(0, 1, 0), _halfPi));
widget.onViewChanged?.call(degrees(o.x), degrees(-o.y), degrees(o.z)); widget.onViewChanged?.call(degrees(o.x), degrees(-o.y), degrees(o.z));
q.rotate(scene!.camera.target..setFrom(Vector3(0, 0, -_radius))); q.rotate(camera.target..setFrom(Vector3(0, 0, -_radius)));
q.rotate(scene!.camera.up..setFrom(Vector3(0, 1, 0))); q.rotate(camera.up..setFrom(Vector3(0, 1, 0)));
scene!.update(); scene!.update();
_streamController.add(null); _streamController.add(null);
} }
@ -275,25 +283,27 @@ class _PanoramaState extends State<Panorama> with SingleTickerProviderStateMixin
void _updateSensorControl() { void _updateSensorControl() {
_orientationSubscription?.cancel(); _orientationSubscription?.cancel();
switch (widget.sensorControl) { switch (widget.sensorControl) {
case SensorControl.Orientation: case SensorControl.orientation:
motionSensors.orientationUpdateInterval = Duration.microsecondsPerSecond ~/ 60; motionSensors.orientationUpdateInterval = Duration.microsecondsPerSecond ~/ 60;
_orientationSubscription = motionSensors.orientation.listen((OrientationEvent event) { _orientationSubscription = motionSensors.orientation.listen((event) {
orientation.setValues(event.yaw, event.pitch, event.roll); orientation.setValues(event.yaw, event.pitch, event.roll);
_updateView();
}); });
break; break;
case SensorControl.AbsoluteOrientation: case SensorControl.absoluteOrientation:
motionSensors.absoluteOrientationUpdateInterval = Duration.microsecondsPerSecond ~/ 60; motionSensors.absoluteOrientationUpdateInterval = Duration.microsecondsPerSecond ~/ 60;
_orientationSubscription = motionSensors.absoluteOrientation.listen((AbsoluteOrientationEvent event) { _orientationSubscription = motionSensors.absoluteOrientation.listen((event) {
orientation.setValues(event.yaw, event.pitch, event.roll); orientation.setValues(event.yaw, event.pitch, event.roll);
_updateView();
}); });
break; break;
default: default:
} }
_screenOrientSubscription?.cancel(); _screenOrientSubscription?.cancel();
if (widget.sensorControl != SensorControl.None) { if (widget.sensorControl != SensorControl.none) {
_screenOrientSubscription = motionSensors.screenOrientation.listen((ScreenOrientationEvent event) { _screenOrientSubscription = motionSensors.screenOrientation.listen((event) {
screenOrientation = radians(event.angle!); screenOrientationRad = radians(event.angle!);
}); });
} }
} }
@ -309,20 +319,28 @@ class _PanoramaState extends State<Panorama> with SingleTickerProviderStateMixin
void _loadTexture(ImageProvider? provider) { void _loadTexture(ImageProvider? provider) {
if (provider == null) return; if (provider == null) return;
_imageStream?.removeListener(ImageStreamListener(_updateTexture)); _imageStream?.removeListener(ImageStreamListener(_updateTexture));
_imageStream = provider.resolve(ImageConfiguration()); _imageStream = provider.resolve(const ImageConfiguration());
ImageStreamListener listener = ImageStreamListener(_updateTexture); ImageStreamListener listener = ImageStreamListener(_updateTexture);
_imageStream!.addListener(listener); _imageStream!.addListener(listener);
} }
void _onSceneCreated(Scene scene) { void _onSceneCreated(Scene scene) {
this.scene = scene; this.scene = scene;
scene.camera.near = 1.0; final camera = scene.camera;
scene.camera.far = _radius + 1.0; camera.near = 1.0;
scene.camera.fov = 75; camera.far = _radius + 1.0;
scene.camera.zoom = widget.zoom; camera.fov = 75;
scene.camera.position.setFrom(Vector3(0, 0, 0.1)); camera.zoom = widget.zoom;
camera.position.setFrom(Vector3(0, 0, 0.1));
if (widget.child != null) { 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); surface = Object(name: 'surface', mesh: mesh, backfaceCulling: false);
_loadTexture(widget.child!.image); _loadTexture(widget.child!.image);
scene.world.add(surface!); scene.world.add(surface!);
@ -335,48 +353,52 @@ class _PanoramaState extends State<Panorama> with SingleTickerProviderStateMixin
} }
Vector3 positionToLatLon(double x, double y) { Vector3 positionToLatLon(double x, double y) {
final camera = scene!.camera;
// transform viewport coordinate to NDC, values between -1 and 1 // 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 v = Vector4(2.0 * x / camera.viewportWidth - 1.0, 1.0 - 2.0 * y / camera.viewportHeight, 1.0, 1.0);
// create projection matrix // create projection matrix
final Matrix4 m = scene!.camera.projectionMatrix * scene!.camera.lookAtMatrix; final m = camera.projectionMatrix * camera.lookAtMatrix;
// apply inversed projection matrix // apply inverse projection matrix
m.invert(); m.invert();
v.applyMatrix4(m); v.applyMatrix4(m);
// apply perspective division // apply perspective division
v.scale(1 / v.w); v.scale(1 / v.w);
// get rotation from two vectors // get rotation from two vectors
final Quaternion q = Quaternion.fromTwoVectors(v.xyz, Vector3(0.0, 0.0, -_radius)); final q = Quaternion.fromTwoVectors(v.xyz, Vector3(0.0, 0.0, -_radius));
// get euler angles from rotation // 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), _halfPi));
} }
Vector3 positionFromLatLon(double lat, double lon) { Vector3 positionFromLatLon(double lat, double lon) {
final camera = scene!.camera;
// create projection matrix // create projection matrix
final Matrix4 m = scene!.camera.projectionMatrix * scene!.camera.lookAtMatrix * matrixFromLatLon(lat, lon); final Matrix4 m = camera.projectionMatrix * camera.lookAtMatrix * matrixFromLatLon(lat, lon);
// apply projection matrix // apply projection matrix
final Vector4 v = Vector4(0.0, 0.0, -_radius, 1.0)..applyMatrix4(m); final Vector4 v = Vector4(0.0, 0.0, -_radius, 1.0)..applyMatrix4(m);
// apply perspective division and transform NDC to the viewport coordinate // apply perspective division and transform NDC to the viewport coordinate
return Vector3( return Vector3(
(1.0 + v.x / v.w) * scene!.camera.viewportWidth / 2, (1.0 + v.x / v.w) * camera.viewportWidth / 2,
(1.0 - v.y / v.w) * scene!.camera.viewportHeight / 2, (1.0 - v.y / v.w) * camera.viewportHeight / 2,
v.z, v.z,
); );
} }
Widget buildHotspotWidgets(List<Hotspot>? hotspots) { Widget buildHotspotWidgets(List<Hotspot>? hotspots) {
final List<Widget> widgets = <Widget>[]; final widgets = <Widget>[];
if (hotspots != null && scene != null) { if (hotspots != null && scene != null) {
for (Hotspot hotspot in hotspots) { for (Hotspot hotspot in hotspots) {
final Vector3 pos = positionFromLatLon(hotspot.latitude, hotspot.longitude); final pos = positionFromLatLon(hotspot.latitude, hotspot.longitude);
final Offset orgin = Offset(hotspot.width * hotspot.orgin.dx, hotspot.height * hotspot.orgin.dy); final origin = Offset(hotspot.width * hotspot.origin.dx, hotspot.height * hotspot.origin.dy);
final Matrix4 transform = scene!.camera.lookAtMatrix * matrixFromLatLon(hotspot.latitude, hotspot.longitude); final transform = scene!.camera.lookAtMatrix * matrixFromLatLon(hotspot.latitude, hotspot.longitude);
final Widget child = Positioned( final child = Positioned(
left: pos.x - orgin.dx, left: pos.x - origin.dx,
top: pos.y - orgin.dy, top: pos.y - origin.dy,
width: hotspot.width, width: hotspot.width,
height: hotspot.height, height: hotspot.height,
child: Transform( child: Transform(
origin: orgin, origin: origin,
transform: transform..invert(), transform: transform..invert(),
child: Offstage( child: Offstage(
offstage: pos.z < 0, offstage: pos.z < 0,
@ -393,15 +415,15 @@ class _PanoramaState extends State<Panorama> with SingleTickerProviderStateMixin
@override @override
void initState() { void initState() {
super.initState(); super.initState();
latitude = degrees(widget.latitude); latitudeRad = radians(widget.latitude);
longitude = degrees(widget.longitude); longitudeRad = radians(widget.longitude);
_streamController = StreamController<Null>.broadcast(); _streamController = StreamController<Null>.broadcast();
_stream = _streamController.stream; _stream = _streamController.stream;
_updateSensorControl(); _updateSensorControl();
_controller = AnimationController(duration: Duration(milliseconds: 60000), vsync: this)..addListener(_updateView); _controller = AnimationController(duration: const Duration(milliseconds: 60000), vsync: this)..addListener(_updateView);
if (widget.sensorControl != SensorControl.None || widget.animSpeed != 0) _controller.repeat(); if (widget.sensorControl != SensorControl.none) _controller.repeat();
} }
@override @override
@ -418,8 +440,19 @@ class _PanoramaState extends State<Panorama> with SingleTickerProviderStateMixin
void didUpdateWidget(Panorama oldWidget) { void didUpdateWidget(Panorama oldWidget) {
super.didUpdateWidget(oldWidget); super.didUpdateWidget(oldWidget);
if (surface == null) return; 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) { if (widget.latSegments != oldWidget.latSegments ||
surface!.mesh = generateSphereMesh(radius: _radius, latSegments: widget.latSegments, lonSegments: widget.lonSegments, croppedArea: widget.croppedArea, croppedFullWidth: widget.croppedFullWidth, croppedFullHeight: widget.croppedFullHeight); 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) { if (widget.child?.image != oldWidget.child?.image) {
_loadTexture(widget.child?.image); _loadTexture(widget.child?.image);
@ -436,7 +469,7 @@ class _PanoramaState extends State<Panorama> with SingleTickerProviderStateMixin
Cube(interactive: false, onSceneCreated: _onSceneCreated), Cube(interactive: false, onSceneCreated: _onSceneCreated),
StreamBuilder( StreamBuilder(
stream: _stream, stream: _stream,
builder: (BuildContext context, AsyncSnapshot snapshot) { builder: (context, snapshot) {
return buildHotspotWidgets(widget.hotspots); return buildHotspotWidgets(widget.hotspots);
}, },
), ),
@ -447,6 +480,7 @@ class _PanoramaState extends State<Panorama> with SingleTickerProviderStateMixin
? GestureDetector( ? GestureDetector(
onScaleStart: _handleScaleStart, onScaleStart: _handleScaleStart,
onScaleUpdate: _handleScaleUpdate, onScaleUpdate: _handleScaleUpdate,
onScaleEnd: _handleScaleEnd,
onTapUp: widget.onTap == null ? null : _handleTapUp, onTapUp: widget.onTap == null ? null : _handleTapUp,
onLongPressStart: widget.onLongPressStart == null ? null : _handleLongPressStart, onLongPressStart: widget.onLongPressStart == null ? null : _handleLongPressStart,
onLongPressMoveUpdate: widget.onLongPressMoveUpdate == null ? null : _handleLongPressMoveUpdate, onLongPressMoveUpdate: widget.onLongPressMoveUpdate == null ? null : _handleLongPressMoveUpdate,
@ -462,7 +496,7 @@ class Hotspot {
this.name, this.name,
this.latitude = 0.0, this.latitude = 0.0,
this.longitude = 0.0, this.longitude = 0.0,
this.orgin = const Offset(0.5, 0.5), this.origin = const Offset(0.5, 0.5),
this.width = 32.0, this.width = 32.0,
this.height = 32.0, this.height = 32.0,
this.widget, this.widget,
@ -477,8 +511,8 @@ class Hotspot {
/// The initial longitude, in degrees, between -180 and 180. /// The initial longitude, in degrees, between -180 and 180.
final double longitude; final double longitude;
/// The local orgin of this hotspot. Default is Offset(0.5, 0.5). /// The local origin of this hotspot. Default is Offset(0.5, 0.5).
final Offset orgin; final Offset origin;
// The width of widget. Default is 32.0 // The width of widget. Default is 32.0
double width; double width;

View file

@ -5,51 +5,50 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: async name: async
url: "https://pub.dartlang.org" sha256: "758e6d74e971c3e5aceb4110bfd6698efc7f501675bcfe0c775459a8140750eb"
url: "https://pub.dev"
source: hosted source: hosted
version: "2.5.0" version: "2.13.0"
boolean_selector: boolean_selector:
dependency: transitive dependency: transitive
description: description:
name: boolean_selector name: boolean_selector
url: "https://pub.dartlang.org" sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea"
url: "https://pub.dev"
source: hosted source: hosted
version: "2.1.0" version: "2.1.2"
characters: characters:
dependency: transitive dependency: transitive
description: description:
name: characters name: characters
url: "https://pub.dartlang.org" sha256: faf38497bda5ead2a8c7615f4f7939df04333478bf32e4173fcb06d428b5716b
url: "https://pub.dev"
source: hosted source: hosted
version: "1.1.0" version: "1.4.1"
charcode:
dependency: transitive
description:
name: charcode
url: "https://pub.dartlang.org"
source: hosted
version: "1.2.0"
clock: clock:
dependency: transitive dependency: transitive
description: description:
name: clock name: clock
url: "https://pub.dartlang.org" sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b
url: "https://pub.dev"
source: hosted source: hosted
version: "1.1.0" version: "1.1.2"
collection: collection:
dependency: transitive dependency: transitive
description: description:
name: collection name: collection
url: "https://pub.dartlang.org" sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76"
url: "https://pub.dev"
source: hosted source: hosted
version: "1.15.0" version: "1.19.1"
fake_async: fake_async:
dependency: transitive dependency: transitive
description: description:
name: fake_async name: fake_async
url: "https://pub.dartlang.org" sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44"
url: "https://pub.dev"
source: hosted source: hosted
version: "1.2.0" version: "1.3.3"
flutter: flutter:
dependency: "direct main" dependency: "direct main"
description: flutter description: flutter
@ -59,103 +58,165 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: flutter_cube name: flutter_cube
url: "https://pub.dartlang.org" sha256: "71cf679a251166eb97f86751c56582b09abdbf859485fbf60524948813914c3b"
url: "https://pub.dev"
source: hosted source: hosted
version: "0.1.1" version: "0.1.1"
flutter_lints:
dependency: "direct dev"
description:
name: flutter_lints
sha256: "3105dc8492f6183fb076ccf1f351ac3d60564bff92e20bfc4af9cc1651f4e7e1"
url: "https://pub.dev"
source: hosted
version: "6.0.0"
flutter_test: flutter_test:
dependency: "direct dev" dependency: "direct dev"
description: flutter description: flutter
source: sdk source: sdk
version: "0.0.0" version: "0.0.0"
leak_tracker:
dependency: transitive
description:
name: leak_tracker
sha256: "33e2e26bdd85a0112ec15400c8cbffea70d0f9c3407491f672a2fad47915e2de"
url: "https://pub.dev"
source: hosted
version: "11.0.2"
leak_tracker_flutter_testing:
dependency: transitive
description:
name: leak_tracker_flutter_testing
sha256: "1dbc140bb5a23c75ea9c4811222756104fbcd1a27173f0c34ca01e16bea473c1"
url: "https://pub.dev"
source: hosted
version: "3.0.10"
leak_tracker_testing:
dependency: transitive
description:
name: leak_tracker_testing
sha256: "8d5a2d49f4a66b49744b23b018848400d23e54caf9463f4eb20df3eb8acb2eb1"
url: "https://pub.dev"
source: hosted
version: "3.0.2"
lints:
dependency: transitive
description:
name: lints
sha256: "12f842a479589fea194fe5c5a3095abc7be0c1f2ddfa9a0e76aed1dbd26a87df"
url: "https://pub.dev"
source: hosted
version: "6.1.0"
matcher: matcher:
dependency: transitive dependency: transitive
description: description:
name: matcher name: matcher
url: "https://pub.dartlang.org" sha256: "12956d0ad8390bbcc63ca2e1469c0619946ccb52809807067a7020d57e647aa6"
url: "https://pub.dev"
source: hosted source: hosted
version: "0.12.10" version: "0.12.18"
material_color_utilities:
dependency: transitive
description:
name: material_color_utilities
sha256: "9c337007e82b1889149c82ed242ed1cb24a66044e30979c44912381e9be4c48b"
url: "https://pub.dev"
source: hosted
version: "0.13.0"
meta: meta:
dependency: transitive dependency: transitive
description: description:
name: meta name: meta
url: "https://pub.dartlang.org" sha256: "23f08335362185a5ea2ad3a4e597f1375e78bce8a040df5c600c8d3552ef2394"
url: "https://pub.dev"
source: hosted source: hosted
version: "1.3.0" version: "1.17.0"
motion_sensors: motion_sensors:
dependency: "direct main" dependency: "direct main"
description: description:
name: motion_sensors path: "."
url: "https://pub.dartlang.org" ref: aves
source: hosted resolved-ref: "400fa42826e22a156b69a5d52926ce5681ab9b45"
url: "https://github.com/deckerst/aves_panorama_motion_sensors.git"
source: git
version: "0.1.0" version: "0.1.0"
path: path:
dependency: transitive dependency: transitive
description: description:
name: path name: path
url: "https://pub.dartlang.org" sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5"
url: "https://pub.dev"
source: hosted source: hosted
version: "1.8.0" version: "1.9.1"
sky_engine: sky_engine:
dependency: transitive dependency: transitive
description: flutter description: flutter
source: sdk source: sdk
version: "0.0.99" version: "0.0.0"
source_span: source_span:
dependency: transitive dependency: transitive
description: description:
name: source_span name: source_span
url: "https://pub.dartlang.org" sha256: "56a02f1f4cd1a2d96303c0144c93bd6d909eea6bee6bf5a0e0b685edbd4c47ab"
url: "https://pub.dev"
source: hosted source: hosted
version: "1.8.0" version: "1.10.2"
stack_trace: stack_trace:
dependency: transitive dependency: transitive
description: description:
name: stack_trace name: stack_trace
url: "https://pub.dartlang.org" sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1"
url: "https://pub.dev"
source: hosted source: hosted
version: "1.10.0" version: "1.12.1"
stream_channel: stream_channel:
dependency: transitive dependency: transitive
description: description:
name: stream_channel name: stream_channel
url: "https://pub.dartlang.org" sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d"
url: "https://pub.dev"
source: hosted source: hosted
version: "2.1.0" version: "2.1.4"
string_scanner: string_scanner:
dependency: transitive dependency: transitive
description: description:
name: string_scanner name: string_scanner
url: "https://pub.dartlang.org" sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43"
url: "https://pub.dev"
source: hosted source: hosted
version: "1.1.0" version: "1.4.1"
term_glyph: term_glyph:
dependency: transitive dependency: transitive
description: description:
name: term_glyph name: term_glyph
url: "https://pub.dartlang.org" sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e"
url: "https://pub.dev"
source: hosted source: hosted
version: "1.2.0" version: "1.2.2"
test_api: test_api:
dependency: transitive dependency: transitive
description: description:
name: test_api name: test_api
url: "https://pub.dartlang.org" sha256: "93167629bfc610f71560ab9312acdda4959de4df6fac7492c89ff0d3886f6636"
url: "https://pub.dev"
source: hosted source: hosted
version: "0.2.19" version: "0.7.9"
typed_data:
dependency: transitive
description:
name: typed_data
url: "https://pub.dartlang.org"
source: hosted
version: "1.3.0"
vector_math: vector_math:
dependency: transitive dependency: transitive
description: description:
name: vector_math name: vector_math
url: "https://pub.dartlang.org" sha256: d530bd74fea330e6e364cda7a85019c434070188383e1cd8d9777ee586914c5b
url: "https://pub.dev"
source: hosted source: hosted
version: "2.1.0" version: "2.2.0"
vm_service:
dependency: transitive
description:
name: vm_service
sha256: "45caa6c5917fa127b5dbcfbd1fa60b14e583afdc08bfc96dda38886ca252eb60"
url: "https://pub.dev"
source: hosted
version: "15.0.2"
sdks: sdks:
dart: ">=2.12.0 <3.0.0" dart: ">=3.11.0 <4.0.0"
flutter: ">=1.10.0" flutter: ">=3.18.0-18.0.pre.54"

View file

@ -1,19 +1,25 @@
name: panorama name: panorama
description: Panorama -- A 360-degree panorama viewer. description: Panorama -- A 360-degree panorama viewer.
version: 0.4.1
homepage: https://github.com/zesage/panorama homepage: https://github.com/zesage/panorama
publish_to: none
version: 0.4.1
environment: environment:
sdk: '>=2.12.0 <3.0.0' sdk: ">=3.11.0 <4.0.0"
dependencies: dependencies:
flutter: flutter:
sdk: flutter sdk: flutter
flutter_cube: ^0.1.1 flutter_cube:
motion_sensors: ^0.1.0 motion_sensors:
git:
url: https://github.com/deckerst/aves_panorama_motion_sensors.git
ref: aves
dev_dependencies: dev_dependencies:
flutter_test: flutter_test:
sdk: flutter sdk: flutter
flutter_lints:
flutter: flutter: