├── .github └── workflows │ └── flutter.yml ├── .gitignore ├── .metadata ├── .vscode └── settings.json ├── CHANGELOG.md ├── LICENSE ├── README.md ├── analysis_options.yaml ├── example ├── .gitignore ├── .metadata ├── README.md ├── analysis_options.yaml ├── android │ ├── .gitignore │ ├── app │ │ ├── build.gradle │ │ └── src │ │ │ ├── debug │ │ │ └── AndroidManifest.xml │ │ │ ├── main │ │ │ ├── AndroidManifest.xml │ │ │ ├── kotlin │ │ │ │ └── com │ │ │ │ │ └── example │ │ │ │ │ └── example │ │ │ │ │ └── MainActivity.kt │ │ │ └── res │ │ │ │ ├── drawable-v21 │ │ │ │ └── launch_background.xml │ │ │ │ ├── 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-night │ │ │ │ └── styles.xml │ │ │ │ └── values │ │ │ │ └── styles.xml │ │ │ └── profile │ │ │ └── AndroidManifest.xml │ ├── build.gradle │ ├── gradle.properties │ ├── gradle │ │ └── wrapper │ │ │ └── gradle-wrapper.properties │ └── settings.gradle ├── ios │ ├── .gitignore │ ├── Flutter │ │ ├── AppFrameworkInfo.plist │ │ ├── Debug.xcconfig │ │ └── Release.xcconfig │ ├── Runner.xcodeproj │ │ ├── project.pbxproj │ │ ├── project.xcworkspace │ │ │ ├── contents.xcworkspacedata │ │ │ └── xcshareddata │ │ │ │ ├── IDEWorkspaceChecks.plist │ │ │ │ └── WorkspaceSettings.xcsettings │ │ └── xcshareddata │ │ │ └── xcschemes │ │ │ └── Runner.xcscheme │ ├── Runner.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ ├── IDEWorkspaceChecks.plist │ │ │ └── WorkspaceSettings.xcsettings │ └── Runner │ │ ├── AppDelegate.swift │ │ ├── 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 │ │ └── Runner-Bridging-Header.h ├── lib │ ├── convenient_painting.dart │ ├── curves_demo.dart │ ├── examples.dart │ ├── hello_solandra.dart │ ├── hello_solandra_five.dart │ ├── hello_solandra_four.dart │ ├── hello_solandra_seven.dart │ ├── hello_solandra_six.dart │ ├── hello_solandra_three.dart │ ├── hello_solandra_two.dart │ ├── home_screen.dart │ ├── main.dart │ └── wallpaper_creator.dart ├── macos │ ├── .gitignore │ ├── Flutter │ │ ├── Flutter-Debug.xcconfig │ │ ├── Flutter-Release.xcconfig │ │ └── GeneratedPluginRegistrant.swift │ ├── Runner.xcodeproj │ │ ├── project.pbxproj │ │ ├── project.xcworkspace │ │ │ └── xcshareddata │ │ │ │ └── IDEWorkspaceChecks.plist │ │ └── xcshareddata │ │ │ └── xcschemes │ │ │ └── Runner.xcscheme │ ├── Runner.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ └── IDEWorkspaceChecks.plist │ └── Runner │ │ ├── AppDelegate.swift │ │ ├── Assets.xcassets │ │ └── AppIcon.appiconset │ │ │ ├── Contents.json │ │ │ ├── app_icon_1024.png │ │ │ ├── app_icon_128.png │ │ │ ├── app_icon_16.png │ │ │ ├── app_icon_256.png │ │ │ ├── app_icon_32.png │ │ │ ├── app_icon_512.png │ │ │ └── app_icon_64.png │ │ ├── Base.lproj │ │ └── MainMenu.xib │ │ ├── Configs │ │ ├── AppInfo.xcconfig │ │ ├── Debug.xcconfig │ │ ├── Release.xcconfig │ │ └── Warnings.xcconfig │ │ ├── DebugProfile.entitlements │ │ ├── Info.plist │ │ ├── MainFlutterWindow.swift │ │ └── Release.entitlements ├── pubspec.lock ├── pubspec.yaml ├── test │ └── widget_test.dart └── web │ ├── favicon.png │ ├── icons │ ├── Icon-192.png │ ├── Icon-512.png │ ├── Icon-maskable-192.png │ └── Icon-maskable-512.png │ ├── index.html │ └── manifest.json ├── lib ├── iteration.dart ├── path.dart ├── solandra.dart ├── solandra_canvas.dart ├── solandra_renderer.dart └── util │ ├── color.dart │ ├── convenience.dart │ └── data.dart ├── pubspec.lock ├── pubspec.yaml ├── sample-images ├── 1.png ├── 2.png └── solandra-flutter-mac-sample.png └── test ├── color_test.dart └── convenience_test.dart /.github/workflows/flutter.yml: -------------------------------------------------------------------------------- 1 | name: Flutter Package Test 2 | 3 | on: 4 | push: 5 | branches: [main] 6 | pull_request: 7 | branches: [main] 8 | 9 | jobs: 10 | build: 11 | runs-on: ubuntu-latest 12 | 13 | steps: 14 | - uses: actions/checkout@v2 15 | - uses: actions/setup-java@v1 16 | with: 17 | java-version: "12.x" 18 | - uses: subosito/flutter-action@v1 19 | with: 20 | channel: "stable" 21 | - run: flutter pub get 22 | - run: dart analyze 23 | - run: flutter test 24 | -------------------------------------------------------------------------------- /.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 | # The .vscode folder contains launch configuration and tasks you configure in 19 | # VS Code which you may wish to be included in version control, so this line 20 | # is commented out by default. 21 | #.vscode/ 22 | 23 | # Flutter/Dart/Pub related 24 | **/doc/api/ 25 | .dart_tool/ 26 | .flutter-plugins 27 | .flutter-plugins-dependencies 28 | .packages 29 | .pub-cache/ 30 | .pub/ 31 | build/ 32 | 33 | # Android related 34 | **/android/**/gradle-wrapper.jar 35 | **/android/.gradle 36 | **/android/captures/ 37 | **/android/gradlew 38 | **/android/gradlew.bat 39 | **/android/local.properties 40 | **/android/**/GeneratedPluginRegistrant.java 41 | 42 | # iOS/XCode related 43 | **/ios/**/*.mode1v3 44 | **/ios/**/*.mode2v3 45 | **/ios/**/*.moved-aside 46 | **/ios/**/*.pbxuser 47 | **/ios/**/*.perspectivev3 48 | **/ios/**/*sync/ 49 | **/ios/**/.sconsign.dblite 50 | **/ios/**/.tags* 51 | **/ios/**/.vagrant/ 52 | **/ios/**/DerivedData/ 53 | **/ios/**/Icon? 54 | **/ios/**/Pods/ 55 | **/ios/**/.symlinks/ 56 | **/ios/**/profile 57 | **/ios/**/xcuserdata 58 | **/ios/.generated/ 59 | **/ios/Flutter/App.framework 60 | **/ios/Flutter/Flutter.framework 61 | **/ios/Flutter/Flutter.podspec 62 | **/ios/Flutter/Generated.xcconfig 63 | **/ios/Flutter/ephemeral 64 | **/ios/Flutter/app.flx 65 | **/ios/Flutter/app.zip 66 | **/ios/Flutter/flutter_assets/ 67 | **/ios/Flutter/flutter_export_environment.sh 68 | **/ios/ServiceDefinitions.json 69 | **/ios/Runner/GeneratedPluginRegistrant.* 70 | 71 | # Exceptions to above rules. 72 | !**/ios/**/default.mode1v3 73 | !**/ios/**/default.mode2v3 74 | !**/ios/**/default.pbxuser 75 | !**/ios/**/default.perspectivev3 76 | -------------------------------------------------------------------------------- /.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: 4cc385b4b84ac2f816d939a49ea1f328c4e0b48e 8 | channel: stable 9 | 10 | project_type: package 11 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "workbench.colorCustomizations": { 3 | "titleBar.activeBackground": "#fbdb7a", 4 | "titleBar.activeForeground": "#000000", 5 | "titleBar.inactiveBackground": "#ffeebc", 6 | "titleBar.inactiveForeground": "#000000" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 0.0.4 2 | 3 | - More convenient drawing (one line of code to set up) 4 | - Offscreen rendering helper 5 | 6 | ## 0.0.1 7 | 8 | - First version; most core functionality 9 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright James Porter 2021 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Creating graphics with code is fun, but sometimes there is a lot of boilerplate. `Solandra` is a Flutter re-imagining of a [TypeScript library for HTML 5 Canvas drawing](https://solandra.netlify.app/). 2 | 3 | ![Solandra created image example](./sample-images/1.png) 4 | 5 | Flutter is a performant, multi platform framework with a great developer experience (for example supporting hot reload and declarative UI) but is often verbose. Paired with Solandra you can quickly create interesting, creative 2D graphics applications and deploy to native mobile apps, the web and native desktop apps. 6 | 7 | ## Solandra is ideal for 8 | 9 | - 2D creative code/algorithmic art 10 | - Data visualizations 11 | - Fun animations for (Flutter) Apps 12 | 13 | ## Features 14 | 15 | - Easy, canvas aware iteration 16 | - Easy randomness 17 | - A higher level (S)Path Class (something that you can perform operations on and draw) 18 | - Human friendly HSL(A) Color 19 | - Lots of convenience functions to save you time and boilerplate 20 | 21 | Solandra emphasizes short (low boilerplate), clear and thus agile (changeable over time) code. It should allow you to be a lot more productive. 22 | 23 | ![Solandra created image example](./sample-images/2.png) 24 | 25 | ![Solandra MacOS App Sample](./sample-images/solandra-flutter-mac-sample.png) 26 | 27 | ## Release Notes 28 | 29 | ### 0.0.4 30 | 31 | #### More convenient drawing 32 | 33 | Flutter tends to encourage boilerplate 😞, but certainly does not require it. Now you can render some custom drawing in one line of code with the new `SolandraSimplePaintingWidget`: 34 | 35 | ```dart 36 | SolandraSimplePaintingWidget(draw: (s) { 37 | s.background(200, 60, 40); 38 | }) 39 | ``` 40 | 41 | This will expand to take all available space, setting up all the usual custom painter and related widget boilerplate. The `ConvenientPainting2` example shows how if you have some associated state you can capture (for example by defining the drawing function in the `build` method). 42 | 43 | #### Easy offscreen rendering 44 | 45 | Often with creative coding you will want an easy way to render images (to save to a file). Solandra now makes this easy: 46 | 47 | ```dart 48 | SolandraRenderer.render((s) { 49 | s.background(200, 60, 40); 50 | }) 51 | ``` 52 | 53 | You'll notice you can use the same function to render to a file or to a canvas. 54 | 55 | ## Demo App 56 | 57 | In `./example` or just look at the: [live web version](https://solandra-flutter.netlify.app). 58 | 59 | ## Getting started 60 | 61 | Install the `solandra` package in usual way, see [Solandra package details](https://pub.dev/packages/solandra). For Flutter. 62 | 63 | ## Usage 64 | 65 | Main import via: 66 | 67 | ```dart 68 | import 'package:solandra/solandra.dart'; 69 | ``` 70 | 71 | Create the main helper object like (assumed to be used in `CustomPainter` subclass): 72 | 73 | ```dart 74 | class Painter extends CustomPainter { 75 | @override 76 | void paint(Canvas canvas, Size size) { 77 | final sol = Solandra(canvas, size); 78 | ``` 79 | 80 | ## Core Parts 81 | 82 | The following are the core elements of Solandra (for Flutter). 83 | 84 | ### Paint Setup for filling and drawing 85 | 86 | Solandra sets up a `fillPaint` and `strokePaint` for drawing with on `Solandra` instances. You can directly manipulate them, though for basic colors you can use the helpers described in the next section. 87 | 88 | Typically you will draw/fill stuff with 89 | 90 | ```dart 91 | draw(SPath path) 92 | fill(SPath path) 93 | ``` 94 | 95 | This uses Solandra's `SPath`. 96 | 97 | For using Dart's `Path`, instead use: 98 | 99 | ```dart 100 | drawPath(Path path) 101 | fillPath(Path path) 102 | ``` 103 | 104 | ### HSL(A) Color 105 | 106 | Colors for the above paints and background can be set via HSL(A) methods. This is much easier to work with than RGB. 107 | 108 | Assumes H(ue) from 0 to 360, and S(aturation), L(ightness) and A(lpha) (optional) from 0 to 100. All take `double`s, as this is more flexible/often what you want when doing creative coding. 109 | 110 | ### Programmable (S)Path Class 111 | 112 | There is an `SPath` class that allows you to create paths from lines and curves and then do higher level operations on those paths. 113 | 114 | The curves API has an unconventional approach that should be easier to reason about in most cases (under the hood it uses cubic beziers but you describe the size, angle, bulbous-ness and twist of the curve, rather that control points; if you move the points the curve scales in a natural way). [Read more (and see interactive demos) about the ideas behind this approach to curves](https://www.amimetic.co.uk/art/bezier). 115 | 116 | Given a path you can perform a number of operations on it, such as applying the Chaikin algorithm to smooth out paths or moving, scaling or otherwise transforming a path. 117 | 118 | ### Canvas/Size aware iteration 119 | 120 | `Solandra` has methods like `forTiling`, `forHorizontal` and more that give you a way to iterate over the canvas with optional margin. 121 | 122 | ### Unified Random Number Generation (with support for several common distributions) 123 | 124 | Random variation is a key part of creative coding and `Solandra` has a wide range of built in functionality that will save you a lot of time. The `randomPoint` method takes into account the `Canvas` size in the obvious way. 125 | 126 | ```dart 127 | Point randomPoint() 128 | double randomAngle() 129 | double random() 130 | int randomInt(int max) 131 | bool randomBool() 132 | double gaussian({double mean = 0, double sd = 1}) 133 | int poisson(int lambda) 134 | T sample(List items) 135 | List samples(List items, int count) 136 | doProportion(double proportion, Function() callback) 137 | proportionately(List cases) 138 | Point perturb( 139 | {required Point at, required double magnitude}) 140 | List shuffle(List items) 141 | ``` 142 | 143 | ### Convenience Helpers 144 | 145 | There are some helpers for converting between Dart/Flutter's classes. There are also some miscellaneous things in `Solandra`: 146 | 147 | ```dart 148 | clipped() 149 | double get aspectRatio 150 | double get width 151 | double get height 152 | Point get center 153 | ``` 154 | 155 | Most of these are obvious. The `clipped` method clips drawing to the `Canvas` (in Flutter drawing is not restricted to the `Canvas`'s `Size`). 156 | 157 | ## What is not included (versus the TypeScript version)? 158 | 159 | The library is much simpler in general, as Dart has a lot more built in functionality for mathematics e.g. `Point`, `Size` classes and so on. 160 | 161 | Unlike the original TypeScript version there is no explicit support for time (you are expected to use Flutter's existing animation tools for that). 162 | 163 | ## Dart/Flutter Tips 164 | 165 | If you are new to either here are some notes: 166 | 167 | - `forEachIndexed` exists but you must `import 'package:collection/collection.dart';` 168 | - `expanded` is the Dart version of `flatMap` 169 | - Check out `flutter_hooks` for a nicer way to add state to Widgets 170 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | # The .vscode folder contains launch configuration and tasks you configure in 19 | # VS Code which you may wish to be included in version control, so this line 20 | # is commented out by default. 21 | #.vscode/ 22 | 23 | # Flutter/Dart/Pub related 24 | **/doc/api/ 25 | **/ios/Flutter/.last_build_id 26 | .dart_tool/ 27 | .flutter-plugins 28 | .flutter-plugins-dependencies 29 | .packages 30 | .pub-cache/ 31 | .pub/ 32 | /build/ 33 | 34 | # Web related 35 | lib/generated_plugin_registrant.dart 36 | 37 | # Symbolication related 38 | app.*.symbols 39 | 40 | # Obfuscation related 41 | app.*.map.json 42 | 43 | # Android Studio will place build artifacts here 44 | /android/app/debug 45 | /android/app/profile 46 | /android/app/release 47 | -------------------------------------------------------------------------------- /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: 4cc385b4b84ac2f816d939a49ea1f328c4e0b48e 8 | channel: stable 9 | 10 | project_type: app 11 | -------------------------------------------------------------------------------- /example/README.md: -------------------------------------------------------------------------------- 1 | # example 2 | 3 | A new Flutter project. 4 | 5 | ## Getting Started 6 | 7 | This project is a starting point for a Flutter application. 8 | 9 | A few resources to get you started if this is your first Flutter project: 10 | 11 | - [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) 12 | - [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) 13 | 14 | For help getting started with Flutter, view our 15 | [online documentation](https://flutter.dev/docs), which offers tutorials, 16 | samples, guidance on mobile development, and a full API reference. 17 | -------------------------------------------------------------------------------- /example/analysis_options.yaml: -------------------------------------------------------------------------------- 1 | # This file configures the analyzer, which statically analyzes Dart code to 2 | # check for errors, warnings, and lints. 3 | # 4 | # The issues identified by the analyzer are surfaced in the UI of Dart-enabled 5 | # IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be 6 | # invoked from the command line by running `flutter analyze`. 7 | 8 | # The following line activates a set of recommended lints for Flutter apps, 9 | # packages, and plugins designed to encourage good coding practices. 10 | include: package:flutter_lints/flutter.yaml 11 | 12 | linter: 13 | # The lint rules applied to this project can be customized in the 14 | # section below to disable rules from the `package:flutter_lints/flutter.yaml` 15 | # included above or to enable additional rules. A list of all available lints 16 | # and their documentation is published at 17 | # https://dart-lang.github.io/linter/lints/index.html. 18 | # 19 | # Instead of disabling a lint rule for the entire project in the 20 | # section below, it can also be suppressed for a single line of code 21 | # or a specific dart file by using the `// ignore: name_of_lint` and 22 | # `// ignore_for_file: name_of_lint` syntax on the line or in the file 23 | # producing the lint. 24 | rules: 25 | # avoid_print: false # Uncomment to disable the `avoid_print` rule 26 | # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule 27 | 28 | # Additional information about this file can be found at 29 | # https://dart.dev/guides/language/analysis-options 30 | -------------------------------------------------------------------------------- /example/android/.gitignore: -------------------------------------------------------------------------------- 1 | gradle-wrapper.jar 2 | /.gradle 3 | /captures/ 4 | /gradlew 5 | /gradlew.bat 6 | /local.properties 7 | GeneratedPluginRegistrant.java 8 | 9 | # Remember to never publicly share your keystore. 10 | # See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app 11 | key.properties 12 | **/*.keystore 13 | **/*.jks 14 | -------------------------------------------------------------------------------- /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 plugin: 'kotlin-android' 26 | apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" 27 | 28 | android { 29 | compileSdkVersion 30 30 | 31 | compileOptions { 32 | sourceCompatibility JavaVersion.VERSION_1_8 33 | targetCompatibility JavaVersion.VERSION_1_8 34 | } 35 | 36 | kotlinOptions { 37 | jvmTarget = '1.8' 38 | } 39 | 40 | sourceSets { 41 | main.java.srcDirs += 'src/main/kotlin' 42 | } 43 | 44 | defaultConfig { 45 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). 46 | applicationId "com.example.example" 47 | minSdkVersion 16 48 | targetSdkVersion 30 49 | versionCode flutterVersionCode.toInteger() 50 | versionName flutterVersionName 51 | } 52 | 53 | buildTypes { 54 | release { 55 | // TODO: Add your own signing config for the release build. 56 | // Signing with the debug keys for now, so `flutter run --release` works. 57 | signingConfig signingConfigs.debug 58 | } 59 | } 60 | } 61 | 62 | flutter { 63 | source '../..' 64 | } 65 | 66 | dependencies { 67 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" 68 | } 69 | -------------------------------------------------------------------------------- /example/android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /example/android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 13 | 17 | 21 | 26 | 30 | 31 | 32 | 33 | 34 | 35 | 37 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /example/android/app/src/main/kotlin/com/example/example/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.example.example 2 | 3 | import io.flutter.embedding.android.FlutterActivity 4 | 5 | class MainActivity: FlutterActivity() { 6 | } 7 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/drawable-v21/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /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/jamesporter/solandra-flutter/e33e61691205ae8d4ee821db9ca5835cea736513/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/jamesporter/solandra-flutter/e33e61691205ae8d4ee821db9ca5835cea736513/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/jamesporter/solandra-flutter/e33e61691205ae8d4ee821db9ca5835cea736513/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/jamesporter/solandra-flutter/e33e61691205ae8d4ee821db9ca5835cea736513/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/jamesporter/solandra-flutter/e33e61691205ae8d4ee821db9ca5835cea736513/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/values-night/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /example/android/app/src/profile/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /example/android/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | ext.kotlin_version = '1.3.50' 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 | project.evaluationDependsOn(':app') 25 | } 26 | 27 | task clean(type: Delete) { 28 | delete rootProject.buildDir 29 | } 30 | -------------------------------------------------------------------------------- /example/android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx1536M 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-6.7-all.zip 7 | -------------------------------------------------------------------------------- /example/android/settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | 3 | def localPropertiesFile = new File(rootProject.projectDir, "local.properties") 4 | def properties = new Properties() 5 | 6 | assert localPropertiesFile.exists() 7 | localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) } 8 | 9 | def flutterSdkPath = properties.getProperty("flutter.sdk") 10 | assert flutterSdkPath != null, "flutter.sdk not set in local.properties" 11 | apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle" 12 | -------------------------------------------------------------------------------- /example/ios/.gitignore: -------------------------------------------------------------------------------- 1 | *.mode1v3 2 | *.mode2v3 3 | *.moved-aside 4 | *.pbxuser 5 | *.perspectivev3 6 | **/*sync/ 7 | .sconsign.dblite 8 | .tags* 9 | **/.vagrant/ 10 | **/DerivedData/ 11 | Icon? 12 | **/Pods/ 13 | **/.symlinks/ 14 | profile 15 | xcuserdata 16 | **/.generated/ 17 | Flutter/App.framework 18 | Flutter/Flutter.framework 19 | Flutter/Flutter.podspec 20 | Flutter/Generated.xcconfig 21 | Flutter/ephemeral/ 22 | Flutter/app.flx 23 | Flutter/app.zip 24 | Flutter/flutter_assets/ 25 | Flutter/flutter_export_environment.sh 26 | ServiceDefinitions.json 27 | Runner/GeneratedPluginRegistrant.* 28 | 29 | # Exceptions to above rules. 30 | !default.mode1v3 31 | !default.mode2v3 32 | !default.pbxuser 33 | !default.perspectivev3 34 | -------------------------------------------------------------------------------- /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 = 46; 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 | 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; 13 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 14 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 15 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; 16 | /* End PBXBuildFile section */ 17 | 18 | /* Begin PBXCopyFilesBuildPhase section */ 19 | 9705A1C41CF9048500538489 /* Embed Frameworks */ = { 20 | isa = PBXCopyFilesBuildPhase; 21 | buildActionMask = 2147483647; 22 | dstPath = ""; 23 | dstSubfolderSpec = 10; 24 | files = ( 25 | ); 26 | name = "Embed Frameworks"; 27 | runOnlyForDeploymentPostprocessing = 0; 28 | }; 29 | /* End PBXCopyFilesBuildPhase section */ 30 | 31 | /* Begin PBXFileReference section */ 32 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; 33 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; 34 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; 35 | 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; 36 | 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 37 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; 38 | 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; 39 | 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; 40 | 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; 41 | 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 42 | 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 43 | 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 44 | 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 45 | /* End PBXFileReference section */ 46 | 47 | /* Begin PBXFrameworksBuildPhase section */ 48 | 97C146EB1CF9000F007C117D /* Frameworks */ = { 49 | isa = PBXFrameworksBuildPhase; 50 | buildActionMask = 2147483647; 51 | files = ( 52 | ); 53 | runOnlyForDeploymentPostprocessing = 0; 54 | }; 55 | /* End PBXFrameworksBuildPhase section */ 56 | 57 | /* Begin PBXGroup section */ 58 | 9740EEB11CF90186004384FC /* Flutter */ = { 59 | isa = PBXGroup; 60 | children = ( 61 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, 62 | 9740EEB21CF90195004384FC /* Debug.xcconfig */, 63 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, 64 | 9740EEB31CF90195004384FC /* Generated.xcconfig */, 65 | ); 66 | name = Flutter; 67 | sourceTree = ""; 68 | }; 69 | 97C146E51CF9000F007C117D = { 70 | isa = PBXGroup; 71 | children = ( 72 | 9740EEB11CF90186004384FC /* Flutter */, 73 | 97C146F01CF9000F007C117D /* Runner */, 74 | 97C146EF1CF9000F007C117D /* Products */, 75 | ); 76 | sourceTree = ""; 77 | }; 78 | 97C146EF1CF9000F007C117D /* Products */ = { 79 | isa = PBXGroup; 80 | children = ( 81 | 97C146EE1CF9000F007C117D /* Runner.app */, 82 | ); 83 | name = Products; 84 | sourceTree = ""; 85 | }; 86 | 97C146F01CF9000F007C117D /* Runner */ = { 87 | isa = PBXGroup; 88 | children = ( 89 | 97C146FA1CF9000F007C117D /* Main.storyboard */, 90 | 97C146FD1CF9000F007C117D /* Assets.xcassets */, 91 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, 92 | 97C147021CF9000F007C117D /* Info.plist */, 93 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, 94 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, 95 | 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, 96 | 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, 97 | ); 98 | path = Runner; 99 | sourceTree = ""; 100 | }; 101 | /* End PBXGroup section */ 102 | 103 | /* Begin PBXNativeTarget section */ 104 | 97C146ED1CF9000F007C117D /* Runner */ = { 105 | isa = PBXNativeTarget; 106 | buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; 107 | buildPhases = ( 108 | 9740EEB61CF901F6004384FC /* Run Script */, 109 | 97C146EA1CF9000F007C117D /* Sources */, 110 | 97C146EB1CF9000F007C117D /* Frameworks */, 111 | 97C146EC1CF9000F007C117D /* Resources */, 112 | 9705A1C41CF9048500538489 /* Embed Frameworks */, 113 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */, 114 | ); 115 | buildRules = ( 116 | ); 117 | dependencies = ( 118 | ); 119 | name = Runner; 120 | productName = Runner; 121 | productReference = 97C146EE1CF9000F007C117D /* Runner.app */; 122 | productType = "com.apple.product-type.application"; 123 | }; 124 | /* End PBXNativeTarget section */ 125 | 126 | /* Begin PBXProject section */ 127 | 97C146E61CF9000F007C117D /* Project object */ = { 128 | isa = PBXProject; 129 | attributes = { 130 | LastUpgradeCheck = 1020; 131 | ORGANIZATIONNAME = ""; 132 | TargetAttributes = { 133 | 97C146ED1CF9000F007C117D = { 134 | CreatedOnToolsVersion = 7.3.1; 135 | LastSwiftMigration = 1100; 136 | }; 137 | }; 138 | }; 139 | buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; 140 | compatibilityVersion = "Xcode 9.3"; 141 | developmentRegion = en; 142 | hasScannedForEncodings = 0; 143 | knownRegions = ( 144 | en, 145 | Base, 146 | ); 147 | mainGroup = 97C146E51CF9000F007C117D; 148 | productRefGroup = 97C146EF1CF9000F007C117D /* Products */; 149 | projectDirPath = ""; 150 | projectRoot = ""; 151 | targets = ( 152 | 97C146ED1CF9000F007C117D /* Runner */, 153 | ); 154 | }; 155 | /* End PBXProject section */ 156 | 157 | /* Begin PBXResourcesBuildPhase section */ 158 | 97C146EC1CF9000F007C117D /* Resources */ = { 159 | isa = PBXResourcesBuildPhase; 160 | buildActionMask = 2147483647; 161 | files = ( 162 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, 163 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, 164 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, 165 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, 166 | ); 167 | runOnlyForDeploymentPostprocessing = 0; 168 | }; 169 | /* End PBXResourcesBuildPhase section */ 170 | 171 | /* Begin PBXShellScriptBuildPhase section */ 172 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { 173 | isa = PBXShellScriptBuildPhase; 174 | buildActionMask = 2147483647; 175 | files = ( 176 | ); 177 | inputPaths = ( 178 | ); 179 | name = "Thin Binary"; 180 | outputPaths = ( 181 | ); 182 | runOnlyForDeploymentPostprocessing = 0; 183 | shellPath = /bin/sh; 184 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; 185 | }; 186 | 9740EEB61CF901F6004384FC /* Run Script */ = { 187 | isa = PBXShellScriptBuildPhase; 188 | buildActionMask = 2147483647; 189 | files = ( 190 | ); 191 | inputPaths = ( 192 | ); 193 | name = "Run Script"; 194 | outputPaths = ( 195 | ); 196 | runOnlyForDeploymentPostprocessing = 0; 197 | shellPath = /bin/sh; 198 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; 199 | }; 200 | /* End PBXShellScriptBuildPhase section */ 201 | 202 | /* Begin PBXSourcesBuildPhase section */ 203 | 97C146EA1CF9000F007C117D /* Sources */ = { 204 | isa = PBXSourcesBuildPhase; 205 | buildActionMask = 2147483647; 206 | files = ( 207 | 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, 208 | 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, 209 | ); 210 | runOnlyForDeploymentPostprocessing = 0; 211 | }; 212 | /* End PBXSourcesBuildPhase section */ 213 | 214 | /* Begin PBXVariantGroup section */ 215 | 97C146FA1CF9000F007C117D /* Main.storyboard */ = { 216 | isa = PBXVariantGroup; 217 | children = ( 218 | 97C146FB1CF9000F007C117D /* Base */, 219 | ); 220 | name = Main.storyboard; 221 | sourceTree = ""; 222 | }; 223 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { 224 | isa = PBXVariantGroup; 225 | children = ( 226 | 97C147001CF9000F007C117D /* Base */, 227 | ); 228 | name = LaunchScreen.storyboard; 229 | sourceTree = ""; 230 | }; 231 | /* End PBXVariantGroup section */ 232 | 233 | /* Begin XCBuildConfiguration section */ 234 | 249021D3217E4FDB00AE95B9 /* Profile */ = { 235 | isa = XCBuildConfiguration; 236 | buildSettings = { 237 | ALWAYS_SEARCH_USER_PATHS = NO; 238 | CLANG_ANALYZER_NONNULL = YES; 239 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 240 | CLANG_CXX_LIBRARY = "libc++"; 241 | CLANG_ENABLE_MODULES = YES; 242 | CLANG_ENABLE_OBJC_ARC = YES; 243 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 244 | CLANG_WARN_BOOL_CONVERSION = YES; 245 | CLANG_WARN_COMMA = YES; 246 | CLANG_WARN_CONSTANT_CONVERSION = YES; 247 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 248 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 249 | CLANG_WARN_EMPTY_BODY = YES; 250 | CLANG_WARN_ENUM_CONVERSION = YES; 251 | CLANG_WARN_INFINITE_RECURSION = YES; 252 | CLANG_WARN_INT_CONVERSION = YES; 253 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 254 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 255 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 256 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 257 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 258 | CLANG_WARN_STRICT_PROTOTYPES = YES; 259 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 260 | CLANG_WARN_UNREACHABLE_CODE = YES; 261 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 262 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 263 | COPY_PHASE_STRIP = NO; 264 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 265 | ENABLE_NS_ASSERTIONS = NO; 266 | ENABLE_STRICT_OBJC_MSGSEND = YES; 267 | GCC_C_LANGUAGE_STANDARD = gnu99; 268 | GCC_NO_COMMON_BLOCKS = YES; 269 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 270 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 271 | GCC_WARN_UNDECLARED_SELECTOR = YES; 272 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 273 | GCC_WARN_UNUSED_FUNCTION = YES; 274 | GCC_WARN_UNUSED_VARIABLE = YES; 275 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 276 | MTL_ENABLE_DEBUG_INFO = NO; 277 | SDKROOT = iphoneos; 278 | SUPPORTED_PLATFORMS = iphoneos; 279 | TARGETED_DEVICE_FAMILY = "1,2"; 280 | VALIDATE_PRODUCT = YES; 281 | }; 282 | name = Profile; 283 | }; 284 | 249021D4217E4FDB00AE95B9 /* Profile */ = { 285 | isa = XCBuildConfiguration; 286 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; 287 | buildSettings = { 288 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 289 | CLANG_ENABLE_MODULES = YES; 290 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; 291 | ENABLE_BITCODE = NO; 292 | INFOPLIST_FILE = Runner/Info.plist; 293 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 294 | PRODUCT_BUNDLE_IDENTIFIER = com.example.example; 295 | PRODUCT_NAME = "$(TARGET_NAME)"; 296 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; 297 | SWIFT_VERSION = 5.0; 298 | VERSIONING_SYSTEM = "apple-generic"; 299 | }; 300 | name = Profile; 301 | }; 302 | 97C147031CF9000F007C117D /* Debug */ = { 303 | isa = XCBuildConfiguration; 304 | buildSettings = { 305 | ALWAYS_SEARCH_USER_PATHS = NO; 306 | CLANG_ANALYZER_NONNULL = YES; 307 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 308 | CLANG_CXX_LIBRARY = "libc++"; 309 | CLANG_ENABLE_MODULES = YES; 310 | CLANG_ENABLE_OBJC_ARC = YES; 311 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 312 | CLANG_WARN_BOOL_CONVERSION = YES; 313 | CLANG_WARN_COMMA = YES; 314 | CLANG_WARN_CONSTANT_CONVERSION = YES; 315 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 316 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 317 | CLANG_WARN_EMPTY_BODY = YES; 318 | CLANG_WARN_ENUM_CONVERSION = YES; 319 | CLANG_WARN_INFINITE_RECURSION = YES; 320 | CLANG_WARN_INT_CONVERSION = YES; 321 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 322 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 323 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 324 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 325 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 326 | CLANG_WARN_STRICT_PROTOTYPES = YES; 327 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 328 | CLANG_WARN_UNREACHABLE_CODE = YES; 329 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 330 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 331 | COPY_PHASE_STRIP = NO; 332 | DEBUG_INFORMATION_FORMAT = dwarf; 333 | ENABLE_STRICT_OBJC_MSGSEND = YES; 334 | ENABLE_TESTABILITY = YES; 335 | GCC_C_LANGUAGE_STANDARD = gnu99; 336 | GCC_DYNAMIC_NO_PIC = NO; 337 | GCC_NO_COMMON_BLOCKS = YES; 338 | GCC_OPTIMIZATION_LEVEL = 0; 339 | GCC_PREPROCESSOR_DEFINITIONS = ( 340 | "DEBUG=1", 341 | "$(inherited)", 342 | ); 343 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 344 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 345 | GCC_WARN_UNDECLARED_SELECTOR = YES; 346 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 347 | GCC_WARN_UNUSED_FUNCTION = YES; 348 | GCC_WARN_UNUSED_VARIABLE = YES; 349 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 350 | MTL_ENABLE_DEBUG_INFO = YES; 351 | ONLY_ACTIVE_ARCH = YES; 352 | SDKROOT = iphoneos; 353 | TARGETED_DEVICE_FAMILY = "1,2"; 354 | }; 355 | name = Debug; 356 | }; 357 | 97C147041CF9000F007C117D /* Release */ = { 358 | isa = XCBuildConfiguration; 359 | buildSettings = { 360 | ALWAYS_SEARCH_USER_PATHS = NO; 361 | CLANG_ANALYZER_NONNULL = YES; 362 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 363 | CLANG_CXX_LIBRARY = "libc++"; 364 | CLANG_ENABLE_MODULES = YES; 365 | CLANG_ENABLE_OBJC_ARC = YES; 366 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 367 | CLANG_WARN_BOOL_CONVERSION = YES; 368 | CLANG_WARN_COMMA = YES; 369 | CLANG_WARN_CONSTANT_CONVERSION = YES; 370 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 371 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 372 | CLANG_WARN_EMPTY_BODY = YES; 373 | CLANG_WARN_ENUM_CONVERSION = YES; 374 | CLANG_WARN_INFINITE_RECURSION = YES; 375 | CLANG_WARN_INT_CONVERSION = YES; 376 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 377 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 378 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 379 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 380 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 381 | CLANG_WARN_STRICT_PROTOTYPES = YES; 382 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 383 | CLANG_WARN_UNREACHABLE_CODE = YES; 384 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 385 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 386 | COPY_PHASE_STRIP = NO; 387 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 388 | ENABLE_NS_ASSERTIONS = NO; 389 | ENABLE_STRICT_OBJC_MSGSEND = YES; 390 | GCC_C_LANGUAGE_STANDARD = gnu99; 391 | GCC_NO_COMMON_BLOCKS = YES; 392 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 393 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 394 | GCC_WARN_UNDECLARED_SELECTOR = YES; 395 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 396 | GCC_WARN_UNUSED_FUNCTION = YES; 397 | GCC_WARN_UNUSED_VARIABLE = YES; 398 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 399 | MTL_ENABLE_DEBUG_INFO = NO; 400 | SDKROOT = iphoneos; 401 | SUPPORTED_PLATFORMS = iphoneos; 402 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 403 | TARGETED_DEVICE_FAMILY = "1,2"; 404 | VALIDATE_PRODUCT = YES; 405 | }; 406 | name = Release; 407 | }; 408 | 97C147061CF9000F007C117D /* Debug */ = { 409 | isa = XCBuildConfiguration; 410 | baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; 411 | buildSettings = { 412 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 413 | CLANG_ENABLE_MODULES = YES; 414 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; 415 | ENABLE_BITCODE = NO; 416 | INFOPLIST_FILE = Runner/Info.plist; 417 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 418 | PRODUCT_BUNDLE_IDENTIFIER = com.example.example; 419 | PRODUCT_NAME = "$(TARGET_NAME)"; 420 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; 421 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 422 | SWIFT_VERSION = 5.0; 423 | VERSIONING_SYSTEM = "apple-generic"; 424 | }; 425 | name = Debug; 426 | }; 427 | 97C147071CF9000F007C117D /* Release */ = { 428 | isa = XCBuildConfiguration; 429 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; 430 | buildSettings = { 431 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 432 | CLANG_ENABLE_MODULES = YES; 433 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; 434 | ENABLE_BITCODE = NO; 435 | INFOPLIST_FILE = Runner/Info.plist; 436 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 437 | PRODUCT_BUNDLE_IDENTIFIER = com.example.example; 438 | PRODUCT_NAME = "$(TARGET_NAME)"; 439 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; 440 | SWIFT_VERSION = 5.0; 441 | VERSIONING_SYSTEM = "apple-generic"; 442 | }; 443 | name = Release; 444 | }; 445 | /* End XCBuildConfiguration section */ 446 | 447 | /* Begin XCConfigurationList section */ 448 | 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { 449 | isa = XCConfigurationList; 450 | buildConfigurations = ( 451 | 97C147031CF9000F007C117D /* Debug */, 452 | 97C147041CF9000F007C117D /* Release */, 453 | 249021D3217E4FDB00AE95B9 /* Profile */, 454 | ); 455 | defaultConfigurationIsVisible = 0; 456 | defaultConfigurationName = Release; 457 | }; 458 | 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { 459 | isa = XCConfigurationList; 460 | buildConfigurations = ( 461 | 97C147061CF9000F007C117D /* Debug */, 462 | 97C147071CF9000F007C117D /* Release */, 463 | 249021D4217E4FDB00AE95B9 /* Profile */, 464 | ); 465 | defaultConfigurationIsVisible = 0; 466 | defaultConfigurationName = Release; 467 | }; 468 | /* End XCConfigurationList section */ 469 | }; 470 | rootObject = 97C146E61CF9000F007C117D /* Project object */; 471 | } 472 | -------------------------------------------------------------------------------- /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/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 42 | 43 | 44 | 54 | 56 | 62 | 63 | 64 | 65 | 66 | 67 | 73 | 75 | 81 | 82 | 83 | 84 | 86 | 87 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /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.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/ios/Runner/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | import Flutter 3 | 4 | @UIApplicationMain 5 | @objc class AppDelegate: FlutterAppDelegate { 6 | override func application( 7 | _ application: UIApplication, 8 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? 9 | ) -> Bool { 10 | GeneratedPluginRegistrant.register(with: self) 11 | return super.application(application, didFinishLaunchingWithOptions: launchOptions) 12 | } 13 | } 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/jamesporter/solandra-flutter/e33e61691205ae8d4ee821db9ca5835cea736513/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/jamesporter/solandra-flutter/e33e61691205ae8d4ee821db9ca5835cea736513/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/jamesporter/solandra-flutter/e33e61691205ae8d4ee821db9ca5835cea736513/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/jamesporter/solandra-flutter/e33e61691205ae8d4ee821db9ca5835cea736513/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/jamesporter/solandra-flutter/e33e61691205ae8d4ee821db9ca5835cea736513/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/jamesporter/solandra-flutter/e33e61691205ae8d4ee821db9ca5835cea736513/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/jamesporter/solandra-flutter/e33e61691205ae8d4ee821db9ca5835cea736513/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/jamesporter/solandra-flutter/e33e61691205ae8d4ee821db9ca5835cea736513/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/jamesporter/solandra-flutter/e33e61691205ae8d4ee821db9ca5835cea736513/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/jamesporter/solandra-flutter/e33e61691205ae8d4ee821db9ca5835cea736513/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/jamesporter/solandra-flutter/e33e61691205ae8d4ee821db9ca5835cea736513/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/jamesporter/solandra-flutter/e33e61691205ae8d4ee821db9ca5835cea736513/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/jamesporter/solandra-flutter/e33e61691205ae8d4ee821db9ca5835cea736513/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/jamesporter/solandra-flutter/e33e61691205ae8d4ee821db9ca5835cea736513/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/jamesporter/solandra-flutter/e33e61691205ae8d4ee821db9ca5835cea736513/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/jamesporter/solandra-flutter/e33e61691205ae8d4ee821db9ca5835cea736513/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jamesporter/solandra-flutter/e33e61691205ae8d4ee821db9ca5835cea736513/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jamesporter/solandra-flutter/e33e61691205ae8d4ee821db9ca5835cea736513/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 | $(DEVELOPMENT_LANGUAGE) 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 | 45 | 46 | -------------------------------------------------------------------------------- /example/ios/Runner/Runner-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | #import "GeneratedPluginRegistrant.h" 2 | -------------------------------------------------------------------------------- /example/lib/convenient_painting.dart: -------------------------------------------------------------------------------- 1 | import 'dart:math'; 2 | 3 | import 'package:flutter/material.dart'; 4 | import 'package:flutter_hooks/flutter_hooks.dart'; 5 | import 'package:solandra/solandra.dart'; 6 | 7 | /// See [ConvenientPainting2] for an even more concise approach where there is no need to create any additional classes for drawing. 8 | class ConvenientPainter extends SolandraCustomPainter { 9 | final double param; 10 | 11 | ConvenientPainter(this.param); 12 | 13 | @override 14 | void sPaint(Solandra s, Size size) { 15 | s.background(200, 60, 40); 16 | 17 | times(10, (n) { 18 | SPath.regularPolygon(radius: param * size.width / 4, at: s.center) 19 | .exploded(magnitude: (n + 1).toDouble() / 5, scale: 1 + param / 3) 20 | .forEach((path) { 21 | s.setFillColor(200, 60, 90, 20 - n.toDouble()); 22 | s.fill(path); 23 | }); 24 | }); 25 | } 26 | } 27 | 28 | class ConvenientPainting extends HookWidget { 29 | const ConvenientPainting({Key? key}) : super(key: key); 30 | 31 | @override 32 | Widget build(BuildContext context) { 33 | final param = useState(0.4); 34 | 35 | return Scaffold( 36 | appBar: AppBar(title: const Text("Convenient Painting")), 37 | body: Column(children: [ 38 | Slider( 39 | value: param.value, 40 | onChanged: (v) { 41 | param.value = v; 42 | }, 43 | min: 0, 44 | max: 1), 45 | SolandraPaintingWidget(painter: ConvenientPainter(param.value)) 46 | ])); 47 | } 48 | } 49 | 50 | /// See [ConvenientPainting] for a more explicit approach, but typically you should just use this approach. 51 | class ConvenientPainting2 extends HookWidget { 52 | const ConvenientPainting2({Key? key}) : super(key: key); 53 | 54 | @override 55 | Widget build(BuildContext context) { 56 | final a = useState(1.0); 57 | final b = useState(0.3); 58 | final c = useState(0.0); 59 | 60 | void draw(Solandra s) { 61 | s.clipped(); 62 | s.background(200, 60, 10); 63 | 64 | [a.value, b.value, c.value].forEach((v) { 65 | final p = SPath.spiral( 66 | at: s.center, 67 | n: 100, 68 | l: s.width / 10, 69 | rate: 10 + 10 * v, 70 | startAngle: v * pi * 2) 71 | .chaikin(n: 2); 72 | s.setStrokeColor(360 * v, 60, 80, 80); 73 | s.strokePaint.strokeWidth = s.height / 32; 74 | s.draw(p); 75 | }); 76 | } 77 | 78 | return Scaffold( 79 | appBar: AppBar(title: const Text("More Convenient Painting")), 80 | body: Row(children: [ 81 | SolandraSimplePaintingWidget(draw: draw), 82 | Padding( 83 | padding: const EdgeInsets.all(8.0), 84 | child: SizedBox( 85 | width: 240, 86 | child: Column(children: [ 87 | Slider( 88 | value: a.value, 89 | onChanged: (v) { 90 | a.value = v; 91 | }, 92 | min: 0, 93 | max: 1), 94 | Slider( 95 | value: b.value, 96 | onChanged: (v) { 97 | b.value = v; 98 | }, 99 | min: 0, 100 | max: 1), 101 | Slider( 102 | value: c.value, 103 | onChanged: (v) { 104 | c.value = v; 105 | }, 106 | min: 0, 107 | max: 1), 108 | const Text( 109 | "See the source code for this button, shows how you could render a PNG image from the same code used for drawing here"), 110 | ElevatedButton( 111 | onPressed: () async { 112 | final bytes = await SolandraRenderer.render( 113 | size: const Size(320, 320), render: draw); 114 | if (bytes != null) { 115 | // For example write to file 116 | } 117 | }, 118 | child: const Text("Render")) 119 | ]), 120 | ), 121 | ), 122 | ])); 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /example/lib/curves_demo.dart: -------------------------------------------------------------------------------- 1 | import 'dart:math'; 2 | 3 | import 'package:flutter/material.dart'; 4 | import 'package:flutter_hooks/flutter_hooks.dart'; 5 | import 'package:solandra/path.dart'; 6 | import 'package:solandra/solandra.dart'; 7 | 8 | class CurvesDemo extends CustomPainter { 9 | double curveSize; 10 | double curveAngle; 11 | double bulbousness; 12 | double twist; 13 | bool positive; 14 | 15 | CurvesDemo(this.curveSize, this.curveAngle, this.bulbousness, this.twist, 16 | this.positive); 17 | 18 | @override 19 | void paint(Canvas canvas, Size size) { 20 | final sol = Solandra(canvas, size); 21 | sol.clipped(); 22 | sol.background(200, 20, 95); 23 | 24 | sol.setStrokeColor(sol.random() * 40 + 180, 80, 30, 50); 25 | sol.setFillColor(210, 90, 40, 10); 26 | sol.strokePaint.strokeWidth = 5; 27 | 28 | times(20, (_) { 29 | final path = SPath(sol.center); 30 | path.curve( 31 | to: sol.randomPoint(), 32 | curveSize: curveSize, 33 | curveAngle: curveAngle, 34 | bulbousness: bulbousness, 35 | twist: twist, 36 | positive: positive); 37 | 38 | sol.draw(path); 39 | sol.fill(path); 40 | }); 41 | } 42 | 43 | @override 44 | bool shouldRepaint(CustomPainter oldDelegate) { 45 | return true; 46 | } 47 | } 48 | 49 | class CurvesDemoScreen extends HookWidget { 50 | @override 51 | Widget build(BuildContext context) { 52 | final curveSize = useState(0.5); 53 | final curveAngle = useState(pi / 4); 54 | final curveTwist = useState(0); 55 | final curveBulbousness = useState(0.8); 56 | final positive = useState(true); 57 | 58 | return Scaffold( 59 | appBar: AppBar(title: const Text("Curves")), 60 | body: Container( 61 | child: Row(children: [ 62 | Expanded( 63 | child: CustomPaint( 64 | painter: CurvesDemo(curveSize.value, curveAngle.value, 65 | curveBulbousness.value, curveTwist.value, positive.value), 66 | child: Container())), 67 | SizedBox( 68 | width: 220, 69 | child: Column( 70 | children: [ 71 | const Padding( 72 | padding: EdgeInsets.all(10), 73 | child: Text( 74 | "Typical Bezier APIs rely on specifying control points which are relative to both the start and end point locations and size. Solandra's API offers more intuitive parameters, which mean the curve shape is the same independent of start and end locations and size. Here 20 curves are drawn from the center to random positions. The curve shapes are the same and can be intuitively adjusted.")), 75 | Padding( 76 | padding: EdgeInsets.all(10), 77 | child: Text( 78 | "Curve Size ${curveSize.value.toStringAsFixed(2)}", 79 | style: TextStyle(fontSize: 18))), 80 | Slider( 81 | value: curveSize.value, 82 | onChanged: (newValue) { 83 | curveSize.value = newValue; 84 | }, 85 | min: 0, 86 | max: 4), 87 | Padding( 88 | padding: EdgeInsets.all(10), 89 | child: Text( 90 | "Angle ${curveAngle.value.toStringAsFixed(2)}", 91 | style: TextStyle(fontSize: 18))), 92 | Slider( 93 | value: curveAngle.value, 94 | onChanged: (newValue) { 95 | curveAngle.value = newValue; 96 | }, 97 | min: -pi * 2, 98 | max: pi * 2), 99 | Padding( 100 | padding: EdgeInsets.all(10), 101 | child: Text( 102 | "Twist ${curveTwist.value.toStringAsFixed(2)}", 103 | style: TextStyle(fontSize: 18))), 104 | Slider( 105 | value: curveTwist.value, 106 | onChanged: (newValue) { 107 | curveTwist.value = newValue; 108 | }, 109 | min: 0, 110 | max: 2), 111 | Padding( 112 | padding: EdgeInsets.all(10), 113 | child: Text( 114 | "Bulbousness ${curveBulbousness.value.toStringAsFixed(2)}", 115 | style: TextStyle(fontSize: 18))), 116 | Slider( 117 | value: curveBulbousness.value, 118 | onChanged: (newValue) { 119 | curveBulbousness.value = newValue; 120 | }, 121 | min: 0, 122 | max: 4), 123 | const Padding( 124 | padding: EdgeInsets.all(10), 125 | child: Text("Positive", style: TextStyle(fontSize: 18))), 126 | Switch( 127 | value: positive.value, 128 | onChanged: (newValue) { 129 | positive.value = newValue; 130 | }) 131 | ], 132 | )) 133 | ]))); 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /example/lib/examples.dart: -------------------------------------------------------------------------------- 1 | import 'package:example/convenient_painting.dart'; 2 | import 'package:example/curves_demo.dart'; 3 | import 'package:example/hello_solandra.dart'; 4 | import 'package:example/hello_solandra_five.dart'; 5 | import 'package:example/hello_solandra_four.dart'; 6 | import 'package:example/hello_solandra_seven.dart'; 7 | import 'package:example/hello_solandra_six.dart'; 8 | import 'package:example/hello_solandra_three.dart'; 9 | import 'package:example/hello_solandra_two.dart'; 10 | import 'package:example/home_screen.dart'; 11 | import 'package:example/wallpaper_creator.dart'; 12 | import 'package:flutter/material.dart'; 13 | 14 | final Map examples = { 15 | "Slideshow": (_) => ExampleOne(), 16 | "Tiling": (_) => ExampleTwo(), 17 | "Simple Animation": (_) => ExampleThree(), 18 | "Circular Animation": (_) => ExampleFour(), 19 | "(S)Path Operations": (_) => ExampleFive(), 20 | "Doodles": (_) => ExampleSix(), 21 | "Fancier Shapes": (_) => ExampleSeven(), 22 | "Wallpaper Creator": (_) => WallpaperCreator(), 23 | "Understanding Curves": (_) => CurvesDemoScreen(), 24 | "Convenient Painting": (_) => ConvenientPainting(), 25 | "(More) Convenient Painting": (_) => ConvenientPainting2() 26 | }; 27 | 28 | Map routes() { 29 | Map routeMap = { 30 | "/": (_) => HomeScreen() 31 | }; 32 | var i = 1; 33 | examples.forEach((key, value) { 34 | routeMap["/$i"] = value; 35 | i++; 36 | }); 37 | return routeMap; 38 | } 39 | 40 | List routeNames() { 41 | List names = []; 42 | examples.forEach((key, value) { 43 | names.add(key); 44 | }); 45 | return names; 46 | } 47 | 48 | final examplesCount = examples.length; 49 | -------------------------------------------------------------------------------- /example/lib/hello_solandra.dart: -------------------------------------------------------------------------------- 1 | import 'dart:math'; 2 | 3 | import 'package:flutter/material.dart'; 4 | import 'package:flutter_hooks/flutter_hooks.dart'; 5 | import 'package:solandra/solandra.dart'; 6 | import 'package:collection/collection.dart'; 7 | 8 | class ExampleOnePainter extends CustomPainter { 9 | Function(Canvas, Size) painter; 10 | ExampleOnePainter(this.painter); 11 | 12 | @override 13 | void paint(Canvas canvas, Size size) { 14 | painter(canvas, size); 15 | } 16 | 17 | @override 18 | bool shouldRepaint(CustomPainter oldDelegate) { 19 | return true; 20 | } 21 | } 22 | 23 | class ExampleOne extends HookWidget { 24 | @override 25 | Widget build(BuildContext context) { 26 | final idx = useState(0); 27 | return Scaffold( 28 | appBar: AppBar(title: const Text("Slideshow")), 29 | body: CustomPaint( 30 | painter: ExampleOnePainter(painters[idx.value]), child: Container()), 31 | floatingActionButton: FloatingActionButton( 32 | onPressed: () { 33 | int newIdx = idx.value + 1; 34 | if (newIdx >= painters.length) { 35 | newIdx = 0; 36 | } 37 | idx.value = newIdx; 38 | }, 39 | child: const Icon(Icons.forward)), 40 | ); 41 | } 42 | 43 | final List painters = [ 44 | (canvas, size) { 45 | final sol = Solandra(canvas, size); 46 | sol.clipped(); 47 | sol.background(100, 10, 90); 48 | times(32, (_) { 49 | sol.setFillColor(sol.sample([190, 210, 220]), 80, 50, 50); 50 | canvas.drawCircle( 51 | sol.randomPoint().offset, 52 | sol.gaussian(sd: size.width / 12, mean: size.width / 8), 53 | sol.fillPaint); 54 | }); 55 | }, 56 | (canvas, size) { 57 | final sol = Solandra(canvas, size); 58 | sol.clipped(); 59 | sol.background(100, 1, 10); 60 | 61 | SPath.regularPolygon(radius: size.minimum * 0.4, at: sol.center, n: 20) 62 | .segmented 63 | .expand((p) => p.exploded(scale: 0.75, magnitude: 1.1)) 64 | .expand((p) => p.exploded(scale: 0.75, magnitude: 1.3)) 65 | .forEachIndexed((i, p) { 66 | sol.setFillColor(i * 5, 80, 70); 67 | sol.fill(p); 68 | }); 69 | }, 70 | (canvas, size) { 71 | final sol = Solandra(canvas, size); 72 | sol.clipped(); 73 | sol.background(200, 5, 90); 74 | times(5, (i) { 75 | sol.setStrokeColor(190 + i * 10, 80, 50, 60); 76 | sol.strokePaint.strokeWidth = size.minimum / 120; 77 | sol.strokePaint.strokeCap = StrokeCap.round; 78 | 79 | final List> points = []; 80 | final R = size.minimum * 0.25; 81 | var r = R; 82 | final center = sol.center; 83 | 84 | for (var i = 0; i <= 64; i++) { 85 | r = R + sol.gaussian(sd: R / 3); 86 | points.add(Point( 87 | center.x + r * cos(pi * i / 8), center.y + r * sin(pi * i / 8))); 88 | } 89 | sol.draw(SPath.fromPoints(points).chaikin(n: 4)); 90 | }); 91 | }, 92 | (canvas, size) { 93 | final sol = Solandra(canvas, size); 94 | sol.clipped(); 95 | sol.background(200, 5, 90); 96 | List> centres = []; 97 | sol.forTiling( 98 | n: 10, 99 | square: true, 100 | margin: 0.1, 101 | callback: (area) { 102 | centres.add(area.center); 103 | }); 104 | centres = sol.shuffle(centres); 105 | for (final c in centres) { 106 | final m = (c.x + c.y) / (size.width + size.height); 107 | sol.setStrokeColor(210, 10, 10, 90); 108 | sol.setFillColor(140 + 50 * m, 80, 70, 80); 109 | sol.strokePaint.strokeWidth = size.magnitude / 200; 110 | 111 | canvas.drawCircle(c.offset, m * size.magnitude / 20, sol.fillPaint); 112 | canvas.drawCircle(c.offset, m * size.magnitude / 20, sol.strokePaint); 113 | } 114 | }, 115 | (canvas, size) { 116 | final sol = Solandra(canvas, size); 117 | sol.clipped(); 118 | sol.background(200, 5, 90); 119 | 120 | List shapes = []; 121 | 122 | SPath.star(at: sol.center, radius: size.magnitude * 0.25, n: 16) 123 | .exploded(magnitude: 1.05, scale: 0.9) 124 | .expand((p) => p.exploded(magnitude: 1.2, scale: 1.1)) 125 | .map((p) => p.rotated(sol.gaussian(sd: pi / 8))) 126 | .forEachIndexed((index, p) { 127 | sol.setFillColor(115.0 - index * 2, 90, 40, 90); 128 | sol.fill(p); 129 | shapes.add(p); 130 | }); 131 | 132 | sol.strokePaint.strokeWidth = size.magnitude * 0.001; 133 | shapes.forEach((element) { 134 | sol.draw(element.moved(Point( 135 | 0.0, 136 | sol.gaussian( 137 | sd: size.magnitude * 0.03, mean: size.magnitude * 0.05)) 138 | .rotate(sol.gaussian(sd: pi / 32)))); 139 | }); 140 | }, 141 | (canvas, size) { 142 | final sol = Solandra(canvas, size); 143 | sol.clipped(); 144 | sol.background(180, 12, 91); 145 | 146 | List shapes = []; 147 | 148 | sol.setFillColor(170, 10, 80); 149 | SPath.star(at: sol.center, radius: size.magnitude * 0.25, n: 16) 150 | .exploded(magnitude: 1.05, scale: 0.9) 151 | .expand((p) => p.exploded(magnitude: 1.2, scale: 1.1)) 152 | .map((p) => p.rotated(sol.gaussian(sd: pi / 8))) 153 | .forEachIndexed((index, p) { 154 | sol.fill(p); 155 | sol.draw(p); 156 | shapes.add(p); 157 | }); 158 | 159 | sol.strokePaint.strokeWidth = size.magnitude * 0.001; 160 | shapes.forEachIndexed((index, element) { 161 | sol.setFillColor(115.0 - index * 2, 90, 40, 80); 162 | sol.fill(element.moved(Point( 163 | 0.0, 164 | sol.gaussian( 165 | sd: size.magnitude * 0.01, mean: size.magnitude * 0.03)) 166 | .rotate(sol.gaussian(sd: pi / 16)))); 167 | }); 168 | } 169 | ]; 170 | } 171 | -------------------------------------------------------------------------------- /example/lib/hello_solandra_five.dart: -------------------------------------------------------------------------------- 1 | import 'dart:math'; 2 | 3 | import 'package:flutter/material.dart'; 4 | import 'package:flutter_hooks/flutter_hooks.dart'; 5 | import 'package:solandra/iteration.dart'; 6 | import 'package:solandra/path.dart'; 7 | import 'package:solandra/solandra.dart'; 8 | 9 | class ExampleFivePainter extends CustomPainter { 10 | double controlValue; 11 | double controlValue2; 12 | double controlValue3; 13 | 14 | ExampleFivePainter(this.controlValue, this.controlValue2, this.controlValue3); 15 | 16 | @override 17 | void paint(Canvas canvas, Size size) { 18 | final sol = Solandra(canvas, size); 19 | sol.clipped(); 20 | sol.background(45, 40, 90); 21 | 22 | final sp = sol.strokePaint 23 | ..strokeWidth = controlValue3 24 | ..strokeJoin = StrokeJoin.round 25 | ..strokeCap = StrokeCap.round; 26 | 27 | sol.setStrokeColor(150, 10, 10, 80); 28 | 29 | final a = Point(size.width / 3, size.height / 3); 30 | final b = Point(2 * size.width / 3, size.height / 3); 31 | final c = Point(2 * size.width / 3, 2 * size.height / 3); 32 | final d = Point(size.width / 3, 2 * size.height / 3); 33 | 34 | var path = SPath(a) 35 | ..line(to: b) 36 | ..line(to: c) 37 | ..line(to: d) 38 | ..close(); 39 | 40 | path = path.rotated(controlValue); 41 | 42 | path.exploded(magnitude: controlValue2).forEach((p) { 43 | sol.setFillColor(180 + sol.gaussian(sd: 40), 90, 50, 50); 44 | sol.fill(p); 45 | 46 | p.exploded(magnitude: controlValue2).forEach((q) { 47 | sol.setFillColor(180 + sol.gaussian(sd: 40), 90, 50, 50); 48 | sol.fill(q.rotated(controlValue / 2)); 49 | sol.draw(q); 50 | }); 51 | 52 | sol.setFillColor(0, 0, 100); 53 | // Note the more verbose of Flutter built in stuff; don't totally like, but the think I did felt too special case 54 | canvas.drawCircle(p.centroid.offset, 10, sol.fillPaint); 55 | }); 56 | } 57 | 58 | @override 59 | bool shouldRepaint(CustomPainter oldDelegate) { 60 | return true; 61 | } 62 | } 63 | 64 | class ExampleFive extends HookWidget { 65 | @override 66 | Widget build(BuildContext context) { 67 | final parameter = useState(0); 68 | final parameter2 = useState(0); 69 | final parameter3 = useState(2); 70 | 71 | return Scaffold( 72 | appBar: AppBar(title: const Text("(S)Path Operations")), 73 | body: Container( 74 | child: Column(children: [ 75 | Row( 76 | children: [ 77 | Expanded( 78 | child: Slider( 79 | value: parameter.value, 80 | onChanged: (newValue) { 81 | parameter.value = newValue; 82 | }, 83 | min: 0, 84 | max: pi)), 85 | Expanded( 86 | child: Slider( 87 | value: parameter2.value, 88 | onChanged: (newValue) { 89 | parameter2.value = newValue; 90 | }, 91 | min: 0, 92 | max: 2)), 93 | Expanded( 94 | child: Slider( 95 | value: parameter3.value, 96 | onChanged: (newValue) { 97 | parameter3.value = newValue; 98 | }, 99 | min: 1, 100 | max: 8)), 101 | ], 102 | ), 103 | Expanded( 104 | child: CustomPaint( 105 | painter: ExampleFivePainter( 106 | parameter.value, parameter2.value, parameter3.value), 107 | child: Container())) 108 | ])), 109 | ); 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /example/lib/hello_solandra_four.dart: -------------------------------------------------------------------------------- 1 | import 'dart:math'; 2 | 3 | import 'package:flutter/material.dart'; 4 | import 'package:flutter_hooks/flutter_hooks.dart'; 5 | import 'package:solandra/iteration.dart'; 6 | import 'package:solandra/solandra.dart'; 7 | 8 | class ExampleFourPainter extends CustomPainter { 9 | double animatedValue; 10 | double controlValue; 11 | 12 | ExampleFourPainter(this.animatedValue, this.controlValue); 13 | 14 | @override 15 | void paint(Canvas canvas, Size size) { 16 | final sol = Solandra(canvas, size); 17 | sol.clipped(); 18 | sol.background(45, 40, 90); 19 | 20 | times(3, (i) { 21 | sol.setFillColor(controlValue - i * 20, 70, 40, 70); 22 | final baseR = size.minimum / 12; 23 | sol.aroundCircle( 24 | radius: size.minimum / 2.4 - i * size.minimum / 6, 25 | n: 24 - i * 8, 26 | callback: (pt, j) { 27 | canvas.drawCircle(pt.offset, 28 | baseR * (1 + cos(j + animatedValue / 40) / 2), sol.fillPaint); 29 | }); 30 | }); 31 | } 32 | 33 | @override 34 | bool shouldRepaint(CustomPainter oldDelegate) { 35 | return true; 36 | } 37 | } 38 | 39 | class ExampleFour extends HookWidget { 40 | @override 41 | Widget build(BuildContext context) { 42 | final parameter = useState(0); 43 | 44 | return Scaffold( 45 | appBar: AppBar(title: const Text("Circular Animation")), 46 | body: Container( 47 | child: Column(children: [ 48 | Slider( 49 | value: parameter.value, 50 | onChanged: (newValue) { 51 | parameter.value = newValue; 52 | }, 53 | min: 0, 54 | max: 360), 55 | Expanded( 56 | child: TweenAnimationBuilder( 57 | tween: Tween(begin: 0, end: 3600 * 60), 58 | duration: const Duration(seconds: 3600), 59 | builder: (BuildContext ctx, double value, Widget? _) { 60 | return CustomPaint( 61 | painter: ExampleFourPainter(value, parameter.value), 62 | child: Container()); 63 | })) 64 | ])), 65 | ); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /example/lib/hello_solandra_seven.dart: -------------------------------------------------------------------------------- 1 | import 'dart:math'; 2 | 3 | import 'package:flutter/material.dart'; 4 | import 'package:flutter_hooks/flutter_hooks.dart'; 5 | import 'package:solandra/iteration.dart'; 6 | import 'package:solandra/path.dart'; 7 | import 'package:solandra/solandra.dart'; 8 | 9 | class ExampleSevenPainter extends CustomPainter { 10 | double parameter; 11 | 12 | ExampleSevenPainter(this.parameter); 13 | 14 | @override 15 | void paint(Canvas canvas, Size size) { 16 | final sol = Solandra(canvas, size); 17 | sol.clipped(); 18 | sol.background(45, 30, 95); 19 | 20 | sol.setStrokeColor(210, 80, 30, 40); 21 | sol.strokePaint.strokeWidth = 5; 22 | 23 | final n = parameter.round(); 24 | 25 | sol.draw(SPath.spiral( 26 | at: sol.center, n: 300, l: sol.size.magnitude / 50, rate: parameter) 27 | .chaikin(n: 2)); 28 | 29 | sol.setFillColor(20, 80, 50, 30); 30 | sol.fill(SPath.star(radius: sol.size.magnitude / 4, at: sol.center, n: n)); 31 | 32 | sol.setFillColor(50, 80, 50, 30); 33 | sol.fill(SPath.regularPolygon( 34 | radius: sol.size.magnitude / 8, at: sol.center, n: n)); 35 | 36 | sol.setFillColor(220, 70, 30, 20); 37 | sol.fill(SPath.rect(at: sol.center, size: size / 5, centered: true)); 38 | } 39 | 40 | @override 41 | bool shouldRepaint(CustomPainter oldDelegate) { 42 | return true; 43 | } 44 | } 45 | 46 | class ExampleSeven extends HookWidget { 47 | @override 48 | Widget build(BuildContext context) { 49 | final parameter = useState(6); 50 | 51 | return Scaffold( 52 | appBar: AppBar(title: const Text("Fancier Shapes")), 53 | body: Container( 54 | child: Column(children: [ 55 | Slider( 56 | value: parameter.value, 57 | onChanged: (newValue) { 58 | parameter.value = newValue; 59 | }, 60 | min: 4, 61 | max: 20), 62 | Expanded( 63 | child: CustomPaint( 64 | painter: ExampleSevenPainter(parameter.value), 65 | child: Container())) 66 | ]))); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /example/lib/hello_solandra_six.dart: -------------------------------------------------------------------------------- 1 | import 'dart:math'; 2 | 3 | import 'package:flutter/material.dart'; 4 | import 'package:flutter_hooks/flutter_hooks.dart'; 5 | import 'package:solandra/iteration.dart'; 6 | import 'package:solandra/path.dart'; 7 | import 'package:solandra/solandra.dart'; 8 | 9 | class ExampleSixPainter extends CustomPainter { 10 | bool square; 11 | ExampleSixPainter(this.square); 12 | 13 | @override 14 | void paint(Canvas canvas, Size size) { 15 | final sol = Solandra(canvas, size); 16 | sol.clipped(); 17 | sol.background(45, 30, 95); 18 | 19 | sol.forTiling( 20 | n: 5, 21 | margin: 0.1, 22 | square: square, 23 | callback: (area) { 24 | final path = SPath(sol.center); 25 | 26 | times(48, (_) { 27 | path.line(to: sol.randomPoint()); 28 | }); 29 | 30 | sol.setFillColor(150 + area.index * 5, 80, 70, 20); 31 | 32 | sol.fill(SPath.rect(at: area.center, size: area.delta, centered: true) 33 | .scaled(0.9, about: area.center)); 34 | final curve = path 35 | .scaled(area.delta.width / size.width, about: sol.center) 36 | .moved(area.center - sol.center) 37 | .chaikin(n: 3); 38 | 39 | sol.fill(curve); 40 | sol.draw(curve); 41 | }); 42 | } 43 | 44 | @override 45 | bool shouldRepaint(CustomPainter oldDelegate) { 46 | return true; 47 | } 48 | } 49 | 50 | class ExampleSix extends HookWidget { 51 | @override 52 | Widget build(BuildContext context) { 53 | final square = useState(false); 54 | 55 | return Scaffold( 56 | appBar: AppBar(title: const Text("Doodles")), 57 | body: CustomPaint( 58 | painter: ExampleSixPainter(square.value), child: Container()), 59 | floatingActionButton: FloatingActionButton( 60 | child: const Icon(Icons.crop_square_sharp), 61 | onPressed: () { 62 | square.value = !square.value; 63 | }, 64 | ), 65 | ); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /example/lib/hello_solandra_three.dart: -------------------------------------------------------------------------------- 1 | import 'dart:math'; 2 | 3 | import 'package:flutter/material.dart'; 4 | import 'package:flutter_hooks/flutter_hooks.dart'; 5 | import 'package:solandra/iteration.dart'; 6 | import 'package:solandra/solandra.dart'; 7 | 8 | class ExampleThreePainter extends CustomPainter { 9 | double animatedValue; 10 | 11 | ExampleThreePainter(this.animatedValue); 12 | 13 | @override 14 | void paint(Canvas canvas, Size size) { 15 | final sol = Solandra(canvas, size); 16 | sol.clipped(); 17 | sol.background(40, 20, 90); 18 | 19 | times(24, (i) { 20 | sol.setFillColor(210, 70, 40, sol.gaussian(sd: 3, mean: 10)); 21 | canvas.drawCircle( 22 | sol.randomPoint().offset, 23 | 32 + 24 | 32 * 25 | cos(animatedValue / 100 + i).abs() * 26 | sol.gaussian(sd: 5, mean: 20), 27 | sol.fillPaint); 28 | }); 29 | } 30 | 31 | @override 32 | bool shouldRepaint(CustomPainter oldDelegate) { 33 | return true; 34 | } 35 | } 36 | 37 | class ExampleThree extends StatelessWidget { 38 | @override 39 | Widget build(BuildContext context) { 40 | return Scaffold( 41 | appBar: AppBar(title: const Text("Simple Animation")), 42 | body: TweenAnimationBuilder( 43 | tween: Tween(begin: 0, end: 3600 * 60), 44 | duration: const Duration(seconds: 3600), 45 | builder: (BuildContext ctx, double value, Widget? _) { 46 | return CustomPaint( 47 | painter: ExampleThreePainter(value), child: Container()); 48 | }), 49 | ); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /example/lib/hello_solandra_two.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_hooks/flutter_hooks.dart'; 3 | import 'package:solandra/path.dart'; 4 | import 'package:solandra/solandra.dart'; 5 | 6 | class ExampleTwoPainter extends CustomPainter { 7 | bool columnFirst; 8 | 9 | ExampleTwoPainter(this.columnFirst); 10 | 11 | @override 12 | void paint(Canvas canvas, Size size) { 13 | final sol = Solandra(canvas, size); 14 | sol.clipped(); 15 | sol.background(40, 20, 90); 16 | sol.forTiling( 17 | n: 32, 18 | margin: 0.05, 19 | columnFirst: columnFirst, 20 | callback: (area) { 21 | sol.setFillColor(area.index.toDouble(), 70, 40); 22 | sol.fill(SPath.rect(at: area.origin, size: area.delta)); 23 | }); 24 | } 25 | 26 | @override 27 | bool shouldRepaint(CustomPainter oldDelegate) { 28 | return true; 29 | } 30 | } 31 | 32 | class ExampleTwo extends HookWidget { 33 | @override 34 | Widget build(BuildContext context) { 35 | final colFirst = useState(false); 36 | return Scaffold( 37 | appBar: AppBar(title: const Text("Tiling")), 38 | body: CustomPaint( 39 | painter: ExampleTwoPainter(colFirst.value), child: Container()), 40 | floatingActionButton: FloatingActionButton( 41 | child: const Icon(Icons.crop_rotate), 42 | onPressed: () { 43 | colFirst.value = !colFirst.value; 44 | }, 45 | ), 46 | ); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /example/lib/home_screen.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'examples.dart'; 3 | 4 | class HomeScreen extends StatelessWidget { 5 | @override 6 | Widget build(BuildContext context) { 7 | final names = routeNames(); 8 | 9 | return Scaffold( 10 | appBar: AppBar( 11 | title: const Text("Solandra Examples"), 12 | ), 13 | body: CustomScrollView( 14 | slivers: [ 15 | SliverList( 16 | delegate: SliverChildBuilderDelegate((ctx, idx) { 17 | return MaterialButton( 18 | onPressed: () { 19 | Navigator.pushNamed( 20 | context, 21 | '/${idx + 1}', 22 | ); 23 | }, 24 | child: Padding( 25 | padding: const EdgeInsets.all(16), 26 | child: Text(names[idx]))); 27 | }, childCount: examplesCount)) 28 | ], 29 | )); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /example/lib/main.dart: -------------------------------------------------------------------------------- 1 | import 'package:example/examples.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | void main() { 5 | runApp(const MyApp()); 6 | } 7 | 8 | class MyApp extends StatelessWidget { 9 | const MyApp({Key? key}) : super(key: key); 10 | 11 | // This widget is the root of your application. 12 | @override 13 | Widget build(BuildContext context) { 14 | return MaterialApp( 15 | title: 'Flutter Demo', 16 | theme: ThemeData( 17 | primarySwatch: Colors.amber, 18 | 19 | // Workaround for bug in 2.5 Desktop (see https://github.com/flutter/flutter/issues/88221 ): 20 | pageTransitionsTheme: const PageTransitionsTheme( 21 | builders: { 22 | TargetPlatform.android: FadeUpwardsPageTransitionsBuilder(), 23 | TargetPlatform.iOS: CupertinoPageTransitionsBuilder(), 24 | TargetPlatform.linux: FadeUpwardsPageTransitionsBuilder(), 25 | TargetPlatform.macOS: CupertinoPageTransitionsBuilder(), 26 | TargetPlatform.windows: FadeUpwardsPageTransitionsBuilder(), 27 | }, 28 | )), 29 | routes: routes(), 30 | // showPerformanceOverlay: true, 31 | debugShowCheckedModeBanner: false, 32 | ); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /example/lib/wallpaper_creator.dart: -------------------------------------------------------------------------------- 1 | import 'dart:math'; 2 | import 'package:fast_noise/fast_noise.dart'; 3 | import 'package:flutter/foundation.dart'; 4 | import 'package:flutter/material.dart'; 5 | import 'package:flutter/widgets.dart'; 6 | import 'package:flutter_hooks/flutter_hooks.dart'; 7 | import 'package:solandra/solandra.dart'; 8 | 9 | enum SceneType { Mountains, Hills, Sea } 10 | 11 | extension SceneTypeName on SceneType { 12 | String get name => describeEnum(this); 13 | } 14 | 15 | class WallpaperCreatorPainter extends CustomPainter { 16 | SceneType sceneType; 17 | int seed; 18 | final noise = ValueNoise(interp: Interp.Quintic, octaves: 4); 19 | 20 | WallpaperCreatorPainter(this.sceneType, this.seed); 21 | 22 | @override 23 | void paint(Canvas canvas, Size size) { 24 | final sol = Solandra(canvas, size, seed: seed); 25 | sol.clipped(); 26 | sol.background(45, 30, 95); 27 | 28 | sol.setStrokeColor(210, 80, 30, 40); 29 | sol.strokePaint.strokeWidth = 5; 30 | 31 | switch (sceneType) { 32 | case SceneType.Mountains: 33 | _drawMountains(sol); 34 | break; 35 | case SceneType.Hills: 36 | _drawHills(sol); 37 | break; 38 | case SceneType.Sea: 39 | _drawSea(sol); 40 | } 41 | } 42 | 43 | void _drawMountains(Solandra sol) { 44 | sol.background(200, 50, 80); 45 | times(5, (n) { 46 | final path = SPath(Point(0, sol.height)); 47 | sol.forHorizontal( 48 | n: 64, 49 | margin: -0.1, 50 | callback: (area) { 51 | final h = sol.height * 52 | (0.2 + 53 | (4 - n) * 54 | (noise.singleValue2( 55 | seed + n * 2, 56 | 4 * (n + 3) * area.center.x / sol.width, 57 | area.center.y / sol.height)) / 58 | 12 + 59 | 0.1 * 60 | (noise.singleValue2( 61 | seed + n * 2, 62 | 48 * area.center.x / sol.width, 63 | area.center.y / sol.height))); 64 | path.line(to: Point(area.origin.x, h + sol.height * 0.2 * n)); 65 | }); 66 | 67 | path.line(to: Point(sol.width, sol.height)); 68 | path.close(); 69 | sol.setFillColor(210, 5.0 * n, 20 + 5.0 * n); 70 | sol.fill(path.chaikin()); 71 | }); 72 | } 73 | 74 | void _drawHills(Solandra sol) { 75 | sol.background(200, 90, 70); 76 | times(4, (n) { 77 | final path = SPath(Point(0, sol.height)); 78 | sol.forHorizontal( 79 | n: 32, 80 | margin: -0.1, 81 | callback: (area) { 82 | final h = sol.height * 83 | (0.25 + 84 | (8 - n) * 85 | (noise.singleValue2( 86 | seed + n * 2, 87 | 4 * (6 - n) * area.center.x / sol.width, 88 | area.center.y / sol.height)) / 89 | 32); 90 | path.line(to: Point(area.origin.x, h + sol.height * 0.2 * n)); 91 | }); 92 | 93 | path.line(to: Point(sol.width, sol.height)); 94 | path.close(); 95 | sol.setFillColor(150 + n * 2.0, 5.0 * n, 20 + 5.0 * n); 96 | sol.fill(path.chaikin(n: 3)); 97 | }); 98 | } 99 | 100 | void _drawSea(Solandra sol) { 101 | sol.background(200, 50, 80); 102 | times(24, (n) { 103 | final path = SPath(Point(0, sol.height)); 104 | sol.forHorizontal( 105 | n: 32, 106 | margin: -0.1, 107 | callback: (area) { 108 | final h = sol.height * 109 | (0.5 + 110 | 0.01 * n + 111 | 0.1 * cos(4 * pi * area.center.x / sol.width + n / 2) - 112 | 0.1 * 113 | (noise.singleValue2( 114 | seed + n * 2, 115 | 48 * area.center.x / sol.width, 116 | area.center.y / sol.height))); 117 | path.line(to: Point(area.origin.x, h)); 118 | }); 119 | 120 | path.line(to: Point(sol.width, sol.height)); 121 | path.close(); 122 | sol.setFillColor(210, 55.0, 15.0 + n + sol.gaussian(sd: 3), 95); 123 | sol.fill(path.chaikin(n: 2)); 124 | }); 125 | } 126 | 127 | @override 128 | bool shouldRepaint(CustomPainter oldDelegate) { 129 | return true; 130 | } 131 | } 132 | 133 | class WallpaperCreator extends HookWidget { 134 | @override 135 | Widget build(BuildContext context) { 136 | final sceneType = useState(SceneType.Mountains); 137 | final seed = useState(0); 138 | 139 | return Scaffold( 140 | appBar: AppBar(title: const Text("Abstract Wallpaper Generator")), 141 | body: Container( 142 | child: Column(children: [ 143 | Row( 144 | children: [ 145 | PopupMenuButton( 146 | child: Padding( 147 | padding: const EdgeInsets.all(12), 148 | child: Row(children: [ 149 | const Icon(Icons.photo), 150 | const SizedBox( 151 | width: 8, 152 | ), 153 | Text( 154 | sceneType.value.name, 155 | style: TextStyle(fontSize: 20), 156 | ) 157 | ])), 158 | itemBuilder: (_) { 159 | return SceneType.values 160 | .map( 161 | (c) => PopupMenuItem(child: Text(c.name), value: c)) 162 | .toList(); 163 | }, 164 | onSelected: (result) { 165 | sceneType.value = result; 166 | }), 167 | MaterialButton( 168 | onPressed: () { 169 | seed.value += 1; 170 | }, 171 | child: const Padding( 172 | padding: EdgeInsets.all(12), 173 | child: Text("Seed", 174 | style: TextStyle( 175 | fontSize: 20, fontWeight: FontWeight.normal))), 176 | ) 177 | ], 178 | ), 179 | Expanded( 180 | child: CustomPaint( 181 | painter: WallpaperCreatorPainter(sceneType.value, seed.value), 182 | child: Container())) 183 | ]))); 184 | } 185 | } 186 | -------------------------------------------------------------------------------- /example/macos/.gitignore: -------------------------------------------------------------------------------- 1 | # Flutter-related 2 | **/Flutter/ephemeral/ 3 | **/Pods/ 4 | 5 | # Xcode-related 6 | **/xcuserdata/ 7 | -------------------------------------------------------------------------------- /example/macos/Flutter/Flutter-Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include "ephemeral/Flutter-Generated.xcconfig" 2 | -------------------------------------------------------------------------------- /example/macos/Flutter/Flutter-Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include "ephemeral/Flutter-Generated.xcconfig" 2 | -------------------------------------------------------------------------------- /example/macos/Flutter/GeneratedPluginRegistrant.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Generated file. Do not edit. 3 | // 4 | 5 | import FlutterMacOS 6 | import Foundation 7 | 8 | 9 | func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { 10 | } 11 | -------------------------------------------------------------------------------- /example/macos/Runner.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 51; 7 | objects = { 8 | 9 | /* Begin PBXAggregateTarget section */ 10 | 33CC111A2044C6BA0003C045 /* Flutter Assemble */ = { 11 | isa = PBXAggregateTarget; 12 | buildConfigurationList = 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */; 13 | buildPhases = ( 14 | 33CC111E2044C6BF0003C045 /* ShellScript */, 15 | ); 16 | dependencies = ( 17 | ); 18 | name = "Flutter Assemble"; 19 | productName = FLX; 20 | }; 21 | /* End PBXAggregateTarget section */ 22 | 23 | /* Begin PBXBuildFile section */ 24 | 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */; }; 25 | 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC10F02044A3C60003C045 /* AppDelegate.swift */; }; 26 | 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; }; 27 | 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; }; 28 | 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; }; 29 | /* End PBXBuildFile section */ 30 | 31 | /* Begin PBXContainerItemProxy section */ 32 | 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */ = { 33 | isa = PBXContainerItemProxy; 34 | containerPortal = 33CC10E52044A3C60003C045 /* Project object */; 35 | proxyType = 1; 36 | remoteGlobalIDString = 33CC111A2044C6BA0003C045; 37 | remoteInfo = FLX; 38 | }; 39 | /* End PBXContainerItemProxy section */ 40 | 41 | /* Begin PBXCopyFilesBuildPhase section */ 42 | 33CC110E2044A8840003C045 /* Bundle Framework */ = { 43 | isa = PBXCopyFilesBuildPhase; 44 | buildActionMask = 2147483647; 45 | dstPath = ""; 46 | dstSubfolderSpec = 10; 47 | files = ( 48 | ); 49 | name = "Bundle Framework"; 50 | runOnlyForDeploymentPostprocessing = 0; 51 | }; 52 | /* End PBXCopyFilesBuildPhase section */ 53 | 54 | /* Begin PBXFileReference section */ 55 | 333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = ""; }; 56 | 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedPluginRegistrant.swift; sourceTree = ""; }; 57 | 33CC10ED2044A3C60003C045 /* Solandra Examples.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Solandra Examples.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 58 | 33CC10F02044A3C60003C045 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 59 | 33CC10F22044A3C60003C045 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = Runner/Assets.xcassets; sourceTree = ""; }; 60 | 33CC10F52044A3C60003C045 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; 61 | 33CC10F72044A3C60003C045 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = Runner/Info.plist; sourceTree = ""; }; 62 | 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainFlutterWindow.swift; sourceTree = ""; }; 63 | 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Debug.xcconfig"; sourceTree = ""; }; 64 | 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Release.xcconfig"; sourceTree = ""; }; 65 | 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = "Flutter-Generated.xcconfig"; path = "ephemeral/Flutter-Generated.xcconfig"; sourceTree = ""; }; 66 | 33E51913231747F40026EE4D /* DebugProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DebugProfile.entitlements; sourceTree = ""; }; 67 | 33E51914231749380026EE4D /* Release.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = ""; }; 68 | 33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = ""; }; 69 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = ""; }; 70 | 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = ""; }; 71 | /* End PBXFileReference section */ 72 | 73 | /* Begin PBXFrameworksBuildPhase section */ 74 | 33CC10EA2044A3C60003C045 /* Frameworks */ = { 75 | isa = PBXFrameworksBuildPhase; 76 | buildActionMask = 2147483647; 77 | files = ( 78 | ); 79 | runOnlyForDeploymentPostprocessing = 0; 80 | }; 81 | /* End PBXFrameworksBuildPhase section */ 82 | 83 | /* Begin PBXGroup section */ 84 | 33BA886A226E78AF003329D5 /* Configs */ = { 85 | isa = PBXGroup; 86 | children = ( 87 | 33E5194F232828860026EE4D /* AppInfo.xcconfig */, 88 | 9740EEB21CF90195004384FC /* Debug.xcconfig */, 89 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, 90 | 333000ED22D3DE5D00554162 /* Warnings.xcconfig */, 91 | ); 92 | path = Configs; 93 | sourceTree = ""; 94 | }; 95 | 33CC10E42044A3C60003C045 = { 96 | isa = PBXGroup; 97 | children = ( 98 | 33FAB671232836740065AC1E /* Runner */, 99 | 33CEB47122A05771004F2AC0 /* Flutter */, 100 | 33CC10EE2044A3C60003C045 /* Products */, 101 | D73912EC22F37F3D000D13A0 /* Frameworks */, 102 | ); 103 | sourceTree = ""; 104 | }; 105 | 33CC10EE2044A3C60003C045 /* Products */ = { 106 | isa = PBXGroup; 107 | children = ( 108 | 33CC10ED2044A3C60003C045 /* Solandra Examples.app */, 109 | ); 110 | name = Products; 111 | sourceTree = ""; 112 | }; 113 | 33CC11242044D66E0003C045 /* Resources */ = { 114 | isa = PBXGroup; 115 | children = ( 116 | 33CC10F22044A3C60003C045 /* Assets.xcassets */, 117 | 33CC10F42044A3C60003C045 /* MainMenu.xib */, 118 | 33CC10F72044A3C60003C045 /* Info.plist */, 119 | ); 120 | name = Resources; 121 | path = ..; 122 | sourceTree = ""; 123 | }; 124 | 33CEB47122A05771004F2AC0 /* Flutter */ = { 125 | isa = PBXGroup; 126 | children = ( 127 | 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */, 128 | 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */, 129 | 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */, 130 | 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */, 131 | ); 132 | path = Flutter; 133 | sourceTree = ""; 134 | }; 135 | 33FAB671232836740065AC1E /* Runner */ = { 136 | isa = PBXGroup; 137 | children = ( 138 | 33CC10F02044A3C60003C045 /* AppDelegate.swift */, 139 | 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */, 140 | 33E51913231747F40026EE4D /* DebugProfile.entitlements */, 141 | 33E51914231749380026EE4D /* Release.entitlements */, 142 | 33CC11242044D66E0003C045 /* Resources */, 143 | 33BA886A226E78AF003329D5 /* Configs */, 144 | ); 145 | path = Runner; 146 | sourceTree = ""; 147 | }; 148 | D73912EC22F37F3D000D13A0 /* Frameworks */ = { 149 | isa = PBXGroup; 150 | children = ( 151 | ); 152 | name = Frameworks; 153 | sourceTree = ""; 154 | }; 155 | /* End PBXGroup section */ 156 | 157 | /* Begin PBXNativeTarget section */ 158 | 33CC10EC2044A3C60003C045 /* Runner */ = { 159 | isa = PBXNativeTarget; 160 | buildConfigurationList = 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */; 161 | buildPhases = ( 162 | 33CC10E92044A3C60003C045 /* Sources */, 163 | 33CC10EA2044A3C60003C045 /* Frameworks */, 164 | 33CC10EB2044A3C60003C045 /* Resources */, 165 | 33CC110E2044A8840003C045 /* Bundle Framework */, 166 | 3399D490228B24CF009A79C7 /* ShellScript */, 167 | ); 168 | buildRules = ( 169 | ); 170 | dependencies = ( 171 | 33CC11202044C79F0003C045 /* PBXTargetDependency */, 172 | ); 173 | name = Runner; 174 | productName = Runner; 175 | productReference = 33CC10ED2044A3C60003C045 /* Solandra Examples.app */; 176 | productType = "com.apple.product-type.application"; 177 | }; 178 | /* End PBXNativeTarget section */ 179 | 180 | /* Begin PBXProject section */ 181 | 33CC10E52044A3C60003C045 /* Project object */ = { 182 | isa = PBXProject; 183 | attributes = { 184 | LastSwiftUpdateCheck = 0920; 185 | LastUpgradeCheck = 0930; 186 | ORGANIZATIONNAME = ""; 187 | TargetAttributes = { 188 | 33CC10EC2044A3C60003C045 = { 189 | CreatedOnToolsVersion = 9.2; 190 | LastSwiftMigration = 1100; 191 | ProvisioningStyle = Automatic; 192 | SystemCapabilities = { 193 | com.apple.Sandbox = { 194 | enabled = 1; 195 | }; 196 | }; 197 | }; 198 | 33CC111A2044C6BA0003C045 = { 199 | CreatedOnToolsVersion = 9.2; 200 | ProvisioningStyle = Manual; 201 | }; 202 | }; 203 | }; 204 | buildConfigurationList = 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */; 205 | compatibilityVersion = "Xcode 9.3"; 206 | developmentRegion = en; 207 | hasScannedForEncodings = 0; 208 | knownRegions = ( 209 | en, 210 | Base, 211 | ); 212 | mainGroup = 33CC10E42044A3C60003C045; 213 | productRefGroup = 33CC10EE2044A3C60003C045 /* Products */; 214 | projectDirPath = ""; 215 | projectRoot = ""; 216 | targets = ( 217 | 33CC10EC2044A3C60003C045 /* Runner */, 218 | 33CC111A2044C6BA0003C045 /* Flutter Assemble */, 219 | ); 220 | }; 221 | /* End PBXProject section */ 222 | 223 | /* Begin PBXResourcesBuildPhase section */ 224 | 33CC10EB2044A3C60003C045 /* Resources */ = { 225 | isa = PBXResourcesBuildPhase; 226 | buildActionMask = 2147483647; 227 | files = ( 228 | 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */, 229 | 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */, 230 | ); 231 | runOnlyForDeploymentPostprocessing = 0; 232 | }; 233 | /* End PBXResourcesBuildPhase section */ 234 | 235 | /* Begin PBXShellScriptBuildPhase section */ 236 | 3399D490228B24CF009A79C7 /* ShellScript */ = { 237 | isa = PBXShellScriptBuildPhase; 238 | buildActionMask = 2147483647; 239 | files = ( 240 | ); 241 | inputFileListPaths = ( 242 | ); 243 | inputPaths = ( 244 | ); 245 | outputFileListPaths = ( 246 | ); 247 | outputPaths = ( 248 | ); 249 | runOnlyForDeploymentPostprocessing = 0; 250 | shellPath = /bin/sh; 251 | shellScript = "echo \"$PRODUCT_NAME.app\" > \"$PROJECT_DIR\"/Flutter/ephemeral/.app_filename && \"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh embed\n"; 252 | }; 253 | 33CC111E2044C6BF0003C045 /* ShellScript */ = { 254 | isa = PBXShellScriptBuildPhase; 255 | buildActionMask = 2147483647; 256 | files = ( 257 | ); 258 | inputFileListPaths = ( 259 | Flutter/ephemeral/FlutterInputs.xcfilelist, 260 | ); 261 | inputPaths = ( 262 | Flutter/ephemeral/tripwire, 263 | ); 264 | outputFileListPaths = ( 265 | Flutter/ephemeral/FlutterOutputs.xcfilelist, 266 | ); 267 | outputPaths = ( 268 | ); 269 | runOnlyForDeploymentPostprocessing = 0; 270 | shellPath = /bin/sh; 271 | shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire"; 272 | }; 273 | /* End PBXShellScriptBuildPhase section */ 274 | 275 | /* Begin PBXSourcesBuildPhase section */ 276 | 33CC10E92044A3C60003C045 /* Sources */ = { 277 | isa = PBXSourcesBuildPhase; 278 | buildActionMask = 2147483647; 279 | files = ( 280 | 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */, 281 | 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */, 282 | 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */, 283 | ); 284 | runOnlyForDeploymentPostprocessing = 0; 285 | }; 286 | /* End PBXSourcesBuildPhase section */ 287 | 288 | /* Begin PBXTargetDependency section */ 289 | 33CC11202044C79F0003C045 /* PBXTargetDependency */ = { 290 | isa = PBXTargetDependency; 291 | target = 33CC111A2044C6BA0003C045 /* Flutter Assemble */; 292 | targetProxy = 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */; 293 | }; 294 | /* End PBXTargetDependency section */ 295 | 296 | /* Begin PBXVariantGroup section */ 297 | 33CC10F42044A3C60003C045 /* MainMenu.xib */ = { 298 | isa = PBXVariantGroup; 299 | children = ( 300 | 33CC10F52044A3C60003C045 /* Base */, 301 | ); 302 | name = MainMenu.xib; 303 | path = Runner; 304 | sourceTree = ""; 305 | }; 306 | /* End PBXVariantGroup section */ 307 | 308 | /* Begin XCBuildConfiguration section */ 309 | 338D0CE9231458BD00FA5F75 /* Profile */ = { 310 | isa = XCBuildConfiguration; 311 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; 312 | buildSettings = { 313 | ALWAYS_SEARCH_USER_PATHS = NO; 314 | CLANG_ANALYZER_NONNULL = YES; 315 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 316 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 317 | CLANG_CXX_LIBRARY = "libc++"; 318 | CLANG_ENABLE_MODULES = YES; 319 | CLANG_ENABLE_OBJC_ARC = YES; 320 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 321 | CLANG_WARN_BOOL_CONVERSION = YES; 322 | CLANG_WARN_CONSTANT_CONVERSION = YES; 323 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 324 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 325 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 326 | CLANG_WARN_EMPTY_BODY = YES; 327 | CLANG_WARN_ENUM_CONVERSION = YES; 328 | CLANG_WARN_INFINITE_RECURSION = YES; 329 | CLANG_WARN_INT_CONVERSION = YES; 330 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 331 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 332 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 333 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 334 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 335 | CODE_SIGN_IDENTITY = "-"; 336 | COPY_PHASE_STRIP = NO; 337 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 338 | ENABLE_NS_ASSERTIONS = NO; 339 | ENABLE_STRICT_OBJC_MSGSEND = YES; 340 | GCC_C_LANGUAGE_STANDARD = gnu11; 341 | GCC_NO_COMMON_BLOCKS = YES; 342 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 343 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 344 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 345 | GCC_WARN_UNUSED_FUNCTION = YES; 346 | GCC_WARN_UNUSED_VARIABLE = YES; 347 | MACOSX_DEPLOYMENT_TARGET = 10.11; 348 | MTL_ENABLE_DEBUG_INFO = NO; 349 | SDKROOT = macosx; 350 | SWIFT_COMPILATION_MODE = wholemodule; 351 | SWIFT_OPTIMIZATION_LEVEL = "-O"; 352 | }; 353 | name = Profile; 354 | }; 355 | 338D0CEA231458BD00FA5F75 /* Profile */ = { 356 | isa = XCBuildConfiguration; 357 | baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; 358 | buildSettings = { 359 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 360 | CLANG_ENABLE_MODULES = YES; 361 | CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; 362 | CODE_SIGN_STYLE = Automatic; 363 | COMBINE_HIDPI_IMAGES = YES; 364 | INFOPLIST_FILE = Runner/Info.plist; 365 | LD_RUNPATH_SEARCH_PATHS = ( 366 | "$(inherited)", 367 | "@executable_path/../Frameworks", 368 | ); 369 | PRODUCT_BUNDLE_IDENTIFIER = "uk.amimetic.solandra-examples"; 370 | PRODUCT_NAME = "Solandra Examples"; 371 | PROVISIONING_PROFILE_SPECIFIER = ""; 372 | SWIFT_VERSION = 5.0; 373 | }; 374 | name = Profile; 375 | }; 376 | 338D0CEB231458BD00FA5F75 /* Profile */ = { 377 | isa = XCBuildConfiguration; 378 | buildSettings = { 379 | CODE_SIGN_STYLE = Manual; 380 | PRODUCT_NAME = "$(TARGET_NAME)"; 381 | }; 382 | name = Profile; 383 | }; 384 | 33CC10F92044A3C60003C045 /* Debug */ = { 385 | isa = XCBuildConfiguration; 386 | baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; 387 | buildSettings = { 388 | ALWAYS_SEARCH_USER_PATHS = NO; 389 | CLANG_ANALYZER_NONNULL = YES; 390 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 391 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 392 | CLANG_CXX_LIBRARY = "libc++"; 393 | CLANG_ENABLE_MODULES = YES; 394 | CLANG_ENABLE_OBJC_ARC = YES; 395 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 396 | CLANG_WARN_BOOL_CONVERSION = YES; 397 | CLANG_WARN_CONSTANT_CONVERSION = YES; 398 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 399 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 400 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 401 | CLANG_WARN_EMPTY_BODY = YES; 402 | CLANG_WARN_ENUM_CONVERSION = YES; 403 | CLANG_WARN_INFINITE_RECURSION = YES; 404 | CLANG_WARN_INT_CONVERSION = YES; 405 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 406 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 407 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 408 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 409 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 410 | CODE_SIGN_IDENTITY = "-"; 411 | COPY_PHASE_STRIP = NO; 412 | DEBUG_INFORMATION_FORMAT = dwarf; 413 | ENABLE_STRICT_OBJC_MSGSEND = YES; 414 | ENABLE_TESTABILITY = YES; 415 | GCC_C_LANGUAGE_STANDARD = gnu11; 416 | GCC_DYNAMIC_NO_PIC = NO; 417 | GCC_NO_COMMON_BLOCKS = YES; 418 | GCC_OPTIMIZATION_LEVEL = 0; 419 | GCC_PREPROCESSOR_DEFINITIONS = ( 420 | "DEBUG=1", 421 | "$(inherited)", 422 | ); 423 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 424 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 425 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 426 | GCC_WARN_UNUSED_FUNCTION = YES; 427 | GCC_WARN_UNUSED_VARIABLE = YES; 428 | MACOSX_DEPLOYMENT_TARGET = 10.11; 429 | MTL_ENABLE_DEBUG_INFO = YES; 430 | ONLY_ACTIVE_ARCH = YES; 431 | SDKROOT = macosx; 432 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 433 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 434 | }; 435 | name = Debug; 436 | }; 437 | 33CC10FA2044A3C60003C045 /* Release */ = { 438 | isa = XCBuildConfiguration; 439 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; 440 | buildSettings = { 441 | ALWAYS_SEARCH_USER_PATHS = NO; 442 | CLANG_ANALYZER_NONNULL = YES; 443 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 444 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 445 | CLANG_CXX_LIBRARY = "libc++"; 446 | CLANG_ENABLE_MODULES = YES; 447 | CLANG_ENABLE_OBJC_ARC = YES; 448 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 449 | CLANG_WARN_BOOL_CONVERSION = YES; 450 | CLANG_WARN_CONSTANT_CONVERSION = YES; 451 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 452 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 453 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 454 | CLANG_WARN_EMPTY_BODY = YES; 455 | CLANG_WARN_ENUM_CONVERSION = YES; 456 | CLANG_WARN_INFINITE_RECURSION = YES; 457 | CLANG_WARN_INT_CONVERSION = YES; 458 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 459 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 460 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 461 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 462 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 463 | CODE_SIGN_IDENTITY = "-"; 464 | COPY_PHASE_STRIP = NO; 465 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 466 | ENABLE_NS_ASSERTIONS = NO; 467 | ENABLE_STRICT_OBJC_MSGSEND = YES; 468 | GCC_C_LANGUAGE_STANDARD = gnu11; 469 | GCC_NO_COMMON_BLOCKS = YES; 470 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 471 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 472 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 473 | GCC_WARN_UNUSED_FUNCTION = YES; 474 | GCC_WARN_UNUSED_VARIABLE = YES; 475 | MACOSX_DEPLOYMENT_TARGET = 10.11; 476 | MTL_ENABLE_DEBUG_INFO = NO; 477 | SDKROOT = macosx; 478 | SWIFT_COMPILATION_MODE = wholemodule; 479 | SWIFT_OPTIMIZATION_LEVEL = "-O"; 480 | }; 481 | name = Release; 482 | }; 483 | 33CC10FC2044A3C60003C045 /* Debug */ = { 484 | isa = XCBuildConfiguration; 485 | baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; 486 | buildSettings = { 487 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 488 | CLANG_ENABLE_MODULES = YES; 489 | CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; 490 | CODE_SIGN_STYLE = Automatic; 491 | COMBINE_HIDPI_IMAGES = YES; 492 | INFOPLIST_FILE = Runner/Info.plist; 493 | LD_RUNPATH_SEARCH_PATHS = ( 494 | "$(inherited)", 495 | "@executable_path/../Frameworks", 496 | ); 497 | PRODUCT_BUNDLE_IDENTIFIER = "uk.amimetic.solandra-examples"; 498 | PRODUCT_NAME = "Solandra Examples"; 499 | PROVISIONING_PROFILE_SPECIFIER = ""; 500 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 501 | SWIFT_VERSION = 5.0; 502 | }; 503 | name = Debug; 504 | }; 505 | 33CC10FD2044A3C60003C045 /* Release */ = { 506 | isa = XCBuildConfiguration; 507 | baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; 508 | buildSettings = { 509 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 510 | CLANG_ENABLE_MODULES = YES; 511 | CODE_SIGN_ENTITLEMENTS = Runner/Release.entitlements; 512 | CODE_SIGN_STYLE = Automatic; 513 | COMBINE_HIDPI_IMAGES = YES; 514 | INFOPLIST_FILE = Runner/Info.plist; 515 | LD_RUNPATH_SEARCH_PATHS = ( 516 | "$(inherited)", 517 | "@executable_path/../Frameworks", 518 | ); 519 | PRODUCT_BUNDLE_IDENTIFIER = "uk.amimetic.solandra-examples"; 520 | PRODUCT_NAME = "Solandra Examples"; 521 | PROVISIONING_PROFILE_SPECIFIER = ""; 522 | SWIFT_VERSION = 5.0; 523 | }; 524 | name = Release; 525 | }; 526 | 33CC111C2044C6BA0003C045 /* Debug */ = { 527 | isa = XCBuildConfiguration; 528 | buildSettings = { 529 | CODE_SIGN_STYLE = Manual; 530 | PRODUCT_NAME = "$(TARGET_NAME)"; 531 | }; 532 | name = Debug; 533 | }; 534 | 33CC111D2044C6BA0003C045 /* Release */ = { 535 | isa = XCBuildConfiguration; 536 | buildSettings = { 537 | CODE_SIGN_STYLE = Automatic; 538 | PRODUCT_NAME = "$(TARGET_NAME)"; 539 | }; 540 | name = Release; 541 | }; 542 | /* End XCBuildConfiguration section */ 543 | 544 | /* Begin XCConfigurationList section */ 545 | 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */ = { 546 | isa = XCConfigurationList; 547 | buildConfigurations = ( 548 | 33CC10F92044A3C60003C045 /* Debug */, 549 | 33CC10FA2044A3C60003C045 /* Release */, 550 | 338D0CE9231458BD00FA5F75 /* Profile */, 551 | ); 552 | defaultConfigurationIsVisible = 0; 553 | defaultConfigurationName = Release; 554 | }; 555 | 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */ = { 556 | isa = XCConfigurationList; 557 | buildConfigurations = ( 558 | 33CC10FC2044A3C60003C045 /* Debug */, 559 | 33CC10FD2044A3C60003C045 /* Release */, 560 | 338D0CEA231458BD00FA5F75 /* Profile */, 561 | ); 562 | defaultConfigurationIsVisible = 0; 563 | defaultConfigurationName = Release; 564 | }; 565 | 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */ = { 566 | isa = XCConfigurationList; 567 | buildConfigurations = ( 568 | 33CC111C2044C6BA0003C045 /* Debug */, 569 | 33CC111D2044C6BA0003C045 /* Release */, 570 | 338D0CEB231458BD00FA5F75 /* Profile */, 571 | ); 572 | defaultConfigurationIsVisible = 0; 573 | defaultConfigurationName = Release; 574 | }; 575 | /* End XCConfigurationList section */ 576 | }; 577 | rootObject = 33CC10E52044A3C60003C045 /* Project object */; 578 | } 579 | -------------------------------------------------------------------------------- /example/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 37 | 38 | 39 | 40 | 41 | 42 | 52 | 54 | 60 | 61 | 62 | 63 | 69 | 71 | 77 | 78 | 79 | 80 | 82 | 83 | 86 | 87 | 88 | -------------------------------------------------------------------------------- /example/macos/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /example/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/macos/Runner/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import Cocoa 2 | import FlutterMacOS 3 | 4 | @NSApplicationMain 5 | class AppDelegate: FlutterAppDelegate { 6 | override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { 7 | return true 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /example/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "16x16", 5 | "idiom" : "mac", 6 | "filename" : "app_icon_16.png", 7 | "scale" : "1x" 8 | }, 9 | { 10 | "size" : "16x16", 11 | "idiom" : "mac", 12 | "filename" : "app_icon_32.png", 13 | "scale" : "2x" 14 | }, 15 | { 16 | "size" : "32x32", 17 | "idiom" : "mac", 18 | "filename" : "app_icon_32.png", 19 | "scale" : "1x" 20 | }, 21 | { 22 | "size" : "32x32", 23 | "idiom" : "mac", 24 | "filename" : "app_icon_64.png", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "size" : "128x128", 29 | "idiom" : "mac", 30 | "filename" : "app_icon_128.png", 31 | "scale" : "1x" 32 | }, 33 | { 34 | "size" : "128x128", 35 | "idiom" : "mac", 36 | "filename" : "app_icon_256.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "256x256", 41 | "idiom" : "mac", 42 | "filename" : "app_icon_256.png", 43 | "scale" : "1x" 44 | }, 45 | { 46 | "size" : "256x256", 47 | "idiom" : "mac", 48 | "filename" : "app_icon_512.png", 49 | "scale" : "2x" 50 | }, 51 | { 52 | "size" : "512x512", 53 | "idiom" : "mac", 54 | "filename" : "app_icon_512.png", 55 | "scale" : "1x" 56 | }, 57 | { 58 | "size" : "512x512", 59 | "idiom" : "mac", 60 | "filename" : "app_icon_1024.png", 61 | "scale" : "2x" 62 | } 63 | ], 64 | "info" : { 65 | "version" : 1, 66 | "author" : "xcode" 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jamesporter/solandra-flutter/e33e61691205ae8d4ee821db9ca5835cea736513/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png -------------------------------------------------------------------------------- /example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jamesporter/solandra-flutter/e33e61691205ae8d4ee821db9ca5835cea736513/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png -------------------------------------------------------------------------------- /example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jamesporter/solandra-flutter/e33e61691205ae8d4ee821db9ca5835cea736513/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png -------------------------------------------------------------------------------- /example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jamesporter/solandra-flutter/e33e61691205ae8d4ee821db9ca5835cea736513/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png -------------------------------------------------------------------------------- /example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jamesporter/solandra-flutter/e33e61691205ae8d4ee821db9ca5835cea736513/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png -------------------------------------------------------------------------------- /example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jamesporter/solandra-flutter/e33e61691205ae8d4ee821db9ca5835cea736513/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png -------------------------------------------------------------------------------- /example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jamesporter/solandra-flutter/e33e61691205ae8d4ee821db9ca5835cea736513/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png -------------------------------------------------------------------------------- /example/macos/Runner/Configs/AppInfo.xcconfig: -------------------------------------------------------------------------------- 1 | // Application-level settings for the Runner target. 2 | // 3 | // This may be replaced with something auto-generated from metadata (e.g., pubspec.yaml) in the 4 | // future. If not, the values below would default to using the project name when this becomes a 5 | // 'flutter create' template. 6 | 7 | // The application's name. By default this is also the title of the Flutter window. 8 | PRODUCT_NAME = example 9 | 10 | // The application's bundle identifier 11 | PRODUCT_BUNDLE_IDENTIFIER = com.example.example 12 | 13 | // The copyright displayed in application information 14 | PRODUCT_COPYRIGHT = Copyright © 2021 com.example. All rights reserved. 15 | -------------------------------------------------------------------------------- /example/macos/Runner/Configs/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include "../../Flutter/Flutter-Debug.xcconfig" 2 | #include "Warnings.xcconfig" 3 | -------------------------------------------------------------------------------- /example/macos/Runner/Configs/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include "../../Flutter/Flutter-Release.xcconfig" 2 | #include "Warnings.xcconfig" 3 | -------------------------------------------------------------------------------- /example/macos/Runner/Configs/Warnings.xcconfig: -------------------------------------------------------------------------------- 1 | WARNING_CFLAGS = -Wall -Wconditional-uninitialized -Wnullable-to-nonnull-conversion -Wmissing-method-return-type -Woverlength-strings 2 | GCC_WARN_UNDECLARED_SELECTOR = YES 3 | CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES 4 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE 5 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES 6 | CLANG_WARN_PRAGMA_PACK = YES 7 | CLANG_WARN_STRICT_PROTOTYPES = YES 8 | CLANG_WARN_COMMA = YES 9 | GCC_WARN_STRICT_SELECTOR_MATCH = YES 10 | CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES 11 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES 12 | GCC_WARN_SHADOW = YES 13 | CLANG_WARN_UNREACHABLE_CODE = YES 14 | -------------------------------------------------------------------------------- /example/macos/Runner/DebugProfile.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.app-sandbox 6 | 7 | com.apple.security.cs.allow-jit 8 | 9 | com.apple.security.network.server 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /example/macos/Runner/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIconFile 10 | 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | $(FLUTTER_BUILD_NAME) 21 | CFBundleVersion 22 | $(FLUTTER_BUILD_NUMBER) 23 | LSApplicationCategoryType 24 | public.app-category.graphics-design 25 | LSMinimumSystemVersion 26 | $(MACOSX_DEPLOYMENT_TARGET) 27 | NSHumanReadableCopyright 28 | $(PRODUCT_COPYRIGHT) 29 | NSMainNibFile 30 | MainMenu 31 | NSPrincipalClass 32 | NSApplication 33 | 34 | 35 | -------------------------------------------------------------------------------- /example/macos/Runner/MainFlutterWindow.swift: -------------------------------------------------------------------------------- 1 | import Cocoa 2 | import FlutterMacOS 3 | 4 | class MainFlutterWindow: NSWindow { 5 | override func awakeFromNib() { 6 | let flutterViewController = FlutterViewController.init() 7 | let windowFrame = self.frame 8 | self.contentViewController = flutterViewController 9 | self.setFrame(windowFrame, display: true) 10 | 11 | RegisterGeneratedPlugins(registry: flutterViewController) 12 | 13 | super.awakeFromNib() 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /example/macos/Runner/Release.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.app-sandbox 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/pubspec.lock: -------------------------------------------------------------------------------- 1 | # Generated by pub 2 | # See https://dart.dev/tools/pub/glossary#lockfile 3 | packages: 4 | async: 5 | dependency: transitive 6 | description: 7 | name: async 8 | url: "https://pub.dartlang.org" 9 | source: hosted 10 | version: "2.8.2" 11 | boolean_selector: 12 | dependency: transitive 13 | description: 14 | name: boolean_selector 15 | url: "https://pub.dartlang.org" 16 | source: hosted 17 | version: "2.1.0" 18 | characters: 19 | dependency: transitive 20 | description: 21 | name: characters 22 | url: "https://pub.dartlang.org" 23 | source: hosted 24 | version: "1.2.0" 25 | charcode: 26 | dependency: transitive 27 | description: 28 | name: charcode 29 | url: "https://pub.dartlang.org" 30 | source: hosted 31 | version: "1.3.1" 32 | clock: 33 | dependency: transitive 34 | description: 35 | name: clock 36 | url: "https://pub.dartlang.org" 37 | source: hosted 38 | version: "1.1.0" 39 | collection: 40 | dependency: transitive 41 | description: 42 | name: collection 43 | url: "https://pub.dartlang.org" 44 | source: hosted 45 | version: "1.16.0" 46 | cupertino_icons: 47 | dependency: "direct main" 48 | description: 49 | name: cupertino_icons 50 | url: "https://pub.dartlang.org" 51 | source: hosted 52 | version: "1.0.3" 53 | fake_async: 54 | dependency: transitive 55 | description: 56 | name: fake_async 57 | url: "https://pub.dartlang.org" 58 | source: hosted 59 | version: "1.3.0" 60 | fast_noise: 61 | dependency: "direct main" 62 | description: 63 | name: fast_noise 64 | url: "https://pub.dartlang.org" 65 | source: hosted 66 | version: "1.0.1" 67 | fixnum: 68 | dependency: transitive 69 | description: 70 | name: fixnum 71 | url: "https://pub.dartlang.org" 72 | source: hosted 73 | version: "1.0.0" 74 | flutter: 75 | dependency: "direct main" 76 | description: flutter 77 | source: sdk 78 | version: "0.0.0" 79 | flutter_hooks: 80 | dependency: "direct main" 81 | description: 82 | name: flutter_hooks 83 | url: "https://pub.dartlang.org" 84 | source: hosted 85 | version: "0.18.0" 86 | flutter_lints: 87 | dependency: "direct dev" 88 | description: 89 | name: flutter_lints 90 | url: "https://pub.dartlang.org" 91 | source: hosted 92 | version: "1.0.4" 93 | flutter_test: 94 | dependency: "direct dev" 95 | description: flutter 96 | source: sdk 97 | version: "0.0.0" 98 | lints: 99 | dependency: transitive 100 | description: 101 | name: lints 102 | url: "https://pub.dartlang.org" 103 | source: hosted 104 | version: "1.0.1" 105 | matcher: 106 | dependency: transitive 107 | description: 108 | name: matcher 109 | url: "https://pub.dartlang.org" 110 | source: hosted 111 | version: "0.12.11" 112 | material_color_utilities: 113 | dependency: transitive 114 | description: 115 | name: material_color_utilities 116 | url: "https://pub.dartlang.org" 117 | source: hosted 118 | version: "0.1.4" 119 | meta: 120 | dependency: transitive 121 | description: 122 | name: meta 123 | url: "https://pub.dartlang.org" 124 | source: hosted 125 | version: "1.7.0" 126 | path: 127 | dependency: transitive 128 | description: 129 | name: path 130 | url: "https://pub.dartlang.org" 131 | source: hosted 132 | version: "1.8.1" 133 | sky_engine: 134 | dependency: transitive 135 | description: flutter 136 | source: sdk 137 | version: "0.0.99" 138 | solandra: 139 | dependency: "direct main" 140 | description: 141 | path: ".." 142 | relative: true 143 | source: path 144 | version: "0.0.4" 145 | source_span: 146 | dependency: transitive 147 | description: 148 | name: source_span 149 | url: "https://pub.dartlang.org" 150 | source: hosted 151 | version: "1.8.2" 152 | stack_trace: 153 | dependency: transitive 154 | description: 155 | name: stack_trace 156 | url: "https://pub.dartlang.org" 157 | source: hosted 158 | version: "1.10.0" 159 | stream_channel: 160 | dependency: transitive 161 | description: 162 | name: stream_channel 163 | url: "https://pub.dartlang.org" 164 | source: hosted 165 | version: "2.1.0" 166 | string_scanner: 167 | dependency: transitive 168 | description: 169 | name: string_scanner 170 | url: "https://pub.dartlang.org" 171 | source: hosted 172 | version: "1.1.0" 173 | term_glyph: 174 | dependency: transitive 175 | description: 176 | name: term_glyph 177 | url: "https://pub.dartlang.org" 178 | source: hosted 179 | version: "1.2.0" 180 | test_api: 181 | dependency: transitive 182 | description: 183 | name: test_api 184 | url: "https://pub.dartlang.org" 185 | source: hosted 186 | version: "0.4.9" 187 | vector_math: 188 | dependency: transitive 189 | description: 190 | name: vector_math 191 | url: "https://pub.dartlang.org" 192 | source: hosted 193 | version: "2.1.2" 194 | sdks: 195 | dart: ">=2.17.0-0 <3.0.0" 196 | flutter: ">=1.20.0" 197 | -------------------------------------------------------------------------------- /example/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: example 2 | description: Examples of using Solandra 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" # Remove this line if you wish to publish to pub.dev 7 | 8 | # The following defines the version and build number for your application. 9 | # A version number is three numbers separated by dots, like 1.2.43 10 | # followed by an optional build number separated by a +. 11 | # Both the version and the builder number may be overridden in flutter 12 | # build by specifying --build-name and --build-number, respectively. 13 | # In Android, build-name is used as versionName while build-number used as versionCode. 14 | # Read more about Android versioning at https://developer.android.com/studio/publish/versioning 15 | # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. 16 | # Read more about iOS versioning at 17 | # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html 18 | version: 1.0.0+1 19 | 20 | environment: 21 | sdk: ">=2.12.0 <3.0.0" 22 | 23 | # Dependencies specify other packages that your package needs in order to work. 24 | # To automatically upgrade your package dependencies to the latest versions 25 | # consider running `flutter pub upgrade --major-versions`. Alternatively, 26 | # dependencies can be manually updated by changing the version numbers below to 27 | # the latest version available on pub.dev. To see which dependencies have newer 28 | # versions available, run `flutter pub outdated`. 29 | dependencies: 30 | flutter: 31 | sdk: flutter 32 | cupertino_icons: ^1.0.2 33 | solandra: 34 | path: ../ 35 | flutter_hooks: ^0.18.0 36 | fast_noise: ^1.0.1 37 | 38 | dev_dependencies: 39 | flutter_test: 40 | sdk: flutter 41 | 42 | # The "flutter_lints" package below contains a set of recommended lints to 43 | # encourage good coding practices. The lint set provided by the package is 44 | # activated in the `analysis_options.yaml` file located at the root of your 45 | # package. See that file for information about deactivating specific lint 46 | # rules and activating additional ones. 47 | flutter_lints: ^1.0.0 48 | 49 | # For information on the generic Dart part of this file, see the 50 | # following page: https://dart.dev/tools/pub/pubspec 51 | 52 | # The following section is specific to Flutter. 53 | flutter: 54 | # The following line ensures that the Material Icons font is 55 | # included with your application, so that you can use the icons in 56 | # the material Icons class. 57 | uses-material-design: true 58 | 59 | # To add assets to your application, add an assets section, like this: 60 | # assets: 61 | # - images/a_dot_burr.jpeg 62 | # - images/a_dot_ham.jpeg 63 | 64 | # An image asset can refer to one or more resolution-specific "variants", see 65 | # https://flutter.dev/assets-and-images/#resolution-aware. 66 | 67 | # For details regarding adding assets from package dependencies, see 68 | # https://flutter.dev/assets-and-images/#from-packages 69 | 70 | # To add custom fonts to your application, add a fonts section here, 71 | # in this "flutter" section. Each entry in this list should have a 72 | # "family" key with the font family name, and a "fonts" key with a 73 | # list giving the asset and other descriptors for the font. For 74 | # example: 75 | # fonts: 76 | # - family: Schyler 77 | # fonts: 78 | # - asset: fonts/Schyler-Regular.ttf 79 | # - asset: fonts/Schyler-Italic.ttf 80 | # style: italic 81 | # - family: Trajan Pro 82 | # fonts: 83 | # - asset: fonts/TrajanPro.ttf 84 | # - asset: fonts/TrajanPro_Bold.ttf 85 | # weight: 700 86 | # 87 | # For details regarding fonts from package dependencies, 88 | # see https://flutter.dev/custom-fonts/#from-packages 89 | -------------------------------------------------------------------------------- /example/test/widget_test.dart: -------------------------------------------------------------------------------- 1 | // This is a basic Flutter widget test. 2 | // 3 | // To perform an interaction with a widget in your test, use the WidgetTester 4 | // utility that Flutter provides. For example, you can send tap and scroll 5 | // gestures. You can also use WidgetTester to find child widgets in the widget 6 | // tree, read text, and verify that the values of widget properties are correct. 7 | 8 | import 'package:flutter/material.dart'; 9 | import 'package:flutter_test/flutter_test.dart'; 10 | 11 | import 'package:example/main.dart'; 12 | 13 | void main() { 14 | testWidgets('Counter increments smoke test', (WidgetTester tester) async { 15 | // Build our app and trigger a frame. 16 | await tester.pumpWidget(const MyApp()); 17 | 18 | // Verify that our counter starts at 0. 19 | expect(find.text('0'), findsOneWidget); 20 | expect(find.text('1'), findsNothing); 21 | 22 | // Tap the '+' icon and trigger a frame. 23 | await tester.tap(find.byIcon(Icons.add)); 24 | await tester.pump(); 25 | 26 | // Verify that our counter has incremented. 27 | expect(find.text('0'), findsNothing); 28 | expect(find.text('1'), findsOneWidget); 29 | }); 30 | } 31 | -------------------------------------------------------------------------------- /example/web/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jamesporter/solandra-flutter/e33e61691205ae8d4ee821db9ca5835cea736513/example/web/favicon.png -------------------------------------------------------------------------------- /example/web/icons/Icon-192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jamesporter/solandra-flutter/e33e61691205ae8d4ee821db9ca5835cea736513/example/web/icons/Icon-192.png -------------------------------------------------------------------------------- /example/web/icons/Icon-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jamesporter/solandra-flutter/e33e61691205ae8d4ee821db9ca5835cea736513/example/web/icons/Icon-512.png -------------------------------------------------------------------------------- /example/web/icons/Icon-maskable-192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jamesporter/solandra-flutter/e33e61691205ae8d4ee821db9ca5835cea736513/example/web/icons/Icon-maskable-192.png -------------------------------------------------------------------------------- /example/web/icons/Icon-maskable-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jamesporter/solandra-flutter/e33e61691205ae8d4ee821db9ca5835cea736513/example/web/icons/Icon-maskable-512.png -------------------------------------------------------------------------------- /example/web/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | example 30 | 31 | 32 | 33 | 36 | 100 | 101 | 102 | -------------------------------------------------------------------------------- /example/web/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "example", 3 | "short_name": "example", 4 | "start_url": ".", 5 | "display": "standalone", 6 | "background_color": "#0175C2", 7 | "theme_color": "#0175C2", 8 | "description": "A new Flutter project.", 9 | "orientation": "portrait-primary", 10 | "prefer_related_applications": false, 11 | "icons": [ 12 | { 13 | "src": "icons/Icon-192.png", 14 | "sizes": "192x192", 15 | "type": "image/png" 16 | }, 17 | { 18 | "src": "icons/Icon-512.png", 19 | "sizes": "512x512", 20 | "type": "image/png" 21 | }, 22 | { 23 | "src": "icons/Icon-maskable-192.png", 24 | "sizes": "192x192", 25 | "type": "image/png", 26 | "purpose": "maskable" 27 | }, 28 | { 29 | "src": "icons/Icon-maskable-512.png", 30 | "sizes": "512x512", 31 | "type": "image/png", 32 | "purpose": "maskable" 33 | } 34 | ] 35 | } 36 | -------------------------------------------------------------------------------- /lib/iteration.dart: -------------------------------------------------------------------------------- 1 | /// Do the callback n times, argument increases 2 | void times(int n, Function(int i) callback) { 3 | for (var i = 0; i < n; i++) { 4 | callback(i); 5 | } 6 | } 7 | 8 | /// Do the callback n times, argument decreases 9 | void downFrom(int n, Function(int i) callback) { 10 | for (var i = n; i > 0; i--) { 11 | callback(i); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /lib/path.dart: -------------------------------------------------------------------------------- 1 | import 'dart:math'; 2 | import 'dart:ui'; 3 | import 'util/convenience.dart'; 4 | 5 | /// Have lines or bezier curves, hence this parent class 6 | abstract class PathEdge { 7 | /// Add to a (standard) Path; for drawing 8 | void addToPath(Path path); 9 | 10 | /// Transform an edge with a function (on Point) 11 | PathEdge transformed(Point Function(Point) transform); 12 | 13 | /// Start of edge 14 | Point get start; 15 | 16 | /// End of edge 17 | Point get end; 18 | 19 | /// Make a copy, want to ensure immutability in some places 20 | PathEdge copy(); 21 | } 22 | 23 | /// A line part of a path 24 | class LineEdge extends PathEdge { 25 | Point from; 26 | Point to; 27 | 28 | LineEdge(this.from, this.to); 29 | 30 | @override 31 | void addToPath(Path path) { 32 | path.lineTo(to.x, to.y); 33 | } 34 | 35 | @override 36 | Point get start => from; 37 | 38 | @override 39 | Point get end => to; 40 | 41 | @override 42 | PathEdge transformed(Point Function(Point) transform) { 43 | return LineEdge(transform(from), transform(to)); 44 | } 45 | 46 | @override 47 | PathEdge copy() => LineEdge(from, to); 48 | } 49 | 50 | /// Cubic bezier curve in path. Note that offers a novel API that is more human friendly: describe curve features in way that is invariant to size, rather than the standard control points (which are implicitly related to start and end points). 51 | class CubicEdge extends PathEdge { 52 | Point from; 53 | Point to; 54 | bool positive; 55 | double curveSize; 56 | double curveAngle; 57 | double bulbousness; 58 | double twist; 59 | 60 | CubicEdge({ 61 | required this.from, 62 | required this.to, 63 | required this.positive, 64 | required this.curveSize, 65 | required this.curveAngle, 66 | required this.bulbousness, 67 | required this.twist, 68 | }); 69 | 70 | @override 71 | void addToPath(Path path) { 72 | double polarity = positive ? 1 : -1; 73 | final u = to - from; 74 | final d = u.magnitude; 75 | final m = from + u * 0.5; 76 | final perp = (u.rotate(-pi / 2)).normalised; 77 | final rotatedPerp = perp.rotate(curveAngle); 78 | final controlMid = m + rotatedPerp * curveSize * polarity * d * 0.5; 79 | final perpOfRot = rotatedPerp.rotate(-pi / 2 - twist).normalised; 80 | final control1 = controlMid + perpOfRot * ((bulbousness * d) / 2); 81 | final control2 = controlMid + perpOfRot * (-(bulbousness * d) / 2); 82 | 83 | path.cubicTo(control1.x, control1.y, control2.x, control2.y, to.x, to.y); 84 | } 85 | 86 | @override 87 | Point get start => from; 88 | 89 | @override 90 | Point get end => to; 91 | 92 | @override 93 | PathEdge transformed(Point Function(Point) transform) { 94 | return CubicEdge( 95 | from: transform(from), 96 | to: transform(to), 97 | positive: positive, 98 | curveAngle: curveAngle, 99 | curveSize: curveSize, 100 | bulbousness: bulbousness, 101 | twist: twist); 102 | } 103 | 104 | @override 105 | PathEdge copy() { 106 | return CubicEdge( 107 | from: from, 108 | to: to, 109 | positive: positive, 110 | curveSize: curveSize, 111 | curveAngle: curveAngle, 112 | bulbousness: bulbousness, 113 | twist: twist, 114 | ); 115 | } 116 | } 117 | 118 | /// A higher level Path class; allows both building and manipulation of paths, prior to drawing 119 | class SPath { 120 | List edges = []; 121 | late Point currentPoint; 122 | 123 | SPath(Point start) { 124 | currentPoint = start; 125 | } 126 | 127 | /// Conveniently construct from a List of Point 128 | SPath.fromPoints(List> points) { 129 | if (points.isEmpty) throw Exception("Must supply at least one point"); 130 | currentPoint = points.first; 131 | for (var i = 1; i < points.length; i++) { 132 | line(to: points[i]); 133 | } 134 | } 135 | 136 | /// Add a line to a point 137 | void line({required Point to}) { 138 | edges.add(LineEdge(currentPoint, to)); 139 | currentPoint = to; 140 | } 141 | 142 | /// Add a curve to a point 143 | void curve({ 144 | required Point to, 145 | bool positive = true, 146 | double curveSize = 1, 147 | double curveAngle = 0, 148 | double bulbousness = 1, 149 | double twist = 0, 150 | }) { 151 | edges.add(CubicEdge( 152 | from: currentPoint, 153 | to: to, 154 | bulbousness: bulbousness, 155 | curveAngle: curveAngle, 156 | curveSize: curveSize, 157 | twist: twist, 158 | positive: positive)); 159 | currentPoint = to; 160 | } 161 | 162 | /// Close a shape (add a line to the start) 163 | void close() { 164 | if (edges.isEmpty) throw Exception("Must have at least one point to close"); 165 | line(to: edges[0].start); 166 | } 167 | 168 | /// Get as a Path (for drawing in Flutter etc) 169 | Path get path { 170 | final path = Path(); 171 | final start = edges[0].start; 172 | path.moveTo(start.x, start.y); 173 | for (var edge in edges) { 174 | edge.addToPath(path); 175 | } 176 | return path; 177 | } 178 | 179 | /// Transform via transform on Point 180 | SPath transformed(Point Function(Point) transform) { 181 | // hmm, this will work, but kind of don't like how exposing some implementation details 182 | final newPath = SPath(transform(currentPoint)); 183 | newPath.edges = edges.map((el) => el.transformed(transform)).toList(); 184 | return newPath; 185 | } 186 | 187 | /// List of points. Loses details on curves 188 | List> get points => edges.map((e) => e.start).toList(); 189 | 190 | /// Centroid (average) point. Is often a good enough approximation for true centroid of a shape 191 | Point get centroid => edges.map((e) => e.start).centroid; 192 | 193 | /// Move the shape 194 | SPath moved(Point by) { 195 | return transformed((p) => p + by); 196 | } 197 | 198 | /// Scale the shape about its approximate centroid 199 | SPath scaled(double scale, {Point? about}) { 200 | final c = about ?? centroid; 201 | return transformed((pt) => c + (pt - c) * scale); 202 | } 203 | 204 | /// Rotate the shape about its approximate centroid 205 | SPath rotated(double angle) { 206 | final c = centroid; 207 | return transformed((pt) => c + (pt - c).rotate(angle)); 208 | } 209 | 210 | /// Draw the shape 211 | void draw(Canvas canvas, Paint paint) { 212 | canvas.drawPath(path, paint); 213 | } 214 | 215 | /// Thinking looking down on orange segments 216 | List get segmented { 217 | if (edges.length < 2) { 218 | throw Exception("You must have at least two edges to segment a (S)Path"); 219 | } 220 | final c = centroid; 221 | final n = edges.length; 222 | List paths = []; 223 | for (var i = 0; i < n; i++) { 224 | final p = SPath(edges[i].start); 225 | p.edges.add(edges[i].copy()); 226 | p.currentPoint = edges[i].end; 227 | p.line(to: c); 228 | p.close(); 229 | paths.add(p); 230 | } 231 | return paths; 232 | } 233 | 234 | /// Segment then explode outwards and scale 235 | List exploded({double magnitude = 1.2, double scale = 1}) { 236 | if (edges.length < 2) { 237 | throw Exception("You must have at least two edges to segment a (S)Path"); 238 | } 239 | final c = centroid; 240 | final n = edges.length; 241 | List paths = []; 242 | for (var i = 0; i < n; i++) { 243 | var p = SPath(edges[i].start); 244 | p.edges.add(edges[i].copy()); 245 | p.currentPoint = edges[i].end; 246 | p.line(to: c); 247 | p.close(); 248 | p = p.scaled(scale); 249 | // local centroid minus global is relative direction; multiply by magnitude - 1 to get the displacement to apply 250 | p = p.moved((p.centroid - centroid) * (magnitude - 1.0)); 251 | paths.add(p); 252 | } 253 | return paths; 254 | } 255 | 256 | /// A way to smooth out a path of lines; after just a few applications it will look like a nice curve. 257 | /// NB this converts the SPath to lines i.e. detail in any existing curves will be lost 258 | /// If the path forms a look you probably want to opt in to the looped option. 259 | SPath chaikin({int n = 1, bool looped = false}) { 260 | var pts = points; 261 | if (pts.length < 3) { 262 | throw Exception("Must have at least 3 points to perform this"); 263 | } 264 | List> newPts = []; 265 | for (var i = 0; i < n; i++) { 266 | if (!looped) { 267 | newPts.add(pts[0]); 268 | } 269 | final m = pts.length - 2; 270 | for (var j = 0; j < m; j++) { 271 | final a = pts[j]; 272 | final b = pts[j + 1]; 273 | final c = pts[j + 2]; 274 | 275 | newPts.add(b.pointTowards(a, proportion: 0.25)); 276 | newPts.add(b.pointTowards(c, proportion: 0.25)); 277 | } 278 | 279 | if (!looped) { 280 | newPts.add(pts.last); 281 | } 282 | 283 | pts = newPts; 284 | newPts = []; 285 | } 286 | // In the JS version I did some extra slice thing at end... this was very fiddly, not doing yet 287 | return SPath.fromPoints(pts); 288 | } 289 | 290 | // Shapes 291 | 292 | /// A star shape 293 | SPath.star( 294 | {double? innerRadius, 295 | required double radius, 296 | required Point at, 297 | int n = 5, 298 | double startAngle = 0}) { 299 | var a = -pi / 2 + startAngle; 300 | final iR = innerRadius ?? radius / 2; 301 | final dA = (pi * 2) / n; 302 | currentPoint = Point(at.x + radius * cos(a), at.y + radius * sin(a)); 303 | for (var i = 1; i < n; i++) { 304 | line( 305 | to: Point(at.x + iR * cos(a + (i - 0.5) * dA), 306 | at.y + iR * sin(a + (i - 0.5) * dA))); 307 | line( 308 | to: Point(at.x + radius * cos(a + i * dA), 309 | at.y + radius * sin(a + i * dA))); 310 | } 311 | line( 312 | to: Point( 313 | at.x + iR * cos(a - 0.5 * dA), at.y + iR * sin(a - 0.5 * dA))); 314 | close(); 315 | } 316 | 317 | /// A regular polygon shape 318 | SPath.regularPolygon( 319 | {required double radius, 320 | required Point at, 321 | int n = 5, 322 | double startAngle = 0}) { 323 | var a = -pi / 2 + startAngle; 324 | final dA = (pi * 2) / n; 325 | currentPoint = Point(at.x + radius * cos(a), at.y + radius * sin(a)); 326 | for (var i = 1; i < n; i++) { 327 | line( 328 | to: Point(at.x + radius * cos(a + i * dA), 329 | at.y + radius * sin(a + i * dA))); 330 | } 331 | close(); 332 | } 333 | 334 | /// A spiral shape made up of lines 335 | SPath.spiral( 336 | {required Point at, 337 | required int n, 338 | required double l, 339 | startAngle = 0, 340 | double rate = 20}) { 341 | var a = startAngle; 342 | var r = l; 343 | 344 | currentPoint = at + Point(r * cos(a), r * sin(a)); 345 | for (var i = 0; i < n; i++) { 346 | final dA = 2 * asin(l / (r * 2)); 347 | r += rate * dA; 348 | a += dA; 349 | line(to: at + Point(r * cos(a), r * sin(a))); 350 | } 351 | } 352 | 353 | /// A rectangle shape 354 | SPath.rect( 355 | {required Point at, required Size size, bool centered = false}) { 356 | if (centered) { 357 | final dX = size.width / 2; 358 | final dY = size.height / 2; 359 | currentPoint = at + Point(-dX, -dY); 360 | line(to: at + Point(dX, -dY)); 361 | line(to: at + Point(dX, dY)); 362 | line(to: at + Point(-dX, dY)); 363 | close(); 364 | } else { 365 | currentPoint = at; 366 | line(to: at + Point(size.width, 0)); 367 | line(to: at + Point(size.width, size.height)); 368 | line(to: at + Point(0, size.height)); 369 | close(); 370 | } 371 | } 372 | } 373 | -------------------------------------------------------------------------------- /lib/solandra.dart: -------------------------------------------------------------------------------- 1 | library solandra; 2 | 3 | import 'package:flutter/widgets.dart'; 4 | import 'package:flutter/painting.dart'; 5 | import 'dart:math'; 6 | 7 | // Imported but not exported (might change?) 8 | import 'util/color.dart'; 9 | 10 | // Main parts of library, all exported 11 | import 'path.dart'; 12 | import 'util/data.dart'; 13 | import 'util/convenience.dart'; 14 | 15 | export 'path.dart'; 16 | export 'util/data.dart'; 17 | export 'util/convenience.dart'; 18 | 19 | // Exported, though not used in this file 20 | export 'iteration.dart'; 21 | 22 | export 'solandra_canvas.dart'; 23 | export 'solandra_renderer.dart'; 24 | 25 | /// The main class for Solandra. Contains some state such as random number seed and some Paints 26 | class Solandra { 27 | Canvas canvas; 28 | Size size; 29 | Paint fillPaint = Paint() 30 | ..color = const Color.fromARGB(255, 32, 32, 32) 31 | ..style = PaintingStyle.fill; 32 | 33 | final c = Color.getAlphaFromOpacity(1); 34 | 35 | Paint strokePaint = Paint() 36 | ..color = const Color.fromARGB(255, 0, 0, 0) 37 | ..style = PaintingStyle.stroke; 38 | 39 | late Random _rng; 40 | 41 | Solandra(this.canvas, this.size, {int seed = 0}) { 42 | _rng = Random(seed); 43 | } 44 | 45 | /// Clip your drawing to the Canvas size 46 | clipped() { 47 | canvas.clipRect(size.rect); 48 | } 49 | 50 | /// Canvas aspect ratio 51 | double get aspectRatio => size.width / size.height; 52 | 53 | /// Canvas width 54 | double get width => size.width; 55 | 56 | /// Canvas height 57 | double get height => size.height; 58 | 59 | /// Center of Canvas 60 | Point get center => Point(size.width / 2, size.height / 2); 61 | 62 | /// Draw (stroke) a conventional Dart Path with the current strokePaint 63 | void drawPath(Path path) { 64 | canvas.drawPath(path, strokePaint); 65 | } 66 | 67 | /// Fill a conventional Dart Path with the current fillPaint 68 | void fillPath(Path path) { 69 | canvas.drawPath(path, fillPaint); 70 | } 71 | 72 | /// Draw a Solandra SPath (shape/path) with the current strokePaint 73 | void draw(SPath path) { 74 | path.draw(canvas, strokePaint); 75 | } 76 | 77 | /// Fill a Solandra SPath (shape/path) with the current fillPaint 78 | void fill(SPath path) { 79 | path.draw(canvas, fillPaint); 80 | } 81 | 82 | /// Fill the background. Color is hsl(a), h goes from 0 to 360, others from 0 to 100. 83 | void background(double h, double s, double l, [double a = 100]) { 84 | Paint paint = Paint() 85 | ..color = fromHSLA(h, s, l, a) 86 | ..style = PaintingStyle.fill; 87 | canvas.drawRect(size.rect, paint); 88 | } 89 | 90 | /// Set the color for fillPaint. Color is hsl(a), h goes from 0 to 360, others from 0 to 100. 91 | void setFillColor(double h, double s, double l, [double a = 100]) { 92 | fillPaint.color = fromHSLA(h, s, l, a); 93 | } 94 | 95 | /// Set the color for strokePaint. Color is hsl(a), h goes from 0 to 360, others from 0 to 100. 96 | void setStrokeColor(double h, double s, double l, [double a = 1.0]) { 97 | strokePaint.color = fromHSLA(h, s, l, a); 98 | } 99 | 100 | // Canvas aware Iteration 101 | 102 | /// Get a drawable Area for painting after adding a margin (proportionate) 103 | void forFrame({required Function(Area area) callback, double? margin}) { 104 | if (margin != null) { 105 | forTiling(n: 1, square: false, callback: callback); 106 | } else { 107 | callback(Area( 108 | const Point(0, 0), size, Point(size.width / 2, size.height / 2), 0)); 109 | } 110 | } 111 | 112 | /// Helper for tiling a canvas 113 | void forTiling( 114 | {required int n, 115 | bool square = true, 116 | double margin = 0, 117 | bool columnFirst = true, 118 | required Function(Area area) callback}) { 119 | if (n < 1) throw Exception("Must be positive n"); 120 | var k = 0; 121 | 122 | final marginSize = margin * size.width; 123 | final nY = square ? (n * (1 / aspectRatio)).floor() : n; 124 | final deltaX = (size.width - marginSize * 2) / n; 125 | final hY = square ? deltaX * nY : size.height - 2 * marginSize; 126 | final deltaY = hY / nY; 127 | final sX = marginSize; 128 | final sY = (size.height - hY) / 2; 129 | 130 | if (columnFirst) { 131 | for (var i = 0; i < n; i++) { 132 | for (var j = 0; j < nY; j++) { 133 | callback(Area( 134 | Point(sX + i * deltaX, sY + j * deltaY), 135 | Size(deltaX, deltaY), 136 | Point(sX + i * deltaX + deltaX / 2, sY + j * deltaY + deltaY / 2), 137 | k)); 138 | k++; 139 | } 140 | } 141 | } else { 142 | for (var j = 0; j < nY; j++) { 143 | for (var i = 0; i < n; i++) { 144 | callback(Area( 145 | Point(sX + i * deltaX, sY + j * deltaY), 146 | Size(deltaX, deltaY), 147 | Point(sX + i * deltaX + deltaX / 2, sY + j * deltaY + deltaY / 2), 148 | k)); 149 | k++; 150 | } 151 | } 152 | } 153 | } 154 | 155 | /// Go across canvas in chunks, with optional margin 156 | void forHorizontal( 157 | {required int n, 158 | double margin = 0.0, 159 | required Function(Area area) callback}) { 160 | final sX = margin * width; 161 | final eX = (1 - margin) * width; 162 | final sY = sX; 163 | final dY = height - 2 * sY; 164 | final dX = (eX - sX) / n; 165 | 166 | for (var i = 0; i < n; i++) { 167 | callback(Area(Point(sX + i * dX, sY), Size(dX, dY), 168 | Point(sX + i * dX + dX / 2, sY + dY / 2), i)); 169 | } 170 | } 171 | 172 | /// Go down canvas in chunks, with optional margin 173 | void forVertical( 174 | {required int n, 175 | double margin = 0.0, 176 | required Function(Area area) callback}) { 177 | final sX = margin * width; 178 | final eY = (1 - margin) * width; 179 | final sY = sX; 180 | final dX = width - 2 * sX; 181 | final dY = (eY - sY) / n; 182 | 183 | for (var i = 0; i < n; i++) { 184 | callback(Area(Point(sX, sY + i * dY), Size(dX, dY), 185 | Point(sX + dX / 2, sY + i * dY + dY / 2), i)); 186 | } 187 | } 188 | 189 | /// Iteration over an integer grid 190 | void forGrid( 191 | {int minX = 0, 192 | required int maxX, 193 | int minY = 0, 194 | required int maxY, 195 | bool columnFirst = true, 196 | required Function(Point point, int index) callback}) { 197 | var k = 0; 198 | if (columnFirst) { 199 | for (var i = minX; i <= maxX; i++) { 200 | for (var j = minY; j <= maxY; j++) { 201 | callback(Point(i, j), k); 202 | k++; 203 | } 204 | } 205 | } else { 206 | for (var j = minY; j <= maxY; j++) { 207 | for (var i = minX; i <= maxX; i++) { 208 | callback(Point(i, j), k); 209 | k++; 210 | } 211 | } 212 | } 213 | } 214 | 215 | /// Defaults to rotating around center of Canvas 216 | void aroundCircle( 217 | {Point? at, 218 | required double radius, 219 | required int n, 220 | required Function(Point, int) callback}) { 221 | final dA = (pi * 2) / n; 222 | var a = -pi * 0.5; 223 | Point c = at ?? center; 224 | for (var i = 0; i < n; i++) { 225 | callback( 226 | Point(c.x + radius * cos(a + dA), c.y + radius * sin(a + dA)), i); 227 | a += dA; 228 | } 229 | } 230 | 231 | // RNG 232 | 233 | /// Set the RNG seed 234 | set seed(int newSeed) { 235 | _rng = Random(newSeed); 236 | } 237 | 238 | /// Get a random point on the canvas 239 | Point randomPoint() { 240 | return Point( 241 | _rng.nextDouble() * size.width, _rng.nextDouble() * size.height); 242 | } 243 | 244 | /// Get a random angle 245 | double randomAngle() { 246 | return _rng.nextDouble() * pi * 2; 247 | } 248 | 249 | /// Get a random number 250 | double random() { 251 | // Want to be able to use same seed for standard operations (so duplicating out of box stuff) 252 | return _rng.nextDouble(); 253 | } 254 | 255 | /// Get a random integer 256 | int randomInt(int max) { 257 | return _rng.nextInt(max); 258 | } 259 | 260 | /// Get a random boolean 261 | bool randomBool() { 262 | return _rng.nextBool(); 263 | } 264 | 265 | /// Get a random Gaussian value 266 | double gaussian({double mean = 0, double sd = 1}) { 267 | final a = _rng.nextDouble(); 268 | final b = _rng.nextDouble(); 269 | final n = sqrt(-2.0 * log(a)) * cos(2.0 * pi * b); 270 | return mean + n * sd; 271 | } 272 | 273 | /// Get a random Poisson value 274 | int poisson(int lambda) { 275 | final limit = exp(-lambda); 276 | double prod = _rng.nextDouble(); 277 | int n = 0; 278 | while (prod >= limit) { 279 | n++; 280 | prod *= _rng.nextDouble(); 281 | } 282 | return n; 283 | } 284 | 285 | /// Pick an item from a list at random 286 | T sample(List items) { 287 | return items[randomInt(items.length)]; 288 | } 289 | 290 | /// Pick many items from a list at random (with replacement) 291 | List samples(List items, int count) { 292 | List result = []; 293 | for (int i = 0; i < count; i++) { 294 | result.add(sample(items)); 295 | } 296 | return result; 297 | } 298 | 299 | /// Do the callback a proportion of times 300 | void doProportion(double proportion, Function() callback) { 301 | if (random() < proportion) callback(); 302 | } 303 | 304 | /// Give a bunch of cases, do one with probability in proportion to proportion given. 305 | /// 306 | /// NB this is unlikely to be the most efficient way to do this when you iterate over it many times as there is some setup cost 307 | /// but you should be easily able to rewrite if necessary, calling `random()` directly. 308 | void proportionately(List cases) { 309 | final total = cases 310 | .map((c) => c.proportion) 311 | .reduce((value, element) => value + element); 312 | if (total <= 0) throw Exception("Must be positive total"); 313 | 314 | var r = random() * total; 315 | 316 | for (var i = 0; i < cases.length; i++) { 317 | if (cases[i].proportion > r) { 318 | cases[i].callback(); 319 | return; 320 | } else { 321 | r -= cases[i].proportion; 322 | } 323 | } 324 | //fallback *should never happen!* 325 | cases[0].callback(); 326 | } 327 | 328 | /// Perturb a point (by uniform amount in 2D) 329 | Point perturb( 330 | {required Point at, required double magnitude}) { 331 | return Point( 332 | at.x + magnitude * (random() - 0.5), 333 | at.y + magnitude * (random() - 0.5), 334 | ); 335 | } 336 | 337 | /// Shuffle a List, importantly uses same RNG as other random code. 338 | List shuffle(List items) { 339 | var currentIndex = items.length; 340 | late T temporaryValue; 341 | var randomIndex = 0; 342 | 343 | while (0 != currentIndex) { 344 | randomIndex = (random() * currentIndex).floor(); 345 | currentIndex -= 1; 346 | 347 | // And swap it with the current element. 348 | temporaryValue = items[currentIndex]; 349 | items[currentIndex] = items[randomIndex]; 350 | items[randomIndex] = temporaryValue; 351 | } 352 | return items; 353 | } 354 | } 355 | -------------------------------------------------------------------------------- /lib/solandra_canvas.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:solandra/solandra.dart'; 3 | 4 | /// simple custom painting widget; takes all available space and allows for drawing with Solandra. 5 | /// Can use with a subclass of [SolandraCustomPainter]. 6 | class SolandraPaintingWidget extends StatelessWidget { 7 | final CustomPainter painter; 8 | 9 | const SolandraPaintingWidget({Key? key, required this.painter}) 10 | : super(key: key); 11 | 12 | @override 13 | Widget build(BuildContext context) { 14 | return Expanded( 15 | child: CustomPaint( 16 | painter: painter, 17 | // need child to take size 18 | child: Container())); 19 | } 20 | } 21 | 22 | abstract class SolandraCustomPainter extends CustomPainter { 23 | void sPaint(Solandra s, Size size); 24 | 25 | @override 26 | void paint(Canvas canvas, Size size) { 27 | final s = Solandra(canvas, size); 28 | sPaint(s, size); 29 | } 30 | 31 | @override 32 | bool shouldRepaint(covariant CustomPainter oldDelegate) { 33 | return true; 34 | } 35 | 36 | /// Override to customize this 37 | int get seed => 0; 38 | } 39 | 40 | /// A very convenient way to draw with Flutter and Solandra. 41 | /// 42 | /// Simple custom painting widget; takes all available space (so you will likely need to 43 | /// put it inside something else like a [Column] or [Row]). 44 | /// 45 | class SolandraSimplePaintingWidget extends SolandraPaintingWidget { 46 | final Function(Solandra) draw; 47 | 48 | SolandraSimplePaintingWidget({ 49 | Key? key, 50 | required this.draw, 51 | }) : super(key: key, painter: SolandraSimplePainting(draw)); 52 | } 53 | 54 | class SolandraSimplePainting extends SolandraCustomPainter { 55 | final Function(Solandra) draw; 56 | late final int? seedValue; 57 | 58 | SolandraSimplePainting(this.draw, {int? seed}) { 59 | seedValue = seed; 60 | } 61 | 62 | @override 63 | void sPaint(Solandra s, Size size) { 64 | draw(s); 65 | } 66 | 67 | @override 68 | int get seed => seedValue ?? 0; 69 | } 70 | -------------------------------------------------------------------------------- /lib/solandra_renderer.dart: -------------------------------------------------------------------------------- 1 | import 'dart:typed_data'; 2 | import 'dart:ui'; 3 | 4 | import 'package:solandra/solandra.dart'; 5 | 6 | /// Flutter has create support for offscreen rendering to images but it is very boilerplate-y. 7 | /// 8 | /// Take the result of this and write to file like: 9 | /// 10 | /// ```dart 11 | /// final f = File(...); 12 | /// if (bytes != null) { 13 | /// await f.writeAsBytes(bytes); 14 | /// } 15 | /// ``` 16 | class SolandraRenderer { 17 | /// Render an image to write to a file 18 | static Future render( 19 | {required Size size, required Function(Solandra) render}) async { 20 | var recorder = PictureRecorder(); 21 | var origin = Offset.zero; 22 | 23 | var paintBounds = Rect.fromPoints( 24 | origin, 25 | origin.translate(size.width, size.height), 26 | ); 27 | 28 | final canvas = Canvas(recorder, paintBounds); 29 | final s = Solandra(canvas, size); 30 | render(s); 31 | 32 | var picture = recorder.endRecording(); 33 | var image = await picture.toImage(size.width.round(), size.height.round()); 34 | 35 | var data = await image.toByteData(format: ImageByteFormat.png); 36 | 37 | return data?.buffer.asUint8List(); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /lib/util/color.dart: -------------------------------------------------------------------------------- 1 | import 'dart:ui'; 2 | 3 | // Not a natural way to do this see https://github.com/dart-lang/language/issues/723 (proposal to add static methods to extensions) 4 | 5 | /// Creates a Color from HSL Conversion formula 6 | /// adapted from http://en.wikipedia.org/wiki/HSV_color_space. 7 | /// Assumes h in [0, 360] 8 | /// s, l and a are in [0, 100] 9 | /// 10 | fromHSLA(double h, double s, double l, double a) { 11 | double r = 0; 12 | double g = 0; 13 | double b = 0; 14 | 15 | final chroma = (1 - (2 * l / 100 - 1).abs()) * (s / 100); 16 | // Take % 360 for wrap around on hue... not really defined but I think in most cases best approach? 17 | 18 | final hDash = (h % 360) / 60; 19 | final i = hDash.floor(); 20 | final x = chroma * (1 - (hDash % 2 - 1).abs()); 21 | 22 | switch (i % 6) { 23 | case 0: 24 | r = chroma; 25 | g = x; 26 | b = 0; 27 | break; 28 | case 1: 29 | r = x; 30 | g = chroma; 31 | b = 0; 32 | break; 33 | case 2: 34 | r = 0; 35 | g = chroma; 36 | b = x; 37 | break; 38 | case 3: 39 | r = 0; 40 | g = x; 41 | b = chroma; 42 | break; 43 | case 4: 44 | r = x; 45 | g = 0; 46 | b = chroma; 47 | break; 48 | case 5: 49 | r = chroma; 50 | g = 0; 51 | b = x; 52 | break; 53 | } 54 | final m = (l / 100) - chroma / 2; 55 | 56 | r += m; 57 | g += m; 58 | b += m; 59 | 60 | return Color.fromARGB(((a * 255) / 100).floor(), (r * 255).floor(), 61 | (g * 255).floor(), (b * 255).floor()); 62 | } 63 | -------------------------------------------------------------------------------- /lib/util/convenience.dart: -------------------------------------------------------------------------------- 1 | import 'dart:math'; 2 | import 'dart:ui'; 3 | 4 | /// Helpers for Size (especially conversions) 5 | extension SizeHelpers on Size { 6 | /// Convert to Rect (at 0,0) 7 | Rect get rect => const Offset(0, 0) & this; 8 | 9 | /// Get the magnitude of a Size 10 | double get magnitude => sqrt(width * width + height * height); 11 | 12 | /// Get minimum dimension 13 | double get minimum => min(width, height); 14 | 15 | /// Convert to a point 16 | Point get point => Point(width, height); 17 | } 18 | 19 | /// Helpers for Point, mostly mathematical things 20 | extension PointHelpers on Point { 21 | /// Rotate (about 0,0) 22 | Point rotate(double angle) => 23 | Point(x * cos(angle) - y * sin(angle), x * sin(angle) + y * cos(angle)); 24 | 25 | /// Normalised version of point 26 | Point get normalised { 27 | final m = magnitude; 28 | return Point(x / m, y / m); 29 | } 30 | 31 | /// Go towards an other point by a proportion 32 | Point pointTowards(Point otherPoint, 33 | {double proportion = 0.5}) { 34 | return this + (otherPoint - this) * proportion; 35 | } 36 | 37 | /// Dot product 38 | double dot(Point other) => x * other.x + y * other.y; 39 | 40 | /// Convert to Offset 41 | Offset get offset => Offset(x, y); 42 | } 43 | 44 | /// Calculation helper for collections of points 45 | extension CentroidCalc on Iterable> { 46 | /// Get a centroid (average point) for Iterable of Points 47 | Point get centroid { 48 | Point p = const Point(0, 0); 49 | for (final el in this) { 50 | p += el; 51 | } 52 | int n = length; 53 | if (n == 0) n = 1; 54 | return Point(p.x / n, p.y / n); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /lib/util/data.dart: -------------------------------------------------------------------------------- 1 | import 'dart:math'; 2 | import 'package:flutter/painting.dart'; 3 | 4 | /// A simple class for (rectangular) parts of a canvas. Makes it easy to iterate over a canvas. 5 | class Area { 6 | Point origin; 7 | Size delta; 8 | Point center; 9 | int index; 10 | 11 | Area(this.origin, this.delta, this.center, this.index); 12 | } 13 | 14 | /// A simple class to contain options for when have several possible actions and want to do one randomly 15 | class Case { 16 | double proportion; 17 | Function() callback; 18 | 19 | Case(this.proportion, this.callback); 20 | } 21 | -------------------------------------------------------------------------------- /pubspec.lock: -------------------------------------------------------------------------------- 1 | # Generated by pub 2 | # See https://dart.dev/tools/pub/glossary#lockfile 3 | packages: 4 | async: 5 | dependency: transitive 6 | description: 7 | name: async 8 | url: "https://pub.dartlang.org" 9 | source: hosted 10 | version: "2.8.2" 11 | boolean_selector: 12 | dependency: transitive 13 | description: 14 | name: boolean_selector 15 | url: "https://pub.dartlang.org" 16 | source: hosted 17 | version: "2.1.0" 18 | characters: 19 | dependency: transitive 20 | description: 21 | name: characters 22 | url: "https://pub.dartlang.org" 23 | source: hosted 24 | version: "1.2.0" 25 | charcode: 26 | dependency: transitive 27 | description: 28 | name: charcode 29 | url: "https://pub.dartlang.org" 30 | source: hosted 31 | version: "1.3.1" 32 | clock: 33 | dependency: transitive 34 | description: 35 | name: clock 36 | url: "https://pub.dartlang.org" 37 | source: hosted 38 | version: "1.1.0" 39 | collection: 40 | dependency: transitive 41 | description: 42 | name: collection 43 | url: "https://pub.dartlang.org" 44 | source: hosted 45 | version: "1.16.0" 46 | fake_async: 47 | dependency: transitive 48 | description: 49 | name: fake_async 50 | url: "https://pub.dartlang.org" 51 | source: hosted 52 | version: "1.3.0" 53 | flutter: 54 | dependency: "direct main" 55 | description: flutter 56 | source: sdk 57 | version: "0.0.0" 58 | flutter_lints: 59 | dependency: "direct dev" 60 | description: 61 | name: flutter_lints 62 | url: "https://pub.dartlang.org" 63 | source: hosted 64 | version: "1.0.4" 65 | flutter_test: 66 | dependency: "direct dev" 67 | description: flutter 68 | source: sdk 69 | version: "0.0.0" 70 | lints: 71 | dependency: transitive 72 | description: 73 | name: lints 74 | url: "https://pub.dartlang.org" 75 | source: hosted 76 | version: "1.0.1" 77 | matcher: 78 | dependency: transitive 79 | description: 80 | name: matcher 81 | url: "https://pub.dartlang.org" 82 | source: hosted 83 | version: "0.12.11" 84 | material_color_utilities: 85 | dependency: transitive 86 | description: 87 | name: material_color_utilities 88 | url: "https://pub.dartlang.org" 89 | source: hosted 90 | version: "0.1.4" 91 | meta: 92 | dependency: transitive 93 | description: 94 | name: meta 95 | url: "https://pub.dartlang.org" 96 | source: hosted 97 | version: "1.7.0" 98 | path: 99 | dependency: transitive 100 | description: 101 | name: path 102 | url: "https://pub.dartlang.org" 103 | source: hosted 104 | version: "1.8.1" 105 | sky_engine: 106 | dependency: transitive 107 | description: flutter 108 | source: sdk 109 | version: "0.0.99" 110 | source_span: 111 | dependency: transitive 112 | description: 113 | name: source_span 114 | url: "https://pub.dartlang.org" 115 | source: hosted 116 | version: "1.8.2" 117 | stack_trace: 118 | dependency: transitive 119 | description: 120 | name: stack_trace 121 | url: "https://pub.dartlang.org" 122 | source: hosted 123 | version: "1.10.0" 124 | stream_channel: 125 | dependency: transitive 126 | description: 127 | name: stream_channel 128 | url: "https://pub.dartlang.org" 129 | source: hosted 130 | version: "2.1.0" 131 | string_scanner: 132 | dependency: transitive 133 | description: 134 | name: string_scanner 135 | url: "https://pub.dartlang.org" 136 | source: hosted 137 | version: "1.1.0" 138 | term_glyph: 139 | dependency: transitive 140 | description: 141 | name: term_glyph 142 | url: "https://pub.dartlang.org" 143 | source: hosted 144 | version: "1.2.0" 145 | test_api: 146 | dependency: transitive 147 | description: 148 | name: test_api 149 | url: "https://pub.dartlang.org" 150 | source: hosted 151 | version: "0.4.9" 152 | vector_math: 153 | dependency: transitive 154 | description: 155 | name: vector_math 156 | url: "https://pub.dartlang.org" 157 | source: hosted 158 | version: "2.1.2" 159 | sdks: 160 | dart: ">=2.17.0-0 <3.0.0" 161 | flutter: ">=1.17.0" 162 | -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: solandra 2 | description: Make drawing with Flutter concise, powerful and easy. 2D creative code/algorithmic art framework with helpers for creating shapes, iteration, (pseudo)randomness and more. 3 | version: 0.0.4 4 | homepage: https://solandra.netlify.app/ 5 | repository: https://github.com/jamesporter/solandra-flutter 6 | 7 | environment: 8 | sdk: ">=2.12.0 <3.0.0" 9 | flutter: ">=1.17.0" 10 | 11 | dependencies: 12 | flutter: 13 | sdk: flutter 14 | 15 | dev_dependencies: 16 | flutter_test: 17 | sdk: flutter 18 | flutter_lints: ^1.0.0 19 | 20 | flutter: 21 | -------------------------------------------------------------------------------- /sample-images/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jamesporter/solandra-flutter/e33e61691205ae8d4ee821db9ca5835cea736513/sample-images/1.png -------------------------------------------------------------------------------- /sample-images/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jamesporter/solandra-flutter/e33e61691205ae8d4ee821db9ca5835cea736513/sample-images/2.png -------------------------------------------------------------------------------- /sample-images/solandra-flutter-mac-sample.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jamesporter/solandra-flutter/e33e61691205ae8d4ee821db9ca5835cea736513/sample-images/solandra-flutter-mac-sample.png -------------------------------------------------------------------------------- /test/color_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_test/flutter_test.dart'; 2 | import 'package:solandra/util/color.dart'; 3 | 4 | void main() { 5 | test('hsla color construction black', () { 6 | final c = fromHSLA(0, 0, 0, 100); 7 | expect(c.toString(), "Color(0xff000000)"); 8 | }); 9 | 10 | test('hsla color construction white', () { 11 | final c = fromHSLA(0, 0, 100, 100); 12 | expect(c.toString(), "Color(0xffffffff)"); 13 | }); 14 | 15 | test('hsla color construction red', () { 16 | final c = fromHSLA(0, 100, 50, 100); 17 | expect(c.toString(), "Color(0xffff0000)"); 18 | }); 19 | 20 | test('hsla color construction blue', () { 21 | final c = fromHSLA(240, 100, 50, 100); 22 | expect(c.toString(), "Color(0xff0000ff)"); 23 | }); 24 | 25 | test('hsla color construction green', () { 26 | final c = fromHSLA(120, 100, 50, 100); 27 | expect(c.toString(), "Color(0xff00ff00)"); 28 | }); 29 | } 30 | -------------------------------------------------------------------------------- /test/convenience_test.dart: -------------------------------------------------------------------------------- 1 | import 'dart:math'; 2 | import 'dart:ui'; 3 | import 'package:flutter_test/flutter_test.dart'; 4 | import 'package:solandra/solandra.dart'; 5 | 6 | void main() { 7 | test('convenience functionality for Size', () { 8 | const s = Size(24, 24); 9 | const s2 = Size(10, 24); 10 | const s3 = Size(2, 102); 11 | 12 | final r = s.rect; 13 | expect(r.width, s.width); 14 | expect(r.height, s.height); 15 | 16 | expect(s.magnitude, closeTo(33.9411, 0.01)); 17 | expect(s2.magnitude, closeTo(26, 0.01)); 18 | expect(s3.magnitude, closeTo(102.0196, 0.01)); 19 | 20 | expect(s.minimum, 24); 21 | expect(s2.minimum, 10); 22 | expect(s3.minimum, 2); 23 | 24 | final p = s.point; 25 | expect(p.x, s.width); 26 | expect(p.y, s.height); 27 | }); 28 | 29 | test('convenience functionality for Point', () { 30 | const p = Point(4, 3); 31 | const p2 = Point(5, 8); 32 | final pR = p.rotate(pi / 2); 33 | 34 | expect(pR.x, closeTo(-3, 000.1)); 35 | expect(pR.y, closeTo(4, 000.1)); 36 | 37 | final pN = p.normalised; 38 | expect(pN.x, closeTo(0.8, 0.01)); 39 | expect(pN.y, closeTo(0.6, 0.01)); 40 | 41 | final pT = const Point(0.0, 0.0).pointTowards(p, proportion: 0.25); 42 | expect(pT.x, closeTo(1.0, 0.01)); 43 | expect(pT.y, closeTo(0.75, 0.01)); 44 | 45 | final dp = p.dot(p2); 46 | expect(dp, closeTo(44.0, 0.01)); 47 | 48 | final offP = p.offset; 49 | expect(offP.dx, closeTo(4.0, 0.01)); 50 | expect(offP.dy, closeTo(3.0, 0.01)); 51 | }); 52 | 53 | test('convenience functionality for Iterable>', () { 54 | const items = [Point(2.0, 2.0), Point(4.0, 1.0), Point(-0.3, -0.4)]; 55 | final c = items.centroid; 56 | expect(c.x, closeTo(1.9, 0.01)); 57 | expect(c.y, closeTo(0.86667, 0.01)); 58 | }); 59 | } 60 | --------------------------------------------------------------------------------