├── .gitignore ├── .metadata ├── CHANGELOG.md ├── LICENSE ├── README.md ├── analysis_options.yaml ├── arrow_path.iml ├── example ├── .gitignore ├── .metadata ├── README.md ├── android │ ├── app │ │ ├── build.gradle │ │ └── src │ │ │ ├── debug │ │ │ └── AndroidManifest.xml │ │ │ ├── main │ │ │ ├── AndroidManifest.xml │ │ │ ├── java │ │ │ │ └── com │ │ │ │ │ └── tengio │ │ │ │ │ └── example │ │ │ │ │ └── MainActivity.java │ │ │ └── res │ │ │ │ ├── drawable │ │ │ │ └── launch_background.xml │ │ │ │ ├── mipmap-hdpi │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-mdpi │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-xhdpi │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-xxhdpi │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-xxxhdpi │ │ │ │ └── ic_launcher.png │ │ │ │ └── values │ │ │ │ └── styles.xml │ │ │ └── profile │ │ │ └── AndroidManifest.xml │ ├── build.gradle │ ├── gradle.properties │ ├── gradle │ │ └── wrapper │ │ │ └── gradle-wrapper.properties │ └── settings.gradle ├── arrow_path_example.png ├── ios │ ├── Flutter │ │ ├── AppFrameworkInfo.plist │ │ ├── Debug.xcconfig │ │ └── Release.xcconfig │ ├── Runner.xcodeproj │ │ ├── project.pbxproj │ │ ├── project.xcworkspace │ │ │ ├── contents.xcworkspacedata │ │ │ └── xcshareddata │ │ │ │ └── IDEWorkspaceChecks.plist │ │ └── xcshareddata │ │ │ └── xcschemes │ │ │ └── Runner.xcscheme │ ├── Runner.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ └── IDEWorkspaceChecks.plist │ └── Runner │ │ ├── AppDelegate.h │ │ ├── AppDelegate.m │ │ ├── Assets.xcassets │ │ ├── AppIcon.appiconset │ │ │ ├── Contents.json │ │ │ ├── Icon-App-1024x1024@1x.png │ │ │ ├── Icon-App-20x20@1x.png │ │ │ ├── Icon-App-20x20@2x.png │ │ │ ├── Icon-App-20x20@3x.png │ │ │ ├── Icon-App-29x29@1x.png │ │ │ ├── Icon-App-29x29@2x.png │ │ │ ├── Icon-App-29x29@3x.png │ │ │ ├── Icon-App-40x40@1x.png │ │ │ ├── Icon-App-40x40@2x.png │ │ │ ├── Icon-App-40x40@3x.png │ │ │ ├── Icon-App-60x60@2x.png │ │ │ ├── Icon-App-60x60@3x.png │ │ │ ├── Icon-App-76x76@1x.png │ │ │ ├── Icon-App-76x76@2x.png │ │ │ └── Icon-App-83.5x83.5@2x.png │ │ └── LaunchImage.imageset │ │ │ ├── Contents.json │ │ │ ├── LaunchImage.png │ │ │ ├── LaunchImage@2x.png │ │ │ ├── LaunchImage@3x.png │ │ │ └── README.md │ │ ├── Base.lproj │ │ ├── LaunchScreen.storyboard │ │ └── Main.storyboard │ │ ├── Info.plist │ │ └── main.m ├── lib │ └── main.dart ├── pubspec.lock └── pubspec.yaml ├── lib └── arrow_path.dart ├── pubspec.lock └── pubspec.yaml /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .dart_tool/ 3 | 4 | .packages 5 | .pub/ 6 | 7 | build/ 8 | ios/.generated/ 9 | ios/Flutter/Generated.xcconfig 10 | ios/Runner/GeneratedPluginRegistrant.* 11 | .idea 12 | example/ios/Flutter/flutter_export_environment.sh 13 | -------------------------------------------------------------------------------- /.metadata: -------------------------------------------------------------------------------- 1 | # This file tracks properties of this Flutter project. 2 | # Used by Flutter tool to assess capabilities and perform upgrades etc. 3 | # 4 | # This file should be version controlled and should not be manually edited. 5 | 6 | version: 7 | revision: 8661d8aecd626f7f57ccbcb735553edc05a2e713 8 | channel: stable 9 | 10 | project_type: package 11 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## [3.1.0] - 2023-06-02 2 | 3 | * *DEPRECATED* Deprecated ArrowPath.make(), use ArrowPath.addTip() instead. 4 | * Added ArrowPath.addTip(), which is the same as ArrowPath.make() but without `isDoubleSided` and with the new `isBackward` argument. 5 | This will allow more control on what side the arrow should be added. 6 | * Updated README to add migration instructions. 7 | * Updated for Flutter 3.10 and Dart 3. 8 | * Update Example app. 9 | * Update License wording (same license). 10 | 11 | ## [3.0.0] - 2022-07-18 12 | 13 | * *(Potentially) Breaking change:* Updated to AndroidX. 14 | * Fixed issue when the given path is too small (for example a 0 length path). Thanks to @Freancy for bug report. 15 | * Example App: Added ScrollView and removed vertical screen constraint. 16 | * Example App: Update to Android embedding V2. 17 | * Improved code style. 18 | 19 | ## [2.0.0] - 2021-04-29 20 | 21 | * *Breaking change:* Null safety 22 | 23 | ## [1.0.0] - 2019-05-11 24 | 25 | * Initial release. 26 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2020 Quentin Le Guennec 2 | 3 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 4 | 5 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 6 | 7 | 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 8 | 9 | 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 10 | 11 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | [![pub package](https://img.shields.io/pub/v/arrow_path.svg)](https://pub.dev/packages/arrow_path) 3 | [![pub points](https://img.shields.io/pub/points/arrow_path?color=2E8B57&label=pub%20points)](https://pub.dev/packages/arrow_path/score) 4 | 5 | 6 | # Flutter arrow_path package 7 | 8 | Draw arrows with Path objects easily. Paths can be composited to add arrows to any curve and draw all at once. 9 | 10 | 11 |

12 | 13 |

14 | 15 | 16 | The arrow is drawn using the direction of the tangent to the curve at the end of the curve. 17 | It features an adjustment parameter to also look at the tangent just before the end of the 18 | segment and rotate the tip of the arrow based on the angle difference to improve the look of the arrow 19 | when the curvature at the end is high. 20 | 21 | ## Getting Started 22 | 23 | Have a look at the [example app](https://github.com/quentinleguennec/flutter-arrow-path/blob/master/example/lib/main.dart) to get started. 24 | 25 | ## Migration from [3.0.0] to [3.1.0] 26 | 27 | ArrowPath.make() is now deprecated, use ArrowPath.addTip() instead. 28 | 29 | 30 | If you are not using the `isDoubleSided` argument of ArrowPath.make() then you can safely replace it by ArrowPath.addTip() without any other change. 31 | 32 | 33 | If you are using the `isDoubleSided` argument of ArrowPath.make() then change yor code like this: 34 | 35 | 36 | Before: 37 | ```dart 38 | Path path = Path(); 39 | path.relativeLineTo(100, 100); 40 | path = ArrowPath.make(path, isDoubleSided: true); 41 | ``` 42 | 43 | After: 44 | ```dart 45 | Path path = Path(); 46 | path.relativeLineTo(100, 100); 47 | path = ArrowPath.addTip(path); 48 | path = ArrowPath.addTip(path, isBackward: true); 49 | ``` -------------------------------------------------------------------------------- /analysis_options.yaml: -------------------------------------------------------------------------------- 1 | include: package:flutter_lints/flutter.yaml 2 | 3 | # Additional information about this file can be found at 4 | # https://dart.dev/guides/language/analysis-options 5 | # List of lints: 6 | # https://dart.dev/tools/linter-rules 7 | 8 | analyzer: 9 | exclude: [build/**] 10 | language: 11 | strict-casts: true 12 | strict-inference: true 13 | strict-raw-types: true 14 | plugins: 15 | - dart_code_metrics 16 | 17 | linter: 18 | rules: 19 | always_declare_return_types: true 20 | prefer_single_quotes: true 21 | only_throw_errors: true 22 | cancel_subscriptions: true 23 | close_sinks: true 24 | prefer_final_fields: true 25 | prefer_final_locals: true 26 | prefer_final_in_for_each: true 27 | use_build_context_synchronously: true 28 | await_only_futures: true 29 | unawaited_futures: true 30 | always_specify_types: false 31 | avoid_function_literals_in_foreach_calls: false 32 | 33 | dart_code_metrics: 34 | metrics-exclude: 35 | - test/** 36 | rules: 37 | - prefer-trailing-comma 38 | - no-equal-then-else 39 | -------------------------------------------------------------------------------- /arrow_path.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /example/.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .buildlog/ 9 | .history 10 | .svn/ 11 | 12 | # IntelliJ related 13 | *.iml 14 | *.ipr 15 | *.iws 16 | .idea/ 17 | 18 | # Visual Studio Code related 19 | .vscode/ 20 | 21 | # Flutter/Dart/Pub related 22 | **/doc/api/ 23 | .dart_tool/ 24 | .flutter-plugins 25 | .packages 26 | .pub-cache/ 27 | .pub/ 28 | /build/ 29 | 30 | # Android related 31 | **/android/**/gradle-wrapper.jar 32 | **/android/.gradle 33 | **/android/captures/ 34 | **/android/gradlew 35 | **/android/gradlew.bat 36 | **/android/local.properties 37 | **/android/**/GeneratedPluginRegistrant.java 38 | 39 | # iOS/XCode related 40 | **/ios/**/*.mode1v3 41 | **/ios/**/*.mode2v3 42 | **/ios/**/*.moved-aside 43 | **/ios/**/*.pbxuser 44 | **/ios/**/*.perspectivev3 45 | **/ios/**/*sync/ 46 | **/ios/**/.sconsign.dblite 47 | **/ios/**/.tags* 48 | **/ios/**/.vagrant/ 49 | **/ios/**/DerivedData/ 50 | **/ios/**/Icon? 51 | **/ios/**/Pods/ 52 | **/ios/**/.symlinks/ 53 | **/ios/**/profile 54 | **/ios/**/xcuserdata 55 | **/ios/.generated/ 56 | **/ios/Flutter/App.framework 57 | **/ios/Flutter/Flutter.framework 58 | **/ios/Flutter/Generated.xcconfig 59 | **/ios/Flutter/app.flx 60 | **/ios/Flutter/app.zip 61 | **/ios/Flutter/flutter_assets/ 62 | **/ios/ServiceDefinitions.json 63 | **/ios/Runner/GeneratedPluginRegistrant.* 64 | 65 | # Exceptions to above rules. 66 | !**/ios/**/default.mode1v3 67 | !**/ios/**/default.mode2v3 68 | !**/ios/**/default.pbxuser 69 | !**/ios/**/default.perspectivev3 70 | !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages 71 | -------------------------------------------------------------------------------- /example/.metadata: -------------------------------------------------------------------------------- 1 | # This file tracks properties of this Flutter project. 2 | # Used by Flutter tool to assess capabilities and perform upgrades etc. 3 | # 4 | # This file should be version controlled and should not be manually edited. 5 | 6 | version: 7 | revision: 7a4c33425ddd78c54aba07d86f3f9a4a0051769b 8 | channel: stable 9 | 10 | project_type: app 11 | -------------------------------------------------------------------------------- /example/README.md: -------------------------------------------------------------------------------- 1 | # Example app 2 | 3 | Example project for the arrow_path package. 4 | -------------------------------------------------------------------------------- /example/android/app/build.gradle: -------------------------------------------------------------------------------- 1 | def localProperties = new Properties() 2 | def localPropertiesFile = rootProject.file('local.properties') 3 | if (localPropertiesFile.exists()) { 4 | localPropertiesFile.withReader('UTF-8') { reader -> 5 | localProperties.load(reader) 6 | } 7 | } 8 | 9 | def flutterRoot = localProperties.getProperty('flutter.sdk') 10 | if (flutterRoot == null) { 11 | throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") 12 | } 13 | 14 | def flutterVersionCode = localProperties.getProperty('flutter.versionCode') 15 | if (flutterVersionCode == null) { 16 | flutterVersionCode = '1' 17 | } 18 | 19 | def flutterVersionName = localProperties.getProperty('flutter.versionName') 20 | if (flutterVersionName == null) { 21 | flutterVersionName = '1.0' 22 | } 23 | 24 | apply plugin: 'com.android.application' 25 | apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" 26 | 27 | android { 28 | compileSdkVersion flutter.compileSdkVersion 29 | 30 | compileOptions { 31 | sourceCompatibility JavaVersion.VERSION_1_8 32 | targetCompatibility JavaVersion.VERSION_1_8 33 | } 34 | 35 | defaultConfig { 36 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). 37 | applicationId "com.tengio.example" 38 | minSdkVersion flutter.minSdkVersion 39 | targetSdkVersion flutter.targetSdkVersion 40 | versionCode flutterVersionCode.toInteger() 41 | versionName flutterVersionName 42 | } 43 | 44 | buildTypes { 45 | release { 46 | // TODO: Add your own signing config for the release build. 47 | // Signing with the debug keys for now, so `flutter run --release` works. 48 | signingConfig signingConfigs.debug 49 | } 50 | } 51 | } 52 | 53 | flutter { 54 | source '../..' 55 | } 56 | 57 | dependencies { 58 | } 59 | -------------------------------------------------------------------------------- /example/android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /example/android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 8 | 16 | 20 | 23 | 24 | 25 | 26 | 27 | 28 | 30 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /example/android/app/src/main/java/com/tengio/example/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.tengio.example; 2 | 3 | import io.flutter.embedding.android.FlutterActivity; 4 | 5 | public class MainActivity extends FlutterActivity { 6 | } 7 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/drawable/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quentinleguennec/flutter-arrow-path/1d37eab5fe676d93ac64f76a8f6fced1a7b0e44c/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quentinleguennec/flutter-arrow-path/1d37eab5fe676d93ac64f76a8f6fced1a7b0e44c/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quentinleguennec/flutter-arrow-path/1d37eab5fe676d93ac64f76a8f6fced1a7b0e44c/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quentinleguennec/flutter-arrow-path/1d37eab5fe676d93ac64f76a8f6fced1a7b0e44c/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quentinleguennec/flutter-arrow-path/1d37eab5fe676d93ac64f76a8f6fced1a7b0e44c/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | -------------------------------------------------------------------------------- /example/android/app/src/profile/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /example/android/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | ext.kotlin_version = '1.6.10' 3 | repositories { 4 | google() 5 | mavenCentral() 6 | } 7 | 8 | dependencies { 9 | classpath 'com.android.tools.build:gradle:4.1.0' 10 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 11 | } 12 | } 13 | 14 | allprojects { 15 | repositories { 16 | google() 17 | mavenCentral() 18 | } 19 | } 20 | 21 | rootProject.buildDir = '../build' 22 | subprojects { 23 | project.buildDir = "${rootProject.buildDir}/${project.name}" 24 | } 25 | subprojects { 26 | project.evaluationDependsOn(':app') 27 | } 28 | 29 | tasks.register("clean", Delete) { 30 | delete rootProject.buildDir 31 | } 32 | -------------------------------------------------------------------------------- /example/android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx1536M --add-exports=java.base/sun.nio.ch=ALL-UNNAMED --add-opens=java.base/java.lang=ALL-UNNAMED --add-opens=java.base/java.lang.reflect=ALL-UNNAMED --add-opens=java.base/java.io=ALL-UNNAMED --add-exports=jdk.unsupported/sun.misc=ALL-UNNAMED 2 | android.useAndroidX=true 3 | android.enableJetifier=true 4 | -------------------------------------------------------------------------------- /example/android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Fri Jun 23 08:50:38 CEST 2017 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.1-all.zip 7 | -------------------------------------------------------------------------------- /example/android/settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | 3 | def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() 4 | 5 | def plugins = new Properties() 6 | def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') 7 | if (pluginsFile.exists()) { 8 | pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } 9 | } 10 | 11 | plugins.each { name, path -> 12 | def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() 13 | include ":$name" 14 | project(":$name").projectDir = pluginDirectory 15 | } 16 | -------------------------------------------------------------------------------- /example/arrow_path_example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quentinleguennec/flutter-arrow-path/1d37eab5fe676d93ac64f76a8f6fced1a7b0e44c/example/arrow_path_example.png -------------------------------------------------------------------------------- /example/ios/Flutter/AppFrameworkInfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | App 9 | CFBundleIdentifier 10 | io.flutter.flutter.app 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | App 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1.0 23 | MinimumOSVersion 24 | 9.0 25 | 26 | 27 | -------------------------------------------------------------------------------- /example/ios/Flutter/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Generated.xcconfig" 2 | -------------------------------------------------------------------------------- /example/ios/Flutter/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Generated.xcconfig" 2 | -------------------------------------------------------------------------------- /example/ios/Runner.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 50; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; 11 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; 12 | 9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 9740EEB21CF90195004384FC /* Debug.xcconfig */; }; 13 | 978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */; }; 14 | 97C146F31CF9000F007C117D /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 97C146F21CF9000F007C117D /* main.m */; }; 15 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 16 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 17 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; 18 | /* End PBXBuildFile section */ 19 | 20 | /* Begin PBXCopyFilesBuildPhase section */ 21 | 9705A1C41CF9048500538489 /* Embed Frameworks */ = { 22 | isa = PBXCopyFilesBuildPhase; 23 | buildActionMask = 2147483647; 24 | dstPath = ""; 25 | dstSubfolderSpec = 10; 26 | files = ( 27 | ); 28 | name = "Embed Frameworks"; 29 | runOnlyForDeploymentPostprocessing = 0; 30 | }; 31 | /* End PBXCopyFilesBuildPhase section */ 32 | 33 | /* Begin PBXFileReference section */ 34 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; 35 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; 36 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; 37 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; 38 | 7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 39 | 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 40 | 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; 41 | 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; 42 | 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; 43 | 97C146F21CF9000F007C117D /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 44 | 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 45 | 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 46 | 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 47 | 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 48 | /* End PBXFileReference section */ 49 | 50 | /* Begin PBXFrameworksBuildPhase section */ 51 | 97C146EB1CF9000F007C117D /* Frameworks */ = { 52 | isa = PBXFrameworksBuildPhase; 53 | buildActionMask = 2147483647; 54 | files = ( 55 | ); 56 | runOnlyForDeploymentPostprocessing = 0; 57 | }; 58 | /* End PBXFrameworksBuildPhase section */ 59 | 60 | /* Begin PBXGroup section */ 61 | 9740EEB11CF90186004384FC /* Flutter */ = { 62 | isa = PBXGroup; 63 | children = ( 64 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, 65 | 9740EEB21CF90195004384FC /* Debug.xcconfig */, 66 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, 67 | 9740EEB31CF90195004384FC /* Generated.xcconfig */, 68 | ); 69 | name = Flutter; 70 | sourceTree = ""; 71 | }; 72 | 97C146E51CF9000F007C117D = { 73 | isa = PBXGroup; 74 | children = ( 75 | 9740EEB11CF90186004384FC /* Flutter */, 76 | 97C146F01CF9000F007C117D /* Runner */, 77 | 97C146EF1CF9000F007C117D /* Products */, 78 | CF3B75C9A7D2FA2A4C99F110 /* Frameworks */, 79 | ); 80 | sourceTree = ""; 81 | }; 82 | 97C146EF1CF9000F007C117D /* Products */ = { 83 | isa = PBXGroup; 84 | children = ( 85 | 97C146EE1CF9000F007C117D /* Runner.app */, 86 | ); 87 | name = Products; 88 | sourceTree = ""; 89 | }; 90 | 97C146F01CF9000F007C117D /* Runner */ = { 91 | isa = PBXGroup; 92 | children = ( 93 | 7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */, 94 | 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */, 95 | 97C146FA1CF9000F007C117D /* Main.storyboard */, 96 | 97C146FD1CF9000F007C117D /* Assets.xcassets */, 97 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, 98 | 97C147021CF9000F007C117D /* Info.plist */, 99 | 97C146F11CF9000F007C117D /* Supporting Files */, 100 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, 101 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, 102 | ); 103 | path = Runner; 104 | sourceTree = ""; 105 | }; 106 | 97C146F11CF9000F007C117D /* Supporting Files */ = { 107 | isa = PBXGroup; 108 | children = ( 109 | 97C146F21CF9000F007C117D /* main.m */, 110 | ); 111 | name = "Supporting Files"; 112 | sourceTree = ""; 113 | }; 114 | /* End PBXGroup section */ 115 | 116 | /* Begin PBXNativeTarget section */ 117 | 97C146ED1CF9000F007C117D /* Runner */ = { 118 | isa = PBXNativeTarget; 119 | buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; 120 | buildPhases = ( 121 | 9740EEB61CF901F6004384FC /* Run Script */, 122 | 97C146EA1CF9000F007C117D /* Sources */, 123 | 97C146EB1CF9000F007C117D /* Frameworks */, 124 | 97C146EC1CF9000F007C117D /* Resources */, 125 | 9705A1C41CF9048500538489 /* Embed Frameworks */, 126 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */, 127 | ); 128 | buildRules = ( 129 | ); 130 | dependencies = ( 131 | ); 132 | name = Runner; 133 | productName = Runner; 134 | productReference = 97C146EE1CF9000F007C117D /* Runner.app */; 135 | productType = "com.apple.product-type.application"; 136 | }; 137 | /* End PBXNativeTarget section */ 138 | 139 | /* Begin PBXProject section */ 140 | 97C146E61CF9000F007C117D /* Project object */ = { 141 | isa = PBXProject; 142 | attributes = { 143 | LastUpgradeCheck = 1300; 144 | ORGANIZATIONNAME = "The Chromium Authors"; 145 | TargetAttributes = { 146 | 97C146ED1CF9000F007C117D = { 147 | CreatedOnToolsVersion = 7.3.1; 148 | }; 149 | }; 150 | }; 151 | buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; 152 | compatibilityVersion = "Xcode 3.2"; 153 | developmentRegion = English; 154 | hasScannedForEncodings = 0; 155 | knownRegions = ( 156 | en, 157 | Base, 158 | ); 159 | mainGroup = 97C146E51CF9000F007C117D; 160 | productRefGroup = 97C146EF1CF9000F007C117D /* Products */; 161 | projectDirPath = ""; 162 | projectRoot = ""; 163 | targets = ( 164 | 97C146ED1CF9000F007C117D /* Runner */, 165 | ); 166 | }; 167 | /* End PBXProject section */ 168 | 169 | /* Begin PBXResourcesBuildPhase section */ 170 | 97C146EC1CF9000F007C117D /* Resources */ = { 171 | isa = PBXResourcesBuildPhase; 172 | buildActionMask = 2147483647; 173 | files = ( 174 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, 175 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, 176 | 9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */, 177 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, 178 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, 179 | ); 180 | runOnlyForDeploymentPostprocessing = 0; 181 | }; 182 | /* End PBXResourcesBuildPhase section */ 183 | 184 | /* Begin PBXShellScriptBuildPhase section */ 185 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { 186 | isa = PBXShellScriptBuildPhase; 187 | buildActionMask = 2147483647; 188 | files = ( 189 | ); 190 | inputPaths = ( 191 | ); 192 | name = "Thin Binary"; 193 | outputPaths = ( 194 | ); 195 | runOnlyForDeploymentPostprocessing = 0; 196 | shellPath = /bin/sh; 197 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; 198 | }; 199 | 9740EEB61CF901F6004384FC /* Run Script */ = { 200 | isa = PBXShellScriptBuildPhase; 201 | buildActionMask = 2147483647; 202 | files = ( 203 | ); 204 | inputPaths = ( 205 | ); 206 | name = "Run Script"; 207 | outputPaths = ( 208 | ); 209 | runOnlyForDeploymentPostprocessing = 0; 210 | shellPath = /bin/sh; 211 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; 212 | }; 213 | /* End PBXShellScriptBuildPhase section */ 214 | 215 | /* Begin PBXSourcesBuildPhase section */ 216 | 97C146EA1CF9000F007C117D /* Sources */ = { 217 | isa = PBXSourcesBuildPhase; 218 | buildActionMask = 2147483647; 219 | files = ( 220 | 978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */, 221 | 97C146F31CF9000F007C117D /* main.m in Sources */, 222 | 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, 223 | ); 224 | runOnlyForDeploymentPostprocessing = 0; 225 | }; 226 | /* End PBXSourcesBuildPhase section */ 227 | 228 | /* Begin PBXVariantGroup section */ 229 | 97C146FA1CF9000F007C117D /* Main.storyboard */ = { 230 | isa = PBXVariantGroup; 231 | children = ( 232 | 97C146FB1CF9000F007C117D /* Base */, 233 | ); 234 | name = Main.storyboard; 235 | sourceTree = ""; 236 | }; 237 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { 238 | isa = PBXVariantGroup; 239 | children = ( 240 | 97C147001CF9000F007C117D /* Base */, 241 | ); 242 | name = LaunchScreen.storyboard; 243 | sourceTree = ""; 244 | }; 245 | /* End PBXVariantGroup section */ 246 | 247 | /* Begin XCBuildConfiguration section */ 248 | 249021D3217E4FDB00AE95B9 /* Profile */ = { 249 | isa = XCBuildConfiguration; 250 | buildSettings = { 251 | ALWAYS_SEARCH_USER_PATHS = NO; 252 | CLANG_ANALYZER_NONNULL = YES; 253 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 254 | CLANG_CXX_LIBRARY = "libc++"; 255 | CLANG_ENABLE_MODULES = YES; 256 | CLANG_ENABLE_OBJC_ARC = YES; 257 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 258 | CLANG_WARN_BOOL_CONVERSION = YES; 259 | CLANG_WARN_COMMA = YES; 260 | CLANG_WARN_CONSTANT_CONVERSION = YES; 261 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 262 | CLANG_WARN_EMPTY_BODY = YES; 263 | CLANG_WARN_ENUM_CONVERSION = YES; 264 | CLANG_WARN_INFINITE_RECURSION = YES; 265 | CLANG_WARN_INT_CONVERSION = YES; 266 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 267 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 268 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 269 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 270 | CLANG_WARN_STRICT_PROTOTYPES = YES; 271 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 272 | CLANG_WARN_UNREACHABLE_CODE = YES; 273 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 274 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 275 | COPY_PHASE_STRIP = NO; 276 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 277 | ENABLE_NS_ASSERTIONS = NO; 278 | ENABLE_STRICT_OBJC_MSGSEND = YES; 279 | GCC_C_LANGUAGE_STANDARD = gnu99; 280 | GCC_NO_COMMON_BLOCKS = YES; 281 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 282 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 283 | GCC_WARN_UNDECLARED_SELECTOR = YES; 284 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 285 | GCC_WARN_UNUSED_FUNCTION = YES; 286 | GCC_WARN_UNUSED_VARIABLE = YES; 287 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 288 | MTL_ENABLE_DEBUG_INFO = NO; 289 | SDKROOT = iphoneos; 290 | TARGETED_DEVICE_FAMILY = "1,2"; 291 | VALIDATE_PRODUCT = YES; 292 | }; 293 | name = Profile; 294 | }; 295 | 249021D4217E4FDB00AE95B9 /* Profile */ = { 296 | isa = XCBuildConfiguration; 297 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; 298 | buildSettings = { 299 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 300 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; 301 | DEVELOPMENT_TEAM = S8QB4VV633; 302 | ENABLE_BITCODE = NO; 303 | FRAMEWORK_SEARCH_PATHS = ( 304 | "$(inherited)", 305 | "$(PROJECT_DIR)/Flutter", 306 | ); 307 | INFOPLIST_FILE = Runner/Info.plist; 308 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 309 | LIBRARY_SEARCH_PATHS = ( 310 | "$(inherited)", 311 | "$(PROJECT_DIR)/Flutter", 312 | ); 313 | PRODUCT_BUNDLE_IDENTIFIER = com.tengio.example; 314 | PRODUCT_NAME = "$(TARGET_NAME)"; 315 | VERSIONING_SYSTEM = "apple-generic"; 316 | }; 317 | name = Profile; 318 | }; 319 | 97C147031CF9000F007C117D /* Debug */ = { 320 | isa = XCBuildConfiguration; 321 | buildSettings = { 322 | ALWAYS_SEARCH_USER_PATHS = NO; 323 | CLANG_ANALYZER_NONNULL = YES; 324 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 325 | CLANG_CXX_LIBRARY = "libc++"; 326 | CLANG_ENABLE_MODULES = YES; 327 | CLANG_ENABLE_OBJC_ARC = YES; 328 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 329 | CLANG_WARN_BOOL_CONVERSION = YES; 330 | CLANG_WARN_COMMA = YES; 331 | CLANG_WARN_CONSTANT_CONVERSION = YES; 332 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 333 | CLANG_WARN_EMPTY_BODY = YES; 334 | CLANG_WARN_ENUM_CONVERSION = YES; 335 | CLANG_WARN_INFINITE_RECURSION = YES; 336 | CLANG_WARN_INT_CONVERSION = YES; 337 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 338 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 339 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 340 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 341 | CLANG_WARN_STRICT_PROTOTYPES = YES; 342 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 343 | CLANG_WARN_UNREACHABLE_CODE = YES; 344 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 345 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 346 | COPY_PHASE_STRIP = NO; 347 | DEBUG_INFORMATION_FORMAT = dwarf; 348 | ENABLE_STRICT_OBJC_MSGSEND = YES; 349 | ENABLE_TESTABILITY = YES; 350 | GCC_C_LANGUAGE_STANDARD = gnu99; 351 | GCC_DYNAMIC_NO_PIC = NO; 352 | GCC_NO_COMMON_BLOCKS = YES; 353 | GCC_OPTIMIZATION_LEVEL = 0; 354 | GCC_PREPROCESSOR_DEFINITIONS = ( 355 | "DEBUG=1", 356 | "$(inherited)", 357 | ); 358 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 359 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 360 | GCC_WARN_UNDECLARED_SELECTOR = YES; 361 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 362 | GCC_WARN_UNUSED_FUNCTION = YES; 363 | GCC_WARN_UNUSED_VARIABLE = YES; 364 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 365 | MTL_ENABLE_DEBUG_INFO = YES; 366 | ONLY_ACTIVE_ARCH = YES; 367 | SDKROOT = iphoneos; 368 | TARGETED_DEVICE_FAMILY = "1,2"; 369 | }; 370 | name = Debug; 371 | }; 372 | 97C147041CF9000F007C117D /* Release */ = { 373 | isa = XCBuildConfiguration; 374 | buildSettings = { 375 | ALWAYS_SEARCH_USER_PATHS = NO; 376 | CLANG_ANALYZER_NONNULL = YES; 377 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 378 | CLANG_CXX_LIBRARY = "libc++"; 379 | CLANG_ENABLE_MODULES = YES; 380 | CLANG_ENABLE_OBJC_ARC = YES; 381 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 382 | CLANG_WARN_BOOL_CONVERSION = YES; 383 | CLANG_WARN_COMMA = YES; 384 | CLANG_WARN_CONSTANT_CONVERSION = YES; 385 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 386 | CLANG_WARN_EMPTY_BODY = YES; 387 | CLANG_WARN_ENUM_CONVERSION = YES; 388 | CLANG_WARN_INFINITE_RECURSION = YES; 389 | CLANG_WARN_INT_CONVERSION = YES; 390 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 391 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 392 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 393 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 394 | CLANG_WARN_STRICT_PROTOTYPES = YES; 395 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 396 | CLANG_WARN_UNREACHABLE_CODE = YES; 397 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 398 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 399 | COPY_PHASE_STRIP = NO; 400 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 401 | ENABLE_NS_ASSERTIONS = NO; 402 | ENABLE_STRICT_OBJC_MSGSEND = YES; 403 | GCC_C_LANGUAGE_STANDARD = gnu99; 404 | GCC_NO_COMMON_BLOCKS = YES; 405 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 406 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 407 | GCC_WARN_UNDECLARED_SELECTOR = YES; 408 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 409 | GCC_WARN_UNUSED_FUNCTION = YES; 410 | GCC_WARN_UNUSED_VARIABLE = YES; 411 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 412 | MTL_ENABLE_DEBUG_INFO = NO; 413 | SDKROOT = iphoneos; 414 | TARGETED_DEVICE_FAMILY = "1,2"; 415 | VALIDATE_PRODUCT = YES; 416 | }; 417 | name = Release; 418 | }; 419 | 97C147061CF9000F007C117D /* Debug */ = { 420 | isa = XCBuildConfiguration; 421 | baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; 422 | buildSettings = { 423 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 424 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; 425 | ENABLE_BITCODE = NO; 426 | FRAMEWORK_SEARCH_PATHS = ( 427 | "$(inherited)", 428 | "$(PROJECT_DIR)/Flutter", 429 | ); 430 | INFOPLIST_FILE = Runner/Info.plist; 431 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 432 | LIBRARY_SEARCH_PATHS = ( 433 | "$(inherited)", 434 | "$(PROJECT_DIR)/Flutter", 435 | ); 436 | PRODUCT_BUNDLE_IDENTIFIER = com.tengio.example; 437 | PRODUCT_NAME = "$(TARGET_NAME)"; 438 | VERSIONING_SYSTEM = "apple-generic"; 439 | }; 440 | name = Debug; 441 | }; 442 | 97C147071CF9000F007C117D /* Release */ = { 443 | isa = XCBuildConfiguration; 444 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; 445 | buildSettings = { 446 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 447 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; 448 | ENABLE_BITCODE = NO; 449 | FRAMEWORK_SEARCH_PATHS = ( 450 | "$(inherited)", 451 | "$(PROJECT_DIR)/Flutter", 452 | ); 453 | INFOPLIST_FILE = Runner/Info.plist; 454 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 455 | LIBRARY_SEARCH_PATHS = ( 456 | "$(inherited)", 457 | "$(PROJECT_DIR)/Flutter", 458 | ); 459 | PRODUCT_BUNDLE_IDENTIFIER = com.tengio.example; 460 | PRODUCT_NAME = "$(TARGET_NAME)"; 461 | VERSIONING_SYSTEM = "apple-generic"; 462 | }; 463 | name = Release; 464 | }; 465 | /* End XCBuildConfiguration section */ 466 | 467 | /* Begin XCConfigurationList section */ 468 | 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { 469 | isa = XCConfigurationList; 470 | buildConfigurations = ( 471 | 97C147031CF9000F007C117D /* Debug */, 472 | 97C147041CF9000F007C117D /* Release */, 473 | 249021D3217E4FDB00AE95B9 /* Profile */, 474 | ); 475 | defaultConfigurationIsVisible = 0; 476 | defaultConfigurationName = Release; 477 | }; 478 | 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { 479 | isa = XCConfigurationList; 480 | buildConfigurations = ( 481 | 97C147061CF9000F007C117D /* Debug */, 482 | 97C147071CF9000F007C117D /* Release */, 483 | 249021D4217E4FDB00AE95B9 /* Profile */, 484 | ); 485 | defaultConfigurationIsVisible = 0; 486 | defaultConfigurationName = Release; 487 | }; 488 | /* End XCConfigurationList section */ 489 | }; 490 | rootObject = 97C146E61CF9000F007C117D /* Project object */; 491 | } 492 | -------------------------------------------------------------------------------- /example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 31 | 32 | 33 | 34 | 40 | 41 | 42 | 43 | 44 | 45 | 56 | 58 | 64 | 65 | 66 | 67 | 68 | 69 | 75 | 77 | 83 | 84 | 85 | 86 | 88 | 89 | 92 | 93 | 94 | -------------------------------------------------------------------------------- /example/ios/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/ios/Runner/AppDelegate.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | 4 | @interface AppDelegate : FlutterAppDelegate 5 | 6 | @end 7 | -------------------------------------------------------------------------------- /example/ios/Runner/AppDelegate.m: -------------------------------------------------------------------------------- 1 | #include "AppDelegate.h" 2 | #include "GeneratedPluginRegistrant.h" 3 | 4 | @implementation AppDelegate 5 | 6 | - (BOOL)application:(UIApplication *)application 7 | didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 8 | [GeneratedPluginRegistrant registerWithRegistry:self]; 9 | // Override point for customization after application launch. 10 | return [super application:application didFinishLaunchingWithOptions:launchOptions]; 11 | } 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "20x20", 5 | "idiom" : "iphone", 6 | "filename" : "Icon-App-20x20@2x.png", 7 | "scale" : "2x" 8 | }, 9 | { 10 | "size" : "20x20", 11 | "idiom" : "iphone", 12 | "filename" : "Icon-App-20x20@3x.png", 13 | "scale" : "3x" 14 | }, 15 | { 16 | "size" : "29x29", 17 | "idiom" : "iphone", 18 | "filename" : "Icon-App-29x29@1x.png", 19 | "scale" : "1x" 20 | }, 21 | { 22 | "size" : "29x29", 23 | "idiom" : "iphone", 24 | "filename" : "Icon-App-29x29@2x.png", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "size" : "29x29", 29 | "idiom" : "iphone", 30 | "filename" : "Icon-App-29x29@3x.png", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "size" : "40x40", 35 | "idiom" : "iphone", 36 | "filename" : "Icon-App-40x40@2x.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "40x40", 41 | "idiom" : "iphone", 42 | "filename" : "Icon-App-40x40@3x.png", 43 | "scale" : "3x" 44 | }, 45 | { 46 | "size" : "60x60", 47 | "idiom" : "iphone", 48 | "filename" : "Icon-App-60x60@2x.png", 49 | "scale" : "2x" 50 | }, 51 | { 52 | "size" : "60x60", 53 | "idiom" : "iphone", 54 | "filename" : "Icon-App-60x60@3x.png", 55 | "scale" : "3x" 56 | }, 57 | { 58 | "size" : "20x20", 59 | "idiom" : "ipad", 60 | "filename" : "Icon-App-20x20@1x.png", 61 | "scale" : "1x" 62 | }, 63 | { 64 | "size" : "20x20", 65 | "idiom" : "ipad", 66 | "filename" : "Icon-App-20x20@2x.png", 67 | "scale" : "2x" 68 | }, 69 | { 70 | "size" : "29x29", 71 | "idiom" : "ipad", 72 | "filename" : "Icon-App-29x29@1x.png", 73 | "scale" : "1x" 74 | }, 75 | { 76 | "size" : "29x29", 77 | "idiom" : "ipad", 78 | "filename" : "Icon-App-29x29@2x.png", 79 | "scale" : "2x" 80 | }, 81 | { 82 | "size" : "40x40", 83 | "idiom" : "ipad", 84 | "filename" : "Icon-App-40x40@1x.png", 85 | "scale" : "1x" 86 | }, 87 | { 88 | "size" : "40x40", 89 | "idiom" : "ipad", 90 | "filename" : "Icon-App-40x40@2x.png", 91 | "scale" : "2x" 92 | }, 93 | { 94 | "size" : "76x76", 95 | "idiom" : "ipad", 96 | "filename" : "Icon-App-76x76@1x.png", 97 | "scale" : "1x" 98 | }, 99 | { 100 | "size" : "76x76", 101 | "idiom" : "ipad", 102 | "filename" : "Icon-App-76x76@2x.png", 103 | "scale" : "2x" 104 | }, 105 | { 106 | "size" : "83.5x83.5", 107 | "idiom" : "ipad", 108 | "filename" : "Icon-App-83.5x83.5@2x.png", 109 | "scale" : "2x" 110 | }, 111 | { 112 | "size" : "1024x1024", 113 | "idiom" : "ios-marketing", 114 | "filename" : "Icon-App-1024x1024@1x.png", 115 | "scale" : "1x" 116 | } 117 | ], 118 | "info" : { 119 | "version" : 1, 120 | "author" : "xcode" 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quentinleguennec/flutter-arrow-path/1d37eab5fe676d93ac64f76a8f6fced1a7b0e44c/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quentinleguennec/flutter-arrow-path/1d37eab5fe676d93ac64f76a8f6fced1a7b0e44c/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quentinleguennec/flutter-arrow-path/1d37eab5fe676d93ac64f76a8f6fced1a7b0e44c/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quentinleguennec/flutter-arrow-path/1d37eab5fe676d93ac64f76a8f6fced1a7b0e44c/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quentinleguennec/flutter-arrow-path/1d37eab5fe676d93ac64f76a8f6fced1a7b0e44c/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quentinleguennec/flutter-arrow-path/1d37eab5fe676d93ac64f76a8f6fced1a7b0e44c/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quentinleguennec/flutter-arrow-path/1d37eab5fe676d93ac64f76a8f6fced1a7b0e44c/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quentinleguennec/flutter-arrow-path/1d37eab5fe676d93ac64f76a8f6fced1a7b0e44c/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quentinleguennec/flutter-arrow-path/1d37eab5fe676d93ac64f76a8f6fced1a7b0e44c/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quentinleguennec/flutter-arrow-path/1d37eab5fe676d93ac64f76a8f6fced1a7b0e44c/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quentinleguennec/flutter-arrow-path/1d37eab5fe676d93ac64f76a8f6fced1a7b0e44c/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quentinleguennec/flutter-arrow-path/1d37eab5fe676d93ac64f76a8f6fced1a7b0e44c/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quentinleguennec/flutter-arrow-path/1d37eab5fe676d93ac64f76a8f6fced1a7b0e44c/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quentinleguennec/flutter-arrow-path/1d37eab5fe676d93ac64f76a8f6fced1a7b0e44c/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quentinleguennec/flutter-arrow-path/1d37eab5fe676d93ac64f76a8f6fced1a7b0e44c/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "LaunchImage.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "LaunchImage@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "LaunchImage@3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quentinleguennec/flutter-arrow-path/1d37eab5fe676d93ac64f76a8f6fced1a7b0e44c/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quentinleguennec/flutter-arrow-path/1d37eab5fe676d93ac64f76a8f6fced1a7b0e44c/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/quentinleguennec/flutter-arrow-path/1d37eab5fe676d93ac64f76a8f6fced1a7b0e44c/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md: -------------------------------------------------------------------------------- 1 | # Launch Screen Assets 2 | 3 | You can customize the launch screen with your own desired assets by replacing the image files in this directory. 4 | 5 | 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. -------------------------------------------------------------------------------- /example/ios/Runner/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /example/ios/Runner/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /example/ios/Runner/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | example 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | $(FLUTTER_BUILD_NAME) 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(FLUTTER_BUILD_NUMBER) 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UISupportedInterfaceOrientations 30 | 31 | UIInterfaceOrientationPortrait 32 | UIInterfaceOrientationLandscapeLeft 33 | UIInterfaceOrientationLandscapeRight 34 | 35 | UISupportedInterfaceOrientations~ipad 36 | 37 | UIInterfaceOrientationPortrait 38 | UIInterfaceOrientationPortraitUpsideDown 39 | UIInterfaceOrientationLandscapeLeft 40 | UIInterfaceOrientationLandscapeRight 41 | 42 | UIViewControllerBasedStatusBarAppearance 43 | 44 | CADisableMinimumFrameDurationOnPhone 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /example/ios/Runner/main.m: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | #import "AppDelegate.h" 4 | 5 | int main(int argc, char* argv[]) { 6 | @autoreleasepool { 7 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /example/lib/main.dart: -------------------------------------------------------------------------------- 1 | import 'dart:math' as math; 2 | 3 | import 'package:arrow_path/arrow_path.dart'; 4 | import 'package:flutter/material.dart'; 5 | 6 | void main() => runApp(const MyApp()); 7 | 8 | class MyApp extends StatelessWidget { 9 | const MyApp({Key? key}) : super(key: key); 10 | 11 | @override 12 | Widget build(BuildContext context) => MaterialApp( 13 | title: 'Arrow Path Example', 14 | theme: ThemeData(primarySwatch: Colors.blue), 15 | home: const ExampleApp(), 16 | ); 17 | } 18 | 19 | class ExampleApp extends StatelessWidget { 20 | const ExampleApp({Key? key}) : super(key: key); 21 | 22 | @override 23 | Widget build(BuildContext context) => Scaffold( 24 | appBar: AppBar( 25 | title: const Text('Arrow Path Example'), 26 | ), 27 | body: SingleChildScrollView( 28 | child: ClipRect( 29 | child: CustomPaint( 30 | size: Size(MediaQuery.of(context).size.width, 700), 31 | painter: ArrowPainter(), 32 | ), 33 | ), 34 | ), 35 | ); 36 | } 37 | 38 | class ArrowPainter extends CustomPainter { 39 | @override 40 | void paint(Canvas canvas, Size size) { 41 | /// The arrows usually looks better with rounded caps. 42 | final Paint paint = Paint() 43 | ..color = Colors.black 44 | ..style = PaintingStyle.stroke 45 | ..strokeCap = StrokeCap.round 46 | ..strokeJoin = StrokeJoin.round 47 | ..strokeWidth = 3.0; 48 | 49 | /// Draw a single arrow. 50 | { 51 | Path path = Path(); 52 | path.moveTo(size.width * 0.25, 60); 53 | path.relativeCubicTo(0, 0, size.width * 0.25, 50, size.width * 0.5, 0); 54 | path = ArrowPath.addTip(path); 55 | 56 | canvas.drawPath(path, paint..color = Colors.blue); 57 | 58 | const TextSpan textSpan = TextSpan( 59 | text: 'Single arrow', 60 | style: TextStyle(color: Colors.blue), 61 | ); 62 | final TextPainter textPainter = TextPainter( 63 | text: textSpan, 64 | textAlign: TextAlign.center, 65 | textDirection: TextDirection.ltr, 66 | ); 67 | textPainter.layout(minWidth: size.width); 68 | textPainter.paint(canvas, const Offset(0, 36)); 69 | } 70 | 71 | /// Draw a double sided arrow. 72 | { 73 | Path path = Path(); 74 | path.moveTo(size.width * 0.25, 120); 75 | path.relativeCubicTo(0, 0, size.width * 0.25, 50, size.width * 0.5, 0); 76 | path = ArrowPath.addTip(path); 77 | path = ArrowPath.addTip(path, isBackward: true); 78 | 79 | canvas.drawPath(path, paint..color = Colors.cyan); 80 | 81 | const TextSpan textSpan = TextSpan( 82 | text: 'Double sided arrow', 83 | style: TextStyle(color: Colors.cyan), 84 | ); 85 | final TextPainter textPainter = TextPainter( 86 | text: textSpan, 87 | textAlign: TextAlign.center, 88 | textDirection: TextDirection.ltr, 89 | ); 90 | textPainter.layout(minWidth: size.width); 91 | textPainter.paint(canvas, const Offset(0, 96)); 92 | } 93 | 94 | /// Use complex path. 95 | { 96 | Path path = Path(); 97 | path.moveTo(size.width * 0.25, 180); 98 | path.relativeCubicTo(0, 0, size.width * 0.25, 50, size.width * 0.5, 50); 99 | path.relativeCubicTo(0, 0, -size.width * 0.25, 0, -size.width * 0.5, 50); 100 | path.relativeCubicTo(0, 0, size.width * 0.125, 10, size.width * 0.25, -10); 101 | path = ArrowPath.addTip(path); 102 | canvas.drawPath(path, paint..color = Colors.blue); 103 | 104 | const TextSpan textSpan = TextSpan( 105 | text: 'Complex path', 106 | style: TextStyle(color: Colors.blue), 107 | ); 108 | final TextPainter textPainter = TextPainter( 109 | text: textSpan, 110 | textAlign: TextAlign.center, 111 | textDirection: TextDirection.ltr, 112 | ); 113 | textPainter.layout(minWidth: size.width); 114 | textPainter.paint(canvas, const Offset(0, 168)); 115 | } 116 | 117 | /// Path with several forward arrow and one backward arrow. 118 | /// IMPORTANT: You should never use more than a single backward arrow on the same path, or the results 119 | /// may be unpredictable due to limitations of the Path API. 120 | /// 121 | /// If you need to build a complex path with several backward arrows then use sub-paths and 122 | /// merge them with Path.addPath (see after). 123 | { 124 | Path path = Path(); 125 | path.moveTo(size.width * 0.25, 358); 126 | path.relativeLineTo(size.width * 0.13, 50); 127 | path = ArrowPath.addTip(path, tipAngle: math.pi * 0.1); 128 | path.relativeLineTo(size.width * 0.13, -50); 129 | path = ArrowPath.addTip(path, tipAngle: math.pi * 0.1); 130 | path.relativeLineTo(size.width * 0.08, 50); 131 | path = ArrowPath.addTip(path, tipAngle: math.pi * 0.1); 132 | path.relativeLineTo(size.width * 0.08, -50); 133 | path = ArrowPath.addTip(path, tipAngle: math.pi * 0.1); 134 | path.relativeLineTo(size.width * 0.04, 50); 135 | path = ArrowPath.addTip(path, tipAngle: math.pi * 0.1); 136 | path.relativeLineTo(size.width * 0.04, -50); 137 | path = ArrowPath.addTip(path, tipAngle: math.pi * 0.1); 138 | path = ArrowPath.addTip(path, tipAngle: math.pi * 0.1, isBackward: true); 139 | 140 | canvas.drawPath(path, paint..color = Colors.cyan); 141 | 142 | const TextSpan textSpan = TextSpan( 143 | text: 'Single Path with multiple forward and one backward arrow tips.', 144 | style: TextStyle(color: Colors.cyan), 145 | ); 146 | final TextPainter textPainter = TextPainter( 147 | text: textSpan, 148 | textAlign: TextAlign.center, 149 | textDirection: TextDirection.ltr, 150 | ); 151 | textPainter.layout(minWidth: size.width); 152 | textPainter.paint(canvas, const Offset(0, 326)); 153 | } 154 | 155 | /// Path with several backward arrow and one forward arrow. 156 | /// IMPORTANT: Due to limitations of the Path API this can only be achieved reliably by using sub-paths. 157 | { 158 | Path path = Path(); 159 | Offset penPosition = Offset(size.width * 0.25, 470); 160 | path.moveTo(penPosition.dx, penPosition.dy); 161 | penPosition += Offset(size.width * 0.13, 50); 162 | path.lineTo(penPosition.dx, penPosition.dy); 163 | path = ArrowPath.addTip(path, tipAngle: math.pi * 0.1, isBackward: true); 164 | 165 | Path subPath = Path(); 166 | subPath.moveTo(penPosition.dx, penPosition.dy); 167 | penPosition += Offset(size.width * 0.13, -50); 168 | subPath.lineTo(penPosition.dx, penPosition.dy); 169 | subPath = ArrowPath.addTip(subPath, tipAngle: math.pi * 0.1, isBackward: true); 170 | path.addPath(subPath, Offset.zero); 171 | 172 | subPath = Path(); 173 | subPath.moveTo(penPosition.dx, penPosition.dy); 174 | penPosition += Offset(size.width * 0.08, 50); 175 | subPath.lineTo(penPosition.dx, penPosition.dy); 176 | subPath = ArrowPath.addTip(subPath, tipAngle: math.pi * 0.1, isBackward: true); 177 | path.addPath(subPath, Offset.zero); 178 | 179 | subPath = Path(); 180 | subPath.moveTo(penPosition.dx, penPosition.dy); 181 | penPosition += Offset(size.width * 0.08, -50); 182 | subPath.lineTo(penPosition.dx, penPosition.dy); 183 | subPath = ArrowPath.addTip(subPath, tipAngle: math.pi * 0.1, isBackward: true); 184 | path.addPath(subPath, Offset.zero); 185 | 186 | subPath = Path(); 187 | subPath.moveTo(penPosition.dx, penPosition.dy); 188 | penPosition += Offset(size.width * 0.04, 50); 189 | subPath.lineTo(penPosition.dx, penPosition.dy); 190 | subPath = ArrowPath.addTip(subPath, tipAngle: math.pi * 0.1, isBackward: true); 191 | path.addPath(subPath, Offset.zero); 192 | 193 | subPath = Path(); 194 | subPath.moveTo(penPosition.dx, penPosition.dy); 195 | penPosition += Offset(size.width * 0.04, -50); 196 | subPath.lineTo(penPosition.dx, penPosition.dy); 197 | subPath = ArrowPath.addTip(subPath, tipAngle: math.pi * 0.1, isBackward: true); 198 | path.addPath(subPath, Offset.zero); 199 | 200 | path = ArrowPath.addTip(path, tipAngle: math.pi * 0.1); 201 | 202 | canvas.drawPath(path, paint..color = Colors.blue); 203 | 204 | const TextSpan textSpan = TextSpan( 205 | text: 'Single Path with multiple backward arrow tips.', 206 | style: TextStyle(color: Colors.blue), 207 | ); 208 | final TextPainter textPainter = TextPainter( 209 | text: textSpan, 210 | textAlign: TextAlign.center, 211 | textDirection: TextDirection.ltr, 212 | ); 213 | textPainter.layout(minWidth: size.width); 214 | textPainter.paint(canvas, const Offset(0, 436)); 215 | } 216 | 217 | /// Adjusted 218 | { 219 | Path path = Path(); 220 | path.moveTo(size.width * 0.1, 590); 221 | path.relativeCubicTo(0, 0, size.width * 0.3, 50, size.width * 0.25, 75); 222 | path = ArrowPath.addTip(path, isAdjusted: true); 223 | canvas.drawPath(path, paint..color = Colors.cyan); 224 | 225 | const TextSpan textSpan = TextSpan( 226 | text: 'Adjusted', 227 | style: TextStyle(color: Colors.cyan), 228 | ); 229 | final TextPainter textPainter = TextPainter( 230 | text: textSpan, 231 | textAlign: TextAlign.left, 232 | textDirection: TextDirection.ltr, 233 | ); 234 | textPainter.layout(); 235 | textPainter.paint(canvas, Offset(size.width * 0.2, 572)); 236 | } 237 | 238 | /// Non adjusted. 239 | { 240 | Path path = Path(); 241 | path.moveTo(size.width * 0.6, 590); 242 | path.relativeCubicTo(0, 0, size.width * 0.3, 50, size.width * 0.25, 75); 243 | path = ArrowPath.addTip(path, isAdjusted: false); 244 | 245 | canvas.drawPath(path, paint..color = Colors.cyan); 246 | 247 | const TextSpan textSpan = TextSpan( 248 | text: 'Non adjusted', 249 | style: TextStyle(color: Colors.cyan), 250 | ); 251 | final TextPainter textPainter = TextPainter( 252 | text: textSpan, 253 | textAlign: TextAlign.left, 254 | textDirection: TextDirection.ltr, 255 | ); 256 | textPainter.layout(); 257 | textPainter.paint(canvas, Offset(size.width * 0.65, 572)); 258 | } 259 | } 260 | 261 | @override 262 | bool shouldRepaint(ArrowPainter oldDelegate) => false; 263 | } 264 | -------------------------------------------------------------------------------- /example/pubspec.lock: -------------------------------------------------------------------------------- 1 | # Generated by pub 2 | # See https://dart.dev/tools/pub/glossary#lockfile 3 | packages: 4 | arrow_path: 5 | dependency: "direct main" 6 | description: 7 | path: ".." 8 | relative: true 9 | source: path 10 | version: "3.1.0" 11 | characters: 12 | dependency: transitive 13 | description: 14 | name: characters 15 | sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605" 16 | url: "https://pub.dev" 17 | source: hosted 18 | version: "1.3.0" 19 | collection: 20 | dependency: transitive 21 | description: 22 | name: collection 23 | sha256: "4a07be6cb69c84d677a6c3096fcf960cc3285a8330b4603e0d463d15d9bd934c" 24 | url: "https://pub.dev" 25 | source: hosted 26 | version: "1.17.1" 27 | flutter: 28 | dependency: "direct main" 29 | description: flutter 30 | source: sdk 31 | version: "0.0.0" 32 | flutter_lints: 33 | dependency: "direct dev" 34 | description: 35 | name: flutter_lints 36 | sha256: aeb0b80a8b3709709c9cc496cdc027c5b3216796bc0af0ce1007eaf24464fd4c 37 | url: "https://pub.dev" 38 | source: hosted 39 | version: "2.0.1" 40 | js: 41 | dependency: transitive 42 | description: 43 | name: js 44 | sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3 45 | url: "https://pub.dev" 46 | source: hosted 47 | version: "0.6.7" 48 | lints: 49 | dependency: transitive 50 | description: 51 | name: lints 52 | sha256: "5cfd6509652ff5e7fe149b6df4859e687fca9048437857cb2e65c8d780f396e3" 53 | url: "https://pub.dev" 54 | source: hosted 55 | version: "2.0.0" 56 | material_color_utilities: 57 | dependency: transitive 58 | description: 59 | name: material_color_utilities 60 | sha256: d92141dc6fe1dad30722f9aa826c7fbc896d021d792f80678280601aff8cf724 61 | url: "https://pub.dev" 62 | source: hosted 63 | version: "0.2.0" 64 | meta: 65 | dependency: transitive 66 | description: 67 | name: meta 68 | sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3" 69 | url: "https://pub.dev" 70 | source: hosted 71 | version: "1.9.1" 72 | sky_engine: 73 | dependency: transitive 74 | description: flutter 75 | source: sdk 76 | version: "0.0.99" 77 | vector_math: 78 | dependency: transitive 79 | description: 80 | name: vector_math 81 | sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" 82 | url: "https://pub.dev" 83 | source: hosted 84 | version: "2.1.4" 85 | sdks: 86 | dart: ">=3.0.0-0 <4.0.0" 87 | -------------------------------------------------------------------------------- /example/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: arrow_path_example 2 | description: Example project for the arrow_path package. 3 | 4 | # The following line prevents the package from being accidentally published to 5 | # pub.dev using `flutter pub publish`. This is preferred for private packages. 6 | publish_to: 'none' 7 | 8 | version: 1.0.1+2 9 | 10 | environment: 11 | sdk: ">=2.12.0 <4.0.0" 12 | 13 | dependencies: 14 | flutter: 15 | sdk: flutter 16 | arrow_path: 17 | path: ../ 18 | 19 | dev_dependencies: 20 | flutter_lints: ^2.0.1 21 | -------------------------------------------------------------------------------- /lib/arrow_path.dart: -------------------------------------------------------------------------------- 1 | library arrow_path; 2 | 3 | import 'dart:math' as math; 4 | import 'dart:ui'; 5 | 6 | class ArrowPath { 7 | /// Add an arrow to the end of the last drawn curve in the given path. 8 | /// 9 | /// The returned path is moved to the end of the curve. Always add the arrow before moving the path, not after, else the move will be lost. 10 | /// After adding the arrow you can move the path, draw more and apply an arrow to the new drawn part. 11 | /// 12 | /// If [isDoubleSided] is true (default to false), an arrow will also be added to the beginning of the first drawn curve. 13 | /// 14 | /// [tipLength] is the length (in pixels) of each of the 2 lines making the arrow. 15 | /// 16 | /// [tipAngle] is the angle (in radians) between each of the 2 lines making the arrow and the curve at this point. 17 | /// 18 | /// If [isAdjusted] is true (default to true), the tip of the arrow will be rotated (not following the tangent perfectly). 19 | /// This improves the look of the arrow when the end of the curve as a strong curvature. 20 | /// Can be disabled to save performance when the arrow is flat. 21 | /// 22 | /// If the given path is not suitable to draw the arrow head (for example if the path as no length) then the path will be returned unchanged. 23 | @Deprecated('This is deprecated and will be removed in a future release. Use ArrowPath.addTip instead.') 24 | static Path make({ 25 | required Path path, 26 | double tipLength = 15, 27 | double tipAngle = math.pi * 0.2, 28 | bool isDoubleSided = false, 29 | bool isAdjusted = true, 30 | }) { 31 | final List pathMetrics = path.computeMetrics().toList(); 32 | if (pathMetrics.isEmpty) { 33 | /// This can happen if the path as no length (trying to draw an arrow that is too small, like less than 1 pixel). 34 | return path; 35 | } 36 | 37 | tipAngle = math.pi - tipAngle; 38 | final PathMetric lastPathMetric = pathMetrics.last; 39 | final PathMetric firstPathMetric = pathMetrics.first; 40 | 41 | final Tangent? tangentLastPath = lastPathMetric.getTangentForOffset(lastPathMetric.length); 42 | 43 | if (tangentLastPath == null) { 44 | /// This should never happen. 45 | return path; 46 | } 47 | 48 | final Offset originalPosition = tangentLastPath.position; 49 | 50 | double adjustmentAngle = 0; 51 | if (isAdjusted && lastPathMetric.length > 10) { 52 | final Tangent tanBefore = lastPathMetric.getTangentForOffset(lastPathMetric.length - 5)!; 53 | adjustmentAngle = _getAngleBetweenVectors(tangentLastPath.vector, tanBefore.vector); 54 | } 55 | 56 | _addFullArrowTip( 57 | path: path, 58 | tangentVector: tangentLastPath.vector, 59 | tangentPosition: tangentLastPath.position, 60 | tipLength: tipLength, 61 | tipAngle: tipAngle, 62 | adjustmentAngle: adjustmentAngle, 63 | ); 64 | 65 | if (isDoubleSided) { 66 | /// This path is double side, add the other arrow tip. 67 | final Tangent? tangentFirstPath = firstPathMetric.getTangentForOffset(0); 68 | if (tangentFirstPath != null) { 69 | if (isAdjusted && firstPathMetric.length > 10) { 70 | final Tangent tanBefore = firstPathMetric.getTangentForOffset(5)!; 71 | adjustmentAngle = _getAngleBetweenVectors(tangentFirstPath.vector, tanBefore.vector); 72 | } 73 | 74 | _addFullArrowTip( 75 | path: path, 76 | tangentVector: -tangentFirstPath.vector, 77 | tangentPosition: tangentFirstPath.position, 78 | tipLength: tipLength, 79 | tipAngle: tipAngle, 80 | adjustmentAngle: adjustmentAngle, 81 | ); 82 | } 83 | } 84 | 85 | path.moveTo(originalPosition.dx, originalPosition.dy); 86 | 87 | return path; 88 | } 89 | 90 | /// Add an arrow to the end of the last drawn curve in the given path. 91 | /// 92 | /// The returned path is moved to the end of the curve. Always add the arrow before moving the path, not after, else the move will be lost. 93 | /// After adding the arrow you can move the path, draw more and apply an arrow to the new drawn part. 94 | /// 95 | /// If [isBackward] is true (default to false), the arrow will be added to the beginning of the first drawn curve instead of the end. 96 | /// This should never be called more than once on the same path. If you want to make a path with several backward arrows then use sub-paths and 97 | /// merge them with [Path.addPath]. 98 | /// 99 | /// [tipLength] is the length (in pixels) of each of the 2 lines making the arrow. 100 | /// 101 | /// [tipAngle] is the angle (in radians) between each of the 2 lines making the arrow and the curve at this point. 102 | /// 103 | /// If [isAdjusted] is true (default to true), the tip of the arrow will be rotated (not following the tangent perfectly). 104 | /// This improves the look of the arrow when the end of the curve as a strong curvature. 105 | /// Can be disabled to save performance when the arrow is flat. 106 | /// 107 | /// If the given path is not suitable to draw the arrow head (for example if the path as no length) then the path will be returned unchanged. 108 | static Path addTip( 109 | Path path, { 110 | double tipLength = 15, 111 | double tipAngle = math.pi * 0.2, 112 | bool isBackward = false, 113 | bool isAdjusted = true, 114 | }) { 115 | path = Path.from(path); 116 | 117 | final List pathMetrics = path.computeMetrics().toList(); 118 | if (pathMetrics.isEmpty) { 119 | /// This can happen if the path as no length (trying to draw an arrow that is too small, like less than 1 pixel). 120 | return path; 121 | } 122 | 123 | final Offset? originalPosition = _getPathEndPosition(pathMetrics); 124 | if (originalPosition == null) { 125 | /// This should never happen. 126 | return path; 127 | } 128 | 129 | tipAngle = math.pi - tipAngle; 130 | final PathMetric pathMetric = isBackward ? pathMetrics.first : pathMetrics.last; 131 | 132 | final Tangent? tangent = pathMetric.getTangentForOffset(isBackward ? 0 : pathMetric.length); 133 | if (tangent == null) { 134 | /// This should never happen. 135 | return path; 136 | } 137 | 138 | double adjustmentAngle = 0; 139 | if (isAdjusted && pathMetric.length > 10) { 140 | final Tangent tangentBefore = pathMetric.getTangentForOffset(isBackward ? 5 : pathMetric.length - 5)!; 141 | adjustmentAngle = _getAngleBetweenVectors(tangent.vector, tangentBefore.vector); 142 | } 143 | 144 | if (isBackward) { 145 | /// Using a temporary [Path] and [Path.addPath] because we want the backward arrow to always be at the start of the [PathMetrics]. 146 | /// This is important because calling [Path.moveTo] does NOT actually create a segment, so the move information is lost we next read [PathMetrics]. 147 | /// See [_getPathEndPosition] for more info. 148 | final tempoPath = Path(); 149 | 150 | tempoPath.moveTo(tangent.position.dx, tangent.position.dy); 151 | 152 | _addFullArrowTip( 153 | path: tempoPath, 154 | tangentVector: -tangent.vector, 155 | tangentPosition: tangent.position, 156 | tipLength: tipLength, 157 | tipAngle: tipAngle, 158 | adjustmentAngle: adjustmentAngle, 159 | ); 160 | tempoPath.addPath(path, Offset.zero); 161 | return tempoPath; 162 | } else { 163 | _addFullArrowTip( 164 | path: path, 165 | tangentVector: tangent.vector, 166 | tangentPosition: tangent.position, 167 | tipLength: tipLength, 168 | tipAngle: tipAngle, 169 | adjustmentAngle: adjustmentAngle, 170 | ); 171 | } 172 | 173 | return path; 174 | } 175 | 176 | static void _addFullArrowTip({ 177 | required Path path, 178 | required Offset tangentVector, 179 | required Offset tangentPosition, 180 | required double tipLength, 181 | required double tipAngle, 182 | required double adjustmentAngle, 183 | }) { 184 | _addPartialArrowTip( 185 | tangentVector: tangentVector, 186 | tangentPosition: tangentPosition, 187 | path: path, 188 | tipLength: tipLength, 189 | tipAngle: tipAngle, 190 | adjustmentAngle: adjustmentAngle, 191 | ); 192 | _addPartialArrowTip( 193 | tangentVector: tangentVector, 194 | tangentPosition: tangentPosition, 195 | path: path, 196 | tipLength: tipLength, 197 | tipAngle: -tipAngle, 198 | adjustmentAngle: adjustmentAngle, 199 | ); 200 | } 201 | 202 | /// We need to make sure we end by drawing back to the start position, because simply doing a moveTo does NOT save to 203 | /// the [PathMetrics], so the move is lost and this causes issues for successive arrow tip drawings. 204 | static void _addPartialArrowTip({ 205 | required Path path, 206 | required Offset tangentVector, 207 | required Offset tangentPosition, 208 | required double tipLength, 209 | required double tipAngle, 210 | required double adjustmentAngle, 211 | }) { 212 | final Offset tipVector = _rotateVector(tangentVector, tipAngle - adjustmentAngle) * tipLength; 213 | path.relativeMoveTo(tipVector.dx, tipVector.dy); 214 | path.relativeLineTo(-tipVector.dx, -tipVector.dy); 215 | } 216 | 217 | /// Defining the Path end is tricky, ideally we would want to get the position of the last moveTo from the Path, but his is not 218 | /// possible (there is no way to get that from the Path API). 219 | /// Instead we have to use the last PathMetric (the segment that was last drawn) and hope it is what we want it to be. 220 | /// This would fails for example if we where adding the backward arrow directly to the end of the path, because even doing 221 | /// a moveTo back to the end of the path (before we added the arrow tip) would not allow us to get the right position if 222 | /// we try to draw a forward arrow straight after. Instead, the forward arrow would be draw at the last lineTo position (not the 223 | /// last moveTo position), which would happen to be at the start of the path (since it's were we last drawn something). 224 | /// This is why we use a temporary path to draw the backward arrow tip, and we add the path as a sub-path 225 | /// of the temporary path. Then we reassign the path with `path = subpath`. This allow us to have the backward arrow at 226 | /// the start of the PathMetrics, rather than the end, and then we can draw any following forward arrow correctly. 227 | static Offset? _getPathEndPosition(List pathMetrics) { 228 | final Tangent? tangent = pathMetrics.last.getTangentForOffset(pathMetrics.last.length); 229 | 230 | if (tangent == null) { 231 | /// This should never happen. 232 | return null; 233 | } 234 | 235 | return tangent.position; 236 | } 237 | 238 | static Offset _rotateVector(Offset vector, double angle) => Offset( 239 | math.cos(angle) * vector.dx - math.sin(angle) * vector.dy, 240 | math.sin(angle) * vector.dx + math.cos(angle) * vector.dy, 241 | ); 242 | 243 | static double _getVectorsDotProduct(Offset vector1, Offset vector2) => 244 | vector1.dx * vector2.dx + vector1.dy * vector2.dy; 245 | 246 | /// Clamp to avoid rounding issues when the 2 vectors are equal. 247 | static double _getAngleBetweenVectors(Offset vector1, Offset vector2) => math.acos( 248 | (_getVectorsDotProduct(vector1, vector2) / (vector1.distance * vector2.distance)).clamp(-1.0, 1.0), 249 | ); 250 | } 251 | -------------------------------------------------------------------------------- /pubspec.lock: -------------------------------------------------------------------------------- 1 | # Generated by pub 2 | # See https://dart.dev/tools/pub/glossary#lockfile 3 | packages: 4 | characters: 5 | dependency: transitive 6 | description: 7 | name: characters 8 | sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605" 9 | url: "https://pub.dev" 10 | source: hosted 11 | version: "1.3.0" 12 | collection: 13 | dependency: transitive 14 | description: 15 | name: collection 16 | sha256: "4a07be6cb69c84d677a6c3096fcf960cc3285a8330b4603e0d463d15d9bd934c" 17 | url: "https://pub.dev" 18 | source: hosted 19 | version: "1.17.1" 20 | flutter: 21 | dependency: "direct main" 22 | description: flutter 23 | source: sdk 24 | version: "0.0.0" 25 | flutter_lints: 26 | dependency: "direct dev" 27 | description: 28 | name: flutter_lints 29 | sha256: aeb0b80a8b3709709c9cc496cdc027c5b3216796bc0af0ce1007eaf24464fd4c 30 | url: "https://pub.dev" 31 | source: hosted 32 | version: "2.0.1" 33 | js: 34 | dependency: transitive 35 | description: 36 | name: js 37 | sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3 38 | url: "https://pub.dev" 39 | source: hosted 40 | version: "0.6.7" 41 | lints: 42 | dependency: transitive 43 | description: 44 | name: lints 45 | sha256: "5cfd6509652ff5e7fe149b6df4859e687fca9048437857cb2e65c8d780f396e3" 46 | url: "https://pub.dev" 47 | source: hosted 48 | version: "2.0.0" 49 | material_color_utilities: 50 | dependency: transitive 51 | description: 52 | name: material_color_utilities 53 | sha256: d92141dc6fe1dad30722f9aa826c7fbc896d021d792f80678280601aff8cf724 54 | url: "https://pub.dev" 55 | source: hosted 56 | version: "0.2.0" 57 | meta: 58 | dependency: transitive 59 | description: 60 | name: meta 61 | sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3" 62 | url: "https://pub.dev" 63 | source: hosted 64 | version: "1.9.1" 65 | sky_engine: 66 | dependency: transitive 67 | description: flutter 68 | source: sdk 69 | version: "0.0.99" 70 | vector_math: 71 | dependency: transitive 72 | description: 73 | name: vector_math 74 | sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" 75 | url: "https://pub.dev" 76 | source: hosted 77 | version: "2.1.4" 78 | sdks: 79 | dart: ">=3.0.0-0 <4.0.0" 80 | -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: arrow_path 2 | description: Draw arrows with Path objects easily. Paths can be composited to add arrows to any curve and draw all at once. 3 | version: 3.1.0 4 | homepage: https://github.com/quentinleguennec/flutter-arrow-path.git 5 | 6 | environment: 7 | sdk: ">=2.12.0 <4.0.0" 8 | 9 | dependencies: 10 | flutter: 11 | sdk: flutter 12 | 13 | dev_dependencies: 14 | flutter_lints: ^2.0.1 15 | --------------------------------------------------------------------------------