├── .gitignore
├── .metadata
├── .vscode
    └── launch.json
├── README.md
├── android
    ├── .gitignore
    ├── app
    │   ├── build.gradle
    │   └── src
    │   │   ├── debug
    │   │       └── AndroidManifest.xml
    │   │   ├── main
    │   │       ├── AndroidManifest.xml
    │   │       ├── kotlin
    │   │       │   └── dev
    │   │       │   │   └── roszkowski
    │   │       │   │       └── animations
    │   │       │   │           └── 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
├── assets
    └── placeholder_image.png
├── docs
    ├── gif.gif
    └── presentation.pdf
├── ios
    ├── .gitignore
    ├── Flutter
    │   ├── AppFrameworkInfo.plist
    │   ├── Debug.xcconfig
    │   └── Release.xcconfig
    ├── Podfile
    ├── 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
    ├── fps_widget.dart
    ├── main.dart
    └── pages
    │   ├── about.dart
    │   ├── custom_controller.dart
    │   ├── explicit
    │       ├── avatar.dart
    │       ├── dots.dart
    │       ├── explicit.dart
    │       ├── flutter.dart
    │       ├── icon.dart
    │       └── slack.dart
    │   ├── explicit_animations.dart
    │   ├── funvas.dart
    │   ├── gravity_simulation.dart
    │   ├── helpers
    │       └── staggered_animations_widgets.dart
    │   ├── implicit
    │       ├── implicit.dart
    │       ├── implicit_counter.dart
    │       └── implicit_loader.dart
    │   ├── implicit_animations.dart
    │   ├── material.dart
    │   ├── material
    │       └── example.dart
    │   ├── page.dart
    │   ├── pages.dart
    │   ├── spring_simulation.dart
    │   ├── staggered_animations.dart
    │   ├── tween_animation_builder.dart
    │   └── tweens.dart
├── linux
    ├── .gitignore
    ├── CMakeLists.txt
    ├── flutter
    │   ├── CMakeLists.txt
    │   ├── generated_plugin_registrant.cc
    │   ├── generated_plugin_registrant.h
    │   └── generated_plugins.cmake
    ├── main.cc
    ├── my_application.cc
    └── my_application.h
├── macos
    ├── .gitignore
    ├── Flutter
    │   ├── Flutter-Debug.xcconfig
    │   ├── Flutter-Release.xcconfig
    │   └── GeneratedPluginRegistrant.swift
    ├── Podfile
    ├── Podfile.lock
    ├── 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
    ├── index.html
    └── manifest.json
└── windows
    ├── .gitignore
    ├── CMakeLists.txt
    ├── flutter
        ├── CMakeLists.txt
        ├── generated_plugin_registrant.cc
        ├── generated_plugin_registrant.h
        └── generated_plugins.cmake
    └── runner
        ├── CMakeLists.txt
        ├── Runner.rc
        ├── flutter_window.cpp
        ├── flutter_window.h
        ├── main.cpp
        ├── resource.h
        ├── resources
            └── app_icon.ico
        ├── run_loop.cpp
        ├── run_loop.h
        ├── runner.exe.manifest
        ├── utils.cpp
        ├── utils.h
        ├── win32_window.cpp
        └── win32_window.h
/.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 | 
--------------------------------------------------------------------------------
/.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: c5a4b4029c0798f37c4a39b479d7cb75daa7b05c
 8 |   channel: stable
 9 | 
10 | project_type: app
11 | 
--------------------------------------------------------------------------------
/.vscode/launch.json:
--------------------------------------------------------------------------------
 1 | {
 2 |     // Use IntelliSense to learn about possible attributes.
 3 |     // Hover to view descriptions of existing attributes.
 4 |     // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
 5 |     "version": "0.2.0",
 6 |     "configurations": [
 7 |         {
 8 |             "name": "animations_samples",
 9 |             "request": "launch",
10 |             "type": "dart"
11 |         },
12 |         {
13 |             "name": "animations_samples (profile mode)",
14 |             "request": "launch",
15 |             "type": "dart",
16 |             "flutterMode": "profile"
17 |         }
18 |     ]
19 | }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
 1 | # animations
 2 | 
 3 | This is a showcase of several animation approaches in Flutter:
 4 | 
 5 | - implicit animations
 6 | - explicit animations
 7 | - TweenAnimationBuilder
 8 | - funvas
 9 | - animations package
10 | 
11 | Feel free to have fun with the app and let me know what you think :)
12 | 
13 | [Web Demo](https://roszkowski.dev/animations/)
14 | 
15 | [Presentation PDF](docs/presentation.pdf)
16 | 
17 | 
18 | 
--------------------------------------------------------------------------------
/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 | 
--------------------------------------------------------------------------------
/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 |     sourceSets {
32 |         main.java.srcDirs += 'src/main/kotlin'
33 |     }
34 | 
35 |     defaultConfig {
36 |         // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
37 |         applicationId "dev.roszkowski.animations"
38 |         minSdkVersion 16
39 |         targetSdkVersion 30
40 |         versionCode flutterVersionCode.toInteger()
41 |         versionName flutterVersionName
42 |     }
43 | 
44 |     buildTypes {
45 |         release {
46 |             // TODO: Add your own signing config for the release build.
47 |             // Signing with the debug keys for now, so `flutter run --release` works.
48 |             signingConfig signingConfigs.debug
49 |         }
50 |     }
51 | }
52 | 
53 | flutter {
54 |     source '../..'
55 | }
56 | 
57 | dependencies {
58 |     implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
59 | }
60 | 
--------------------------------------------------------------------------------
/android/app/src/debug/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 | 
3 |     
6 |     
7 | 
8 | 
--------------------------------------------------------------------------------
/android/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
 1 | 
 3 |    
 6 |         
13 |             
17 |             
21 |             
26 |             
30 |             
31 |                 
32 |                 
33 |             
34 |         
35 |         
37 |         
40 |     
41 |     
42 |     
43 |     
44 |       
45 |       
46 |     
47 |   
48 | 
49 | 
--------------------------------------------------------------------------------
/android/app/src/main/kotlin/dev/roszkowski/animations/MainActivity.kt:
--------------------------------------------------------------------------------
1 | package dev.roszkowski.animations
2 | 
3 | import io.flutter.embedding.android.FlutterActivity
4 | 
5 | class MainActivity: FlutterActivity() {
6 | }
7 | 
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-v21/launch_background.xml:
--------------------------------------------------------------------------------
 1 | 
 2 | 
 3 | 
 4 |     5 | 
 6 |     
 7 |     
12 | 
13 | 
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable/launch_background.xml:
--------------------------------------------------------------------------------
 1 | 
 2 | 
 3 | 
 4 |
5 | 
 6 |     
 7 |     
12 | 
13 | 
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orestesgaolin/animations_samples/3680de04ece1eea8d4338f0dabf353fc8e9fec4e/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orestesgaolin/animations_samples/3680de04ece1eea8d4338f0dabf353fc8e9fec4e/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orestesgaolin/animations_samples/3680de04ece1eea8d4338f0dabf353fc8e9fec4e/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orestesgaolin/animations_samples/3680de04ece1eea8d4338f0dabf353fc8e9fec4e/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orestesgaolin/animations_samples/3680de04ece1eea8d4338f0dabf353fc8e9fec4e/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/values-night/styles.xml:
--------------------------------------------------------------------------------
 1 | 
 2 | 
 3 |     
 4 |     
 9 |     
15 |     
18 | 
19 | 
--------------------------------------------------------------------------------
/android/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
 1 | 
 2 | 
 3 |     
 4 |     
 9 |     
15 |     
18 | 
19 | 
--------------------------------------------------------------------------------
/android/app/src/profile/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 | 
3 |     
6 |     
7 | 
8 | 
--------------------------------------------------------------------------------
/android/build.gradle:
--------------------------------------------------------------------------------
 1 | buildscript {
 2 |     ext.kotlin_version = '1.3.50'
 3 |     repositories {
 4 |         google()
 5 |         jcenter()
 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 |         jcenter()
18 |     }
19 | }
20 | 
21 | rootProject.buildDir = '../build'
22 | subprojects {
23 |     project.buildDir = "${rootProject.buildDir}/${project.name}"
24 | }
25 | subprojects {
26 |     project.evaluationDependsOn(':app')
27 | }
28 | 
29 | task clean(type: Delete) {
30 |     delete rootProject.buildDir
31 | }
32 | 
--------------------------------------------------------------------------------
/android/gradle.properties:
--------------------------------------------------------------------------------
1 | org.gradle.jvmargs=-Xmx1536M
2 | android.useAndroidX=true
3 | android.enableJetifier=true
4 | 
--------------------------------------------------------------------------------
/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 | 
--------------------------------------------------------------------------------
/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 | 
--------------------------------------------------------------------------------
/assets/placeholder_image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orestesgaolin/animations_samples/3680de04ece1eea8d4338f0dabf353fc8e9fec4e/assets/placeholder_image.png
--------------------------------------------------------------------------------
/docs/gif.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orestesgaolin/animations_samples/3680de04ece1eea8d4338f0dabf353fc8e9fec4e/docs/gif.gif
--------------------------------------------------------------------------------
/docs/presentation.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orestesgaolin/animations_samples/3680de04ece1eea8d4338f0dabf353fc8e9fec4e/docs/presentation.pdf
--------------------------------------------------------------------------------
/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/app.flx
22 | Flutter/app.zip
23 | Flutter/flutter_assets/
24 | Flutter/flutter_export_environment.sh
25 | ServiceDefinitions.json
26 | Runner/GeneratedPluginRegistrant.*
27 | 
28 | # Exceptions to above rules.
29 | !default.mode1v3
30 | !default.mode2v3
31 | !default.pbxuser
32 | !default.perspectivev3
33 | 
--------------------------------------------------------------------------------
/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 |   8.0
25 | 
26 | 
27 | 
--------------------------------------------------------------------------------
/ios/Flutter/Debug.xcconfig:
--------------------------------------------------------------------------------
1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
2 | #include "Generated.xcconfig"
3 | 
--------------------------------------------------------------------------------
/ios/Flutter/Release.xcconfig:
--------------------------------------------------------------------------------
1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
2 | #include "Generated.xcconfig"
3 | 
--------------------------------------------------------------------------------
/ios/Podfile:
--------------------------------------------------------------------------------
 1 | # Uncomment this line to define a global platform for your project
 2 | # platform :ios, '9.0'
 3 | 
 4 | # CocoaPods analytics sends network stats synchronously affecting flutter build latency.
 5 | ENV['COCOAPODS_DISABLE_STATS'] = 'true'
 6 | 
 7 | project 'Runner', {
 8 |   'Debug' => :debug,
 9 |   'Profile' => :release,
10 |   'Release' => :release,
11 | }
12 | 
13 | def flutter_root
14 |   generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__)
15 |   unless File.exist?(generated_xcode_build_settings_path)
16 |     raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first"
17 |   end
18 | 
19 |   File.foreach(generated_xcode_build_settings_path) do |line|
20 |     matches = line.match(/FLUTTER_ROOT\=(.*)/)
21 |     return matches[1].strip if matches
22 |   end
23 |   raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get"
24 | end
25 | 
26 | require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root)
27 | 
28 | flutter_ios_podfile_setup
29 | 
30 | target 'Runner' do
31 |   use_frameworks!
32 |   use_modular_headers!
33 | 
34 |   flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
35 | end
36 | 
37 | post_install do |installer|
38 |   installer.pods_project.targets.each do |target|
39 |     flutter_additional_ios_build_settings(target)
40 |   end
41 | end
42 | 
--------------------------------------------------------------------------------
/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 | 
2 | 
4 |    
6 |    
7 | 
8 | 
--------------------------------------------------------------------------------
/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 | 
2 | 
3 | 
4 | 
5 | 	IDEDidComputeMac32BitWarning
6 | 	
7 | 
8 | 
9 | 
--------------------------------------------------------------------------------
/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings:
--------------------------------------------------------------------------------
1 | 
2 | 
3 | 
4 | 
5 | 	PreviewsEnabled
6 | 	
7 | 
8 | 
9 | 
--------------------------------------------------------------------------------
/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 | 
--------------------------------------------------------------------------------
/ios/Runner.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 | 
2 | 
4 |    
6 |    
7 | 
8 | 
--------------------------------------------------------------------------------
/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 | 
2 | 
3 | 
4 | 
5 | 	IDEDidComputeMac32BitWarning
6 | 	
7 | 
8 | 
9 | 
--------------------------------------------------------------------------------
/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings:
--------------------------------------------------------------------------------
1 | 
2 | 
3 | 
4 | 
5 | 	PreviewsEnabled
6 | 	
7 | 
8 | 
9 | 
--------------------------------------------------------------------------------
/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 | 
--------------------------------------------------------------------------------
/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 | 
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orestesgaolin/animations_samples/3680de04ece1eea8d4338f0dabf353fc8e9fec4e/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orestesgaolin/animations_samples/3680de04ece1eea8d4338f0dabf353fc8e9fec4e/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orestesgaolin/animations_samples/3680de04ece1eea8d4338f0dabf353fc8e9fec4e/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orestesgaolin/animations_samples/3680de04ece1eea8d4338f0dabf353fc8e9fec4e/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orestesgaolin/animations_samples/3680de04ece1eea8d4338f0dabf353fc8e9fec4e/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orestesgaolin/animations_samples/3680de04ece1eea8d4338f0dabf353fc8e9fec4e/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orestesgaolin/animations_samples/3680de04ece1eea8d4338f0dabf353fc8e9fec4e/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orestesgaolin/animations_samples/3680de04ece1eea8d4338f0dabf353fc8e9fec4e/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orestesgaolin/animations_samples/3680de04ece1eea8d4338f0dabf353fc8e9fec4e/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orestesgaolin/animations_samples/3680de04ece1eea8d4338f0dabf353fc8e9fec4e/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orestesgaolin/animations_samples/3680de04ece1eea8d4338f0dabf353fc8e9fec4e/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orestesgaolin/animations_samples/3680de04ece1eea8d4338f0dabf353fc8e9fec4e/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orestesgaolin/animations_samples/3680de04ece1eea8d4338f0dabf353fc8e9fec4e/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orestesgaolin/animations_samples/3680de04ece1eea8d4338f0dabf353fc8e9fec4e/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orestesgaolin/animations_samples/3680de04ece1eea8d4338f0dabf353fc8e9fec4e/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png
--------------------------------------------------------------------------------
/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 | 
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orestesgaolin/animations_samples/3680de04ece1eea8d4338f0dabf353fc8e9fec4e/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orestesgaolin/animations_samples/3680de04ece1eea8d4338f0dabf353fc8e9fec4e/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orestesgaolin/animations_samples/3680de04ece1eea8d4338f0dabf353fc8e9fec4e/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png
--------------------------------------------------------------------------------
/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.
--------------------------------------------------------------------------------
/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 | 
--------------------------------------------------------------------------------
/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 | 
--------------------------------------------------------------------------------
/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 | 	animations
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 | 	LSApplicationQueriesSchemes
45 | 	
46 | 	https
47 | 	http
48 | 	
49 | 
50 | 
51 | 
--------------------------------------------------------------------------------
/ios/Runner/Runner-Bridging-Header.h:
--------------------------------------------------------------------------------
1 | #import "GeneratedPluginRegistrant.h"
2 | 
--------------------------------------------------------------------------------
/lib/fps_widget.dart:
--------------------------------------------------------------------------------
 1 | import 'package:flutter/material.dart';
 2 | import 'package:fps_widget/fps_widget.dart';
 3 | import 'package:provider/provider.dart';
 4 | 
 5 | class MyFpsWidget extends StatelessWidget {
 6 |   const MyFpsWidget({Key? key, required this.child}) : super(key: key);
 7 | 
 8 |   final Widget child;
 9 | 
10 |   @override
11 |   Widget build(BuildContext context) {
12 |     return ChangeNotifierProvider(
13 |       create: (_) => FpsState(),
14 |       child: FpsWrapper(child: child),
15 |     );
16 |   }
17 | }
18 | 
19 | class FpsWrapper extends StatelessWidget {
20 |   const FpsWrapper({
21 |     Key? key,
22 |     required this.child,
23 |   }) : super(key: key);
24 | 
25 |   final Widget child;
26 | 
27 |   @override
28 |   Widget build(BuildContext context) {
29 |     final value = context.watch().show;
30 |     if (value) {
31 |       return Scaffold(
32 |         body: FPSWidget(
33 |           show: true,
34 |           child: child,
35 |         ),
36 |       );
37 |     } else {
38 |       return child;
39 |     }
40 |   }
41 | }
42 | 
43 | class FpsState extends ChangeNotifier {
44 |   bool show = false;
45 | 
46 |   void toggle() {
47 |     show = !show;
48 |     notifyListeners();
49 |   }
50 | }
51 | 
--------------------------------------------------------------------------------
/lib/main.dart:
--------------------------------------------------------------------------------
  1 | import 'package:animations_sample/fps_widget.dart';
  2 | import 'package:animations_sample/pages/gravity_simulation.dart';
  3 | import 'package:flutter/material.dart';
  4 | import 'package:provider/provider.dart';
  5 | import 'package:url_launcher/url_launcher.dart';
  6 | 
  7 | import 'pages/pages.dart';
  8 | 
  9 | void main() {
 10 |   runApp(MyApp());
 11 | }
 12 | 
 13 | class MyApp extends StatelessWidget {
 14 |   @override
 15 |   Widget build(BuildContext context) {
 16 |     return MaterialApp(
 17 |       title: 'Animations Demo',
 18 |       theme: ThemeData(
 19 |         primarySwatch: Colors.blue,
 20 |         scrollbarTheme: ScrollbarThemeData(isAlwaysShown: true),
 21 |       ),
 22 |       debugShowCheckedModeBanner: false,
 23 |       home: MyFpsWidget(
 24 |         child: Dashboard(),
 25 |       ),
 26 |     );
 27 |   }
 28 | }
 29 | 
 30 | class Dashboard extends StatefulWidget {
 31 |   @override
 32 |   _DashboardState createState() => _DashboardState();
 33 | }
 34 | 
 35 | class _DashboardState extends State {
 36 |   int selectedIndex = 0;
 37 | 
 38 |   Widget getPage(int index) {
 39 |     if (index < pages.length) {
 40 |       return pages[index].widget;
 41 |     } else {
 42 |       return const SizedBox();
 43 |     }
 44 |   }
 45 | 
 46 |   final pages = [
 47 |     AppPage('Implicit animations', ImplicitAnimations()),
 48 |     AppPage('Explicit animations', ExplicitAnimations()),
 49 |     AppPage('Tweens', Tweens()),
 50 |     AppPage('TweenAnimationBuilder', TweenPageController()),
 51 |     AppPage('Staggered animations', StaggeredAnimations()),
 52 |     AppPage('Custom controller', CustomController()),
 53 |     AppPage('Spring simulation', PhysicsAnimation()),
 54 |     AppPage('Gravity simulation', GravitySimulationWidget()),
 55 |     AppPage('Material animations', MaterialAnimationsDemo()),
 56 |     AppPage('Funvas', FunvasDemo()),
 57 |   ];
 58 | 
 59 |   @override
 60 |   Widget build(BuildContext context) {
 61 |     final drawer = AppDrawer(
 62 |       pages: pages,
 63 |       selectedIndex: selectedIndex,
 64 |       onTap: (index) {
 65 |         setState(() {
 66 |           selectedIndex = index;
 67 |         });
 68 |       },
 69 |     );
 70 | 
 71 |     return Scaffold(
 72 |       drawer: drawer,
 73 |       body: LayoutBuilder(
 74 |         builder: (context, constraints) {
 75 |           return Row(
 76 |             children: [
 77 |               if (constraints.maxWidth < 800)
 78 |                 Align(
 79 |                   alignment: Alignment.topLeft,
 80 |                   child: IconButton(
 81 |                     icon: Icon(Icons.menu),
 82 |                     onPressed: () {
 83 |                       Scaffold.of(context).openDrawer();
 84 |                     },
 85 |                   ),
 86 |                 )
 87 |               else
 88 |                 drawer,
 89 |               Expanded(
 90 |                 child: getPage(selectedIndex),
 91 |               )
 92 |             ],
 93 |           );
 94 |         },
 95 |       ),
 96 |     );
 97 |   }
 98 | }
 99 | 
100 | class AppDrawer extends StatefulWidget {
101 |   const AppDrawer({
102 |     Key? key,
103 |     required this.onTap,
104 |     required this.pages,
105 |     this.selectedIndex = 0,
106 |   }) : super(key: key);
107 | 
108 |   final Function(int) onTap;
109 |   final List pages;
110 |   final int selectedIndex;
111 | 
112 |   @override
113 |   State createState() => _AppDrawerState();
114 | }
115 | 
116 | class _AppDrawerState extends State {
117 |   final scrollController = ScrollController();
118 | 
119 |   @override
120 |   void dispose() {
121 |     scrollController.dispose();
122 |     super.dispose();
123 |   }
124 | 
125 |   @override
126 |   Widget build(BuildContext context) {
127 |     final theme = Theme.of(context);
128 |     return Drawer(
129 |       child: ListView(
130 |         padding: EdgeInsets.zero,
131 |         controller: scrollController,
132 |         children: [
133 |           DrawerHeader(
134 |             child: Padding(
135 |               padding: const EdgeInsets.all(16.0),
136 |               child: Text(
137 |                 'Animations examples',
138 |                 style: theme.textTheme.headline5,
139 |               ),
140 |             ),
141 |           ),
142 |           for (final page in widget.pages)
143 |             ListTile(
144 |               leading: Icon(Icons.chevron_right),
145 |               title: Text(page.title),
146 |               selected: widget.pages.indexOf(page) == widget.selectedIndex,
147 |               onTap: () {
148 |                 widget.onTap(widget.pages.indexOf(page));
149 |                 if (Scaffold.of(context).isDrawerOpen) {
150 |                   Navigator.of(context).pop();
151 |                 }
152 |               },
153 |             ),
154 |           ThinDivider(),
155 |           ListTile(
156 |             leading: Icon(Icons.info_outline),
157 |             title: Text('About'),
158 |             onTap: () {
159 |               if (Scaffold.of(context).isDrawerOpen) {
160 |                 Navigator.of(context).pop();
161 |               }
162 |               showAboutDialog(
163 |                 context: context,
164 |                 children: [
165 |                   AboutPage(),
166 |                 ],
167 |               );
168 |               if (Scaffold.of(context).isDrawerOpen) {
169 |                 Navigator.of(context).pop();
170 |               }
171 |             },
172 |           ),
173 |           ListTile(
174 |             leading: Icon(Icons.code),
175 |             title: Text('Source Code'),
176 |             onTap: () async {
177 |               if (Scaffold.of(context).isDrawerOpen) {
178 |                 Navigator.of(context).pop();
179 |               }
180 |               final url = 'https://github.com/orestesgaolin/animations_samples';
181 |               if (await canLaunch(url)) {
182 |                 launch(url);
183 |               }
184 |             },
185 |           ),
186 |           ThinDivider(),
187 |           SwitchListTile(
188 |             value: context.watch().show,
189 |             title: Text('Show FPS'),
190 |             onChanged: (_) {
191 |               context.read().toggle();
192 |             },
193 |           ),
194 |         ],
195 |       ),
196 |     );
197 |   }
198 | }
199 | 
200 | class ThinDivider extends StatelessWidget {
201 |   const ThinDivider({
202 |     Key? key,
203 |   }) : super(key: key);
204 | 
205 |   @override
206 |   Widget build(BuildContext context) {
207 |     return Divider(
208 |       height: 1,
209 |       thickness: 1,
210 |     );
211 |   }
212 | }
213 | 
--------------------------------------------------------------------------------
/lib/pages/about.dart:
--------------------------------------------------------------------------------
 1 | import 'package:flutter/material.dart';
 2 | import 'package:gap/gap.dart';
 3 | import 'package:url_launcher/url_launcher.dart';
 4 | 
 5 | class AboutPage extends StatelessWidget {
 6 |   @override
 7 |   Widget build(BuildContext context) {
 8 |     return Column(
 9 |       mainAxisAlignment: MainAxisAlignment.center,
10 |       children: [
11 |         Text('Application made by Dominik Roszkowski'),
12 |         const Gap(16),
13 |         InkWell(
14 |           onTap: () async {
15 |             final url = 'https://roszkowski.dev';
16 |             if (await canLaunch(url)) {
17 |               launch(url);
18 |             }
19 |           },
20 |           child: Text('dominik@roszkowski.dev'),
21 |         ),
22 |         const Gap(16),
23 |         InkWell(
24 |           onTap: () async {
25 |             final url = 'https://twitter.com/OrestesGaolin';
26 |             if (await canLaunch(url)) {
27 |               launch(url);
28 |             }
29 |           },
30 |           child: Text('@OrestesGaolin'),
31 |         ),
32 |       ],
33 |     );
34 |   }
35 | }
36 | 
--------------------------------------------------------------------------------
/lib/pages/custom_controller.dart:
--------------------------------------------------------------------------------
  1 | /// Boids algorithm ported from JS to Dart by Dominik Roszkowski
  2 | /// Original version by Ben Eater licensesd under MIT
  3 | /// Available https://github.com/beneater/boids
  4 | ///
  5 | /// Check out the Smarter Every Day video about
  6 | /// this simulation https://www.youtube.com/watch?v=4LWmRuB-uNU
  7 | ///
  8 | /// Find me on Twitter https://twitter.com/OrestesGaolin
  9 | /// And my website https://roszkowski.dev/
 10 | import 'dart:math' as math;
 11 | import 'package:flutter/material.dart';
 12 | import 'package:flutter/scheduler.dart';
 13 | 
 14 | const double kSize = 150.0;
 15 | 
 16 | class CustomController extends StatelessWidget {
 17 |   @override
 18 |   Widget build(BuildContext context) {
 19 |     return BoidsAnimation();
 20 |   }
 21 | }
 22 | 
 23 | class BoidsAnimation extends StatefulWidget {
 24 |   BoidsAnimation({Key? key}) : super(key: key);
 25 | 
 26 |   @override
 27 |   _BoidsAnimationState createState() => _BoidsAnimationState();
 28 | }
 29 | 
 30 | class _BoidsAnimationState extends State
 31 |     with TickerProviderStateMixin {
 32 |   late BoidSimulation simulation;
 33 | 
 34 |   @override
 35 |   void initState() {
 36 |     super.initState();
 37 |     simulation = BoidSimulation(this);
 38 |   }
 39 | 
 40 |   @override
 41 |   void dispose() {
 42 |     simulation.dispose();
 43 |     super.dispose();
 44 |   }
 45 | 
 46 |   @override
 47 |   Widget build(BuildContext context) {
 48 |     return Column(
 49 |       children: [
 50 |         Expanded(
 51 |           child: LayoutBuilder(builder: (context, size) {
 52 |             return ColoredBox(
 53 |               color: Colors.blue[800]!,
 54 |               child: AnimatedBuilder(
 55 |                 animation: simulation,
 56 |                 builder: (context, child) => Stack(
 57 |                   children: [
 58 |                     Center(
 59 |                       child: CustomPaint(
 60 |                         painter: BoidPainter(simulation.boids),
 61 |                         child: Container(
 62 |                           height: size.maxHeight,
 63 |                           width: size.maxWidth,
 64 |                           color: Colors.white.withOpacity(0.05),
 65 |                         ),
 66 |                       ),
 67 |                     ),
 68 |                   ],
 69 |                 ),
 70 |               ),
 71 |             );
 72 |           }),
 73 |         ),
 74 |         Controls(simulation: simulation),
 75 |       ],
 76 |     );
 77 |   }
 78 | }
 79 | 
 80 | class Controls extends StatelessWidget {
 81 |   const Controls({
 82 |     Key? key,
 83 |     required this.simulation,
 84 |   }) : super(key: key);
 85 | 
 86 |   final BoidSimulation simulation;
 87 | 
 88 |   @override
 89 |   Widget build(BuildContext context) {
 90 |     return AnimatedBuilder(
 91 |         animation: simulation,
 92 |         builder: (context, anim) {
 93 |           return Padding(
 94 |             padding: const EdgeInsets.all(8.0),
 95 |             child: Wrap(
 96 |               alignment: WrapAlignment.center,
 97 |               children: [
 98 |                 Container(
 99 |                   width: 200,
100 |                   child: Column(
101 |                     children: [
102 |                       Text('Speed'),
103 |                       Slider(
104 |                         value: simulation.speedLimit,
105 |                         min: 0.0,
106 |                         max: 20.0,
107 |                         onChanged: (value) {
108 |                           simulation.speedLimit = value;
109 |                         },
110 |                       ),
111 |                     ],
112 |                   ),
113 |                 ),
114 |                 Container(
115 |                   width: 200,
116 |                   child: Column(
117 |                     children: [
118 |                       Text('Visual Range'),
119 |                       Slider(
120 |                         value: simulation.visualRange,
121 |                         min: 0.0,
122 |                         max: 100.0,
123 |                         onChanged: (value) {
124 |                           simulation.visualRange = value;
125 |                         },
126 |                       ),
127 |                     ],
128 |                   ),
129 |                 ),
130 |                 Container(
131 |                   width: 200,
132 |                   child: Column(
133 |                     children: [
134 |                       Text('Boids number'),
135 |                       Slider(
136 |                         value: simulation.numBoids.toDouble(),
137 |                         min: 0,
138 |                         max: 200,
139 |                         onChanged: (value) {
140 |                           simulation.setBoidsNumber(value.toInt());
141 |                         },
142 |                       ),
143 |                     ],
144 |                   ),
145 |                 ),
146 |                 Container(
147 |                   width: 200,
148 |                   child: Column(
149 |                     children: [
150 |                       Text('Turn factor'),
151 |                       Slider(
152 |                         value: simulation.turnFactor,
153 |                         min: 0.0,
154 |                         max: 1.0,
155 |                         onChanged: (value) {
156 |                           simulation.turnFactor = value;
157 |                         },
158 |                       ),
159 |                     ],
160 |                   ),
161 |                 ),
162 |               ],
163 |             ),
164 |           );
165 |         });
166 |   }
167 | }
168 | 
169 | class BoidPainter extends CustomPainter {
170 |   final List boids;
171 |   BoidPainter(this.boids);
172 | 
173 |   @override
174 |   void paint(Canvas canvas, Size size) {
175 |     final scale = size.shortestSide / kSize / 2;
176 |     canvas.translate(size.width / 4, size.height / 4);
177 |     canvas.scale(scale);
178 |     for (var boid in boids) {
179 |       canvas.save();
180 |       // canvas.drawCircle(boid.position, 1.0, Paint()..color = Colors.white);
181 |       DashPainter(boid.position).paint(canvas, size);
182 |       canvas.restore();
183 |     }
184 |   }
185 | 
186 |   @override
187 |   bool shouldRepaint(CustomPainter oldDelegate) {
188 |     return true;
189 |   }
190 | }
191 | 
192 | class Boid {
193 |   double x;
194 |   double y;
195 |   double dx;
196 |   double dy;
197 | 
198 |   Offset get position => Offset(x, y);
199 |   Offset get velocity => Offset(dx, dy);
200 | 
201 |   List history = [];
202 | 
203 |   Boid(this.x, this.y, this.dx, this.dy);
204 | 
205 |   bool operator ==(dynamic other) {
206 |     if (other is Boid) {
207 |       return other.x == this.x &&
208 |           other.y == this.y &&
209 |           other.dx == this.dx &&
210 |           other.dy == this.dy;
211 |     } else
212 |       return false;
213 |   }
214 | 
215 |   @override
216 |   int get hashCode => (x * y * dx * dy).toInt();
217 | }
218 | 
219 | class BoidSimulation extends ChangeNotifier {
220 |   BoidSimulation(this.vsync) {
221 |     initBoids();
222 |     _ticker = vsync.createTicker(_onEachTick)..start();
223 |   }
224 |   final TickerProvider vsync;
225 |   late Ticker _ticker;
226 |   double time = 0.0;
227 | 
228 |   double speedLimit = 5.0;
229 |   double visualRange = 40.0;
230 |   int numBoids = 100;
231 |   double turnFactor = 0.2;
232 | 
233 |   final double width = kSize;
234 |   final double height = kSize;
235 | 
236 |   final List boids = [];
237 | 
238 |   void _onEachTick(Duration deltaTime) {
239 |     final lastFrameTime = deltaTime.inMilliseconds.toDouble() / 1000.0;
240 |     time += lastFrameTime;
241 | 
242 |     for (var boid in boids) {
243 |       // Update the velocities according to each rule
244 |       _flyTowardsCenter(boid);
245 |       _avoidOthers(boid);
246 |       _matchVelocity(boid);
247 |       limitSpeed(boid);
248 |       _keepWithinBounds(boid);
249 | 
250 |       // Update the position based on the current velocity
251 |       boid.x += boid.dx;
252 |       boid.y += boid.dy;
253 |       boid.history.add(boid.position);
254 |       boid.history = boid.history.take(50).toList();
255 |     }
256 | 
257 |     notifyListeners();
258 |   }
259 | 
260 |   @override
261 |   void dispose() {
262 |     _ticker.dispose();
263 |     super.dispose();
264 |   }
265 | 
266 |   void initBoids([int init = 0]) {
267 |     for (var i = init; i < numBoids; i++) {
268 |       final x = math.Random().nextDouble() * width;
269 |       final y = math.Random().nextDouble() * height;
270 |       final dx = math.Random().nextDouble() * 10 - 5;
271 |       final dy = math.Random().nextDouble() * 10 - 5;
272 |       boids.add(Boid(x, y, dx, dy));
273 |     }
274 |   }
275 | 
276 |   void setBoidsNumber(int value) {
277 |     numBoids = value;
278 |     if (numBoids < boids.length) {
279 |       boids.removeRange(numBoids, boids.length);
280 |     } else {
281 |       initBoids(boids.length);
282 |     }
283 |   }
284 | 
285 |   double _distance(Boid boid1, Boid boid2) {
286 |     return math.sqrt(
287 |       (boid1.x - boid2.x) * (boid1.x - boid2.x) +
288 |           (boid1.y - boid2.y) * (boid1.y - boid2.y),
289 |     );
290 |   }
291 | 
292 |   /// Constrain a boid to within the window. If it gets too close to an edge,
293 |   /// nudge it back in and reverse its direction.
294 |   void _keepWithinBounds(Boid boid) {
295 |     const margin = 50;
296 | 
297 |     if (boid.x < width + margin) {
298 |       boid.dx += turnFactor;
299 |     }
300 |     if (boid.x > -margin) {
301 |       boid.dx -= turnFactor;
302 |     }
303 |     if (boid.y < height + margin) {
304 |       boid.dy += turnFactor;
305 |     }
306 |     if (boid.y > -margin) {
307 |       boid.dy -= turnFactor;
308 |     }
309 |   }
310 | 
311 |   /// Find the center of mass of the other boids and adjust velocity slightly to
312 |   /// point towards the center of mass.
313 |   void _flyTowardsCenter(Boid boid) {
314 |     const centeringFactor = 0.005; // adjust velocity by this %
315 | 
316 |     var centerX = 0.0;
317 |     var centerY = 0.0;
318 |     var numNeighbors = 0.0;
319 | 
320 |     for (var otherBoid in boids) {
321 |       if (_distance(boid, otherBoid) < visualRange) {
322 |         centerX += otherBoid.x;
323 |         centerY += otherBoid.y;
324 |         numNeighbors += 1;
325 |       }
326 |     }
327 | 
328 |     if (numNeighbors > 0.0) {
329 |       centerX = centerX / numNeighbors;
330 |       centerY = centerY / numNeighbors;
331 | 
332 |       boid.dx += (centerX - boid.x) * centeringFactor;
333 |       boid.dy += (centerY - boid.y) * centeringFactor;
334 |     }
335 |   }
336 | 
337 |   /// Move away from other boids that are too close to avoid colliding
338 |   void _avoidOthers(Boid boid) {
339 |     const minDistance = 10; // The distance to stay away from other boids
340 |     const avoidFactor = 0.01; // Adjust velocity by this %
341 |     var moveX = 0.0;
342 |     var moveY = 0.0;
343 |     for (var otherBoid in boids) {
344 |       if (otherBoid != boid) {
345 |         if (_distance(boid, otherBoid) < minDistance) {
346 |           moveX += boid.x - otherBoid.x;
347 |           moveY += boid.y - otherBoid.y;
348 |         }
349 |       }
350 |     }
351 | 
352 |     boid.dx += moveX * avoidFactor;
353 |     boid.dy += moveY * avoidFactor;
354 |   }
355 | 
356 |   /// Find the average velocity (speed and direction) of the other boids and
357 |   /// adjust velocity slightly to match.
358 |   void _matchVelocity(Boid boid) {
359 |     const matchingFactor = 0.05; // Adjust by this % of average velocity
360 | 
361 |     var avgDX = 0.0;
362 |     var avgDY = 0.0;
363 |     var numNeighbors = 0.0;
364 | 
365 |     for (var otherBoid in boids) {
366 |       if (_distance(boid, otherBoid) < visualRange) {
367 |         avgDX += otherBoid.dx;
368 |         avgDY += otherBoid.dy;
369 |         numNeighbors += 1;
370 |       }
371 |     }
372 | 
373 |     if (numNeighbors > 0.0) {
374 |       avgDX = avgDX / numNeighbors;
375 |       avgDY = avgDY / numNeighbors;
376 | 
377 |       boid.dx += (avgDX - boid.dx) * matchingFactor;
378 |       boid.dy += (avgDY - boid.dy) * matchingFactor;
379 |     }
380 |   }
381 | 
382 |   /// Speed will naturally vary in flocking behavior, but real animals can't go
383 |   /// arbitrarily fast.
384 |   void limitSpeed(boid) {
385 |     final speed = math.sqrt(boid.dx * boid.dx + boid.dy * boid.dy);
386 |     if (speed > speedLimit) {
387 |       boid.dx = (boid.dx / speed) * speedLimit;
388 |       boid.dy = (boid.dy / speed) * speedLimit;
389 |     }
390 |   }
391 | }
392 | 
393 | class DashPainter extends CustomPainter {
394 |   DashPainter(this.position);
395 | 
396 |   final Offset position;
397 | 
398 |   @override
399 |   void paint(Canvas canvas, Size size) {
400 |     final leftLeg = true;
401 |     final rightLeg = true;
402 | 
403 |     final body = Path()
404 |       ..addOval(
405 |         Rect.fromLTWH(
406 |           10,
407 |           10,
408 |           100,
409 |           100,
410 |         ),
411 |       );
412 |     final tail = Path()
413 |       ..moveTo(0, 20)
414 |       ..lineTo(40, 40)
415 |       ..lineTo(40, 80)
416 |       ..lineTo(0, 50);
417 |     final wing = Path()
418 |       ..moveTo(0, 40)
419 |       ..lineTo(45, 40)
420 |       ..relativeArcToPoint(Offset(0, 40), radius: Radius.circular(20))
421 |       ..lineTo(15, 80)
422 |       ..close();
423 |     final tip = Path()
424 |       ..moveTo(90, 50)
425 |       ..lineTo(140, 60)
426 |       ..lineTo(90, 60);
427 |     final eye = Path()..addOval(Rect.fromLTWH(80, 40, 10, 10));
428 |     final eyeWhite = Path()..addOval(Rect.fromLTWH(82.5, 42.5, 3, 3));
429 |     final top = Path()..addOval(Rect.fromLTWH(50, 6, 20, 10));
430 |     final legL = Path()
431 |       ..moveTo(50, 100)
432 |       ..lineTo(50, 130)
433 |       ..lineTo(52, 135)
434 |       ..lineTo(63, 135)
435 |       ..lineTo(58, 130)
436 |       ..lineTo(58, 100);
437 |     final legR = Path()
438 |       ..moveTo(68, 100)
439 |       ..lineTo(68, 130)
440 |       ..lineTo(70, 135)
441 |       ..lineTo(81, 135)
442 |       ..lineTo(76, 130)
443 |       ..lineTo(76, 100);
444 |     final faceWhite = Path()
445 |       ..moveTo(90, 50)
446 |       ..relativeArcToPoint(Offset(-0, 50),
447 |           radius: Radius.circular(15), clockwise: false)
448 |       ..lineTo(100, 90)
449 |       ..lineTo(110, 80);
450 |     canvas.translate(position.dx, position.dy);
451 |     canvas.scale(0.1);
452 |     if (leftLeg) canvas.drawPath(legL, Paint()..color = Colors.brown[400]!);
453 |     if (rightLeg) canvas.drawPath(legR, Paint()..color = Colors.brown[400]!);
454 |     canvas.drawPath(body, Paint()..color = Colors.blue[300]!);
455 |     canvas.drawPath(tail, Paint()..color = Colors.teal[400]!);
456 |     canvas.drawPath(faceWhite, Paint()..color = Colors.white.withOpacity(0.8));
457 |     canvas.drawPath(wing, Paint()..color = Colors.blue[500]!);
458 |     canvas.drawPath(tip, Paint()..color = Colors.brown[400]!);
459 |     canvas.drawPath(eye, Paint()..color = Colors.black);
460 |     canvas.drawPath(eyeWhite, Paint()..color = Colors.white);
461 |     canvas.drawPath(top, Paint()..color = Colors.blue[400]!);
462 |   }
463 | 
464 |   @override
465 |   bool shouldRepaint(covariant DashPainter oldDelegate) {
466 |     return position != oldDelegate.position;
467 |   }
468 | }
469 | 
--------------------------------------------------------------------------------
/lib/pages/explicit/avatar.dart:
--------------------------------------------------------------------------------
  1 | // Copyright 2021 Dominik Roszkowski
  2 | import 'package:flutter/material.dart';
  3 | 
  4 | class AvatarAnimation extends StatelessWidget {
  5 |   @override
  6 |   Widget build(BuildContext context) {
  7 |     final radius = 100.0;
  8 |     return Center(
  9 |       child: _AnimatedAvatarDecoration(
 10 |         child: CircleAvatar(
 11 |           backgroundImage: NetworkImage('https://picsum.photos/id/823/300'),
 12 |           backgroundColor: Colors.white,
 13 |           radius: radius,
 14 |         ),
 15 |         radius: radius,
 16 |       ),
 17 |     );
 18 |   }
 19 | }
 20 | 
 21 | /// Pulse decoration shown around the avatar
 22 | ///
 23 | /// It uses several animation controllers to show sequential
 24 | /// radiating circles around the avatar. As they extend from
 25 | /// the avatar their opacity decreases to 0.0.
 26 | class _AnimatedAvatarDecoration extends StatefulWidget {
 27 |   const _AnimatedAvatarDecoration({
 28 |     Key? key,
 29 |     required this.child,
 30 |     required this.radius,
 31 |   }) : super(key: key);
 32 | 
 33 |   final Widget child;
 34 |   final double radius;
 35 | 
 36 |   @override
 37 |   _AnimatedAvatarDecorationState createState() =>
 38 |       _AnimatedAvatarDecorationState();
 39 | }
 40 | 
 41 | class _AnimatedAvatarDecorationState extends State<_AnimatedAvatarDecoration>
 42 |     with TickerProviderStateMixin {
 43 |   AnimationController? animationController1;
 44 |   AnimationController? animationController2;
 45 |   AnimationController? animationController3;
 46 | 
 47 |   final radiatingTween = Tween(begin: 1.0, end: 0.0);
 48 | 
 49 |   @override
 50 |   void initState() {
 51 |     super.initState();
 52 |     animationController1 = AnimationController(
 53 |       vsync: this,
 54 |       duration: _kRadiatingAnimationDuration,
 55 |       debugLabel: 'animated_avatar_decoration1',
 56 |     )
 57 |       ..forward()
 58 |       ..repeat();
 59 |     animationController2 = AnimationController(
 60 |       vsync: this,
 61 |       duration: _kRadiatingAnimationDuration,
 62 |       debugLabel: 'animated_avatar_decoration2',
 63 |     )
 64 |       ..forward(from: 1 / 3)
 65 |       ..repeat();
 66 |     animationController3 = AnimationController(
 67 |       vsync: this,
 68 |       duration: _kRadiatingAnimationDuration,
 69 |       debugLabel: 'animated_avatar_decoration3',
 70 |     )
 71 |       ..forward(from: 2 / 3)
 72 |       ..repeat();
 73 |   }
 74 | 
 75 |   @override
 76 |   void dispose() {
 77 |     animationController1?.dispose();
 78 |     animationController2?.dispose();
 79 |     animationController3?.dispose();
 80 |     super.dispose();
 81 |   }
 82 | 
 83 |   @override
 84 |   Widget build(BuildContext context) {
 85 |     return AnimatedBuilder(
 86 |       animation: animationController1!,
 87 |       builder: (context, child) {
 88 |         final _padding = widget.radius * 0.75;
 89 |         final anim1 = radiatingTween.animate(animationController1!);
 90 |         final anim2 = radiatingTween.animate(animationController2!);
 91 |         final anim3 = radiatingTween.animate(animationController3!);
 92 | 
 93 |         return Center(
 94 |           child: Stack(
 95 |             children: [
 96 |               _RadiatingCircle(
 97 |                 padding: _padding,
 98 |                 anim1: anim1,
 99 |                 key: const Key('animated_avatar_decoration1'),
100 |               ),
101 |               _RadiatingCircle(
102 |                 padding: _padding,
103 |                 anim1: anim2,
104 |                 key: const Key('animated_avatar_decoration2'),
105 |               ),
106 |               _RadiatingCircle(
107 |                 padding: _padding,
108 |                 anim1: anim3,
109 |                 key: const Key('animated_avatar_decoration3'),
110 |               ),
111 |               Padding(
112 |                 padding: EdgeInsets.all(_padding),
113 |                 child: child,
114 |               ),
115 |             ],
116 |           ),
117 |         );
118 |       },
119 |       child: DecoratedBox(
120 |         decoration: const ShapeDecoration(
121 |           shape: CircleBorder(),
122 |           shadows: [
123 |             BoxShadow(
124 |               color: Color(0x8008212D),
125 |               blurRadius: 28,
126 |               offset: Offset(4, 4),
127 |             ),
128 |           ],
129 |         ),
130 |         child: widget.child,
131 |       ),
132 |     );
133 |   }
134 | }
135 | 
136 | const _kRadiatingAnimationDuration = Duration(milliseconds: 3500);
137 | const _kOpacityFraction = 1 / 5;
138 | 
139 | class _RadiatingCircle extends StatelessWidget {
140 |   const _RadiatingCircle({
141 |     Key? key,
142 |     required this.padding,
143 |     required this.anim1,
144 |   }) : super(key: key);
145 | 
146 |   final double padding;
147 |   final Animation anim1;
148 |   final baseColor = Colors.white10;
149 | 
150 |   @override
151 |   Widget build(BuildContext context) {
152 |     return Positioned.fill(
153 |       child: Padding(
154 |         padding: EdgeInsets.all(padding * anim1.value),
155 |         child: DecoratedBox(
156 |           decoration: ShapeDecoration(
157 |             shape: const CircleBorder(),
158 |             color: baseColor.withOpacity(anim1.value * _kOpacityFraction),
159 |           ),
160 |         ),
161 |       ),
162 |     );
163 |   }
164 | }
165 | 
--------------------------------------------------------------------------------
/lib/pages/explicit/dots.dart:
--------------------------------------------------------------------------------
  1 | // Copyright (c) 2021 Dominik Roszkowski on the MIT license
  2 | import 'dart:async';
  3 | 
  4 | import 'package:flutter/material.dart';
  5 | 
  6 | const _numberOfElements = 5;
  7 | const _duration = Duration(milliseconds: 350);
  8 | 
  9 | class DotsLoader extends StatefulWidget {
 10 |   const DotsLoader({
 11 |     Key? key,
 12 |     this.size = 20.0,
 13 |   })  : assert(size > 0),
 14 |         super(key: key);
 15 | 
 16 |   /// Size of the largest dot
 17 |   final double size;
 18 | 
 19 |   @override
 20 |   _DotsLoaderState createState() => _DotsLoaderState();
 21 | }
 22 | 
 23 | class _DotsLoaderState extends State {
 24 |   Timer? timer;
 25 |   int index = 0;
 26 | 
 27 |   @override
 28 |   void initState() {
 29 |     super.initState();
 30 | 
 31 |     timer = Timer.periodic(
 32 |       _duration,
 33 |       _incrementIndex,
 34 |     );
 35 |   }
 36 | 
 37 |   void _incrementIndex(timer) {
 38 |     setState(() {
 39 |       index = (index + 1) % (_numberOfElements + 1);
 40 |     });
 41 |   }
 42 | 
 43 |   @override
 44 |   void dispose() {
 45 |     timer?.cancel();
 46 |     super.dispose();
 47 |   }
 48 | 
 49 |   @override
 50 |   Widget build(BuildContext context) {
 51 |     return Row(
 52 |       mainAxisAlignment: MainAxisAlignment.center,
 53 |       mainAxisSize: MainAxisSize.min,
 54 |       children: [
 55 |         for (final i in List.generate(_numberOfElements, (i) => i))
 56 |           _Dot(
 57 |             size: widget.size,
 58 |             currentIndex: index,
 59 |             elementIndex: i,
 60 |           )
 61 |       ],
 62 |     );
 63 |   }
 64 | }
 65 | 
 66 | class _Dot extends StatelessWidget {
 67 |   const _Dot({
 68 |     Key? key,
 69 |     this.size,
 70 |     this.currentIndex,
 71 |     this.elementIndex,
 72 |   }) : super(key: key);
 73 | 
 74 |   final double? size;
 75 |   final int? currentIndex;
 76 |   final int? elementIndex;
 77 | 
 78 |   /// Return default size for the main element (index == elementIndex)
 79 |   ///
 80 |   /// Return 3/4 of the default size for the 2 neighbouring elements
 81 |   ///
 82 |   /// Return 1/2 of the default size for the other elements
 83 |   double getFraction() {
 84 |     if (currentIndex == elementIndex) {
 85 |       return 1.0;
 86 |     }
 87 |     final absoluteIndex = (currentIndex! - elementIndex!).abs();
 88 |     final isNeighbourToMainPoint = absoluteIndex == 1;
 89 |     if (isNeighbourToMainPoint) {
 90 |       return 0.75;
 91 |     }
 92 |     return 0.5;
 93 |   }
 94 | 
 95 |   @override
 96 |   Widget build(BuildContext context) {
 97 |     final fraction = getFraction();
 98 |     return SizedBox(
 99 |       height: size! + 4,
100 |       width: size! + 4,
101 |       child: Center(
102 |         child: AnimatedContainer(
103 |           duration: _duration,
104 |           decoration: ShapeDecoration(
105 |             color: Colors.white.withOpacity(fraction),
106 |             shape: const CircleBorder(),
107 |           ),
108 |           height: fraction * size!,
109 |           width: fraction * size!,
110 |         ),
111 |       ),
112 |     );
113 |   }
114 | }
115 | 
--------------------------------------------------------------------------------
/lib/pages/explicit/explicit.dart:
--------------------------------------------------------------------------------
1 | export 'avatar.dart';
2 | export 'dots.dart';
3 | export 'flutter.dart';
4 | export 'icon.dart';
5 | export 'slack.dart';
6 | 
--------------------------------------------------------------------------------
/lib/pages/explicit/icon.dart:
--------------------------------------------------------------------------------
 1 | import 'package:flutter/material.dart';
 2 | 
 3 | class AnimatedRadiatingIcon extends StatefulWidget {
 4 |   @override
 5 |   _AnimatedRadiatingIconState createState() => _AnimatedRadiatingIconState();
 6 | }
 7 | 
 8 | class _AnimatedRadiatingIconState extends State
 9 |     with TickerProviderStateMixin {
10 |   late AnimationController animationController;
11 | 
12 |   @override
13 |   void initState() {
14 |     super.initState();
15 |     animationController = AnimationController(
16 |       vsync: this,
17 |       duration: Duration(seconds: 1),
18 |     )
19 |       ..forward()
20 |       ..repeat(reverse: true);
21 |   }
22 | 
23 |   @override
24 |   void dispose() {
25 |     animationController.dispose();
26 |     super.dispose();
27 |   }
28 | 
29 |   @override
30 |   Widget build(BuildContext context) {
31 |     return ColoredBox(
32 |       color: Colors.blue,
33 |       child: Center(
34 |         child: AnimatedBuilder(
35 |           animation: animationController,
36 |           builder: (context, child) {
37 |             return Container(
38 |               decoration: ShapeDecoration(
39 |                 color: Colors.white.withOpacity(0.5),
40 |                 shape: CircleBorder(),
41 |               ),
42 |               child: Padding(
43 |                 padding: EdgeInsets.all(8.0 * animationController.value),
44 |                 child: child,
45 |               ),
46 |             );
47 |           },
48 |           child: DecoratedBox(
49 |             decoration: ShapeDecoration(
50 |               color: Colors.white,
51 |               shape: CircleBorder(),
52 |             ),
53 |             child: IconButton(
54 |               onPressed: () {},
55 |               color: Colors.blue,
56 |               icon: Icon(Icons.calendar_today, size: 24),
57 |             ),
58 |           ),
59 |         ),
60 |       ),
61 |     );
62 |   }
63 | }
64 | 
--------------------------------------------------------------------------------
/lib/pages/explicit/slack.dart:
--------------------------------------------------------------------------------
  1 | import 'dart:math' as math;
  2 | import 'package:flutter/material.dart';
  3 | 
  4 | class SlackLogo extends StatefulWidget {
  5 |   SlackLogo({Key? key, this.title}) : super(key: key);
  6 | 
  7 |   final String? title;
  8 | 
  9 |   @override
 10 |   _SlackLogoState createState() => _SlackLogoState();
 11 | }
 12 | 
 13 | class _SlackLogoState extends State with TickerProviderStateMixin {
 14 |   AnimationController? animationController;
 15 | 
 16 |   @override
 17 |   void initState() {
 18 |     super.initState();
 19 |     animationController = AnimationController(
 20 |       duration: Duration(seconds: 3),
 21 |       vsync: this,
 22 |       lowerBound: 0.0,
 23 |       upperBound: 1.0,
 24 |     )
 25 |       ..forward()
 26 |       ..repeat(reverse: true);
 27 |   }
 28 | 
 29 |   @override
 30 |   void dispose() {
 31 |     animationController?.dispose();
 32 |     super.dispose();
 33 |   }
 34 | 
 35 |   @override
 36 |   Widget build(BuildContext context) {
 37 |     final size = MediaQuery.of(context).size;
 38 |     final width = size.shortestSide / 2;
 39 |     return ClipRect(
 40 |       child: Scaffold(
 41 |         body: Center(
 42 |           child: Container(
 43 |             height: width,
 44 |             width: width,
 45 |             child: AnimatedBuilder(
 46 |               animation: animationController!,
 47 |               builder: (context, anim) {
 48 |                 final scale = Tween(begin: 1.0, end: 0.5).animate(
 49 |                   CurvedAnimation(
 50 |                     parent: animationController!,
 51 |                     curve: Interval(
 52 |                       0.3,
 53 |                       0.8,
 54 |                       curve: Curves.easeOut,
 55 |                     ),
 56 |                   ),
 57 |                 );
 58 |                 final oneToZero = Tween(begin: 1.0, end: 0.0).animate(
 59 |                   CurvedAnimation(
 60 |                     parent: animationController!,
 61 |                     curve: Interval(
 62 |                       0.1,
 63 |                       0.6,
 64 |                       curve: Curves.easeOutCubic,
 65 |                     ),
 66 |                   ),
 67 |                 );
 68 |                 final oneToZeroTwo =
 69 |                     Tween(begin: 1.0, end: 0.19).animate(
 70 |                   CurvedAnimation(
 71 |                     parent: animationController!,
 72 |                     curve: Interval(
 73 |                       0.1,
 74 |                       0.7,
 75 |                       curve: Curves.easeOutCubic,
 76 |                     ),
 77 |                   ),
 78 |                 );
 79 | 
 80 |                 final zeroToOne = Tween(begin: 0.0, end: 1.0).animate(
 81 |                   CurvedAnimation(
 82 |                     parent: animationController!,
 83 |                     curve: Interval(
 84 |                       0.1,
 85 |                       0.7,
 86 |                       curve: Curves.easeOutCubic,
 87 |                     ),
 88 |                   ),
 89 |                 );
 90 | 
 91 |                 final rotation =
 92 |                     Tween(begin: 0.0, end: math.pi).animate(
 93 |                   CurvedAnimation(
 94 |                     parent: animationController!,
 95 |                     curve: Interval(
 96 |                       0.1,
 97 |                       0.7,
 98 |                       curve: Curves.easeOutCubic,
 99 |                     ),
100 |                   ),
101 |                 );
102 | 
103 |                 return LogoStack(
104 |                   width,
105 |                   scale.value,
106 |                   oneToZero.value,
107 |                   zeroToOne.value,
108 |                   oneToZeroTwo.value,
109 |                   rotation.value,
110 |                 );
111 |               },
112 |             ),
113 |           ),
114 |         ),
115 |       ),
116 |     );
117 |   }
118 | }
119 | 
120 | class LogoStack extends StatelessWidget {
121 |   const LogoStack(
122 |     this.size,
123 |     this.scale,
124 |     this.oneToZero,
125 |     this.zeroToOne,
126 |     this.oneToZeroTwo,
127 |     this.rotation, {
128 |     Key? key,
129 |   }) : super(key: key);
130 | 
131 |   final double size;
132 |   final double scale;
133 |   final double oneToZero;
134 |   final double zeroToOne;
135 |   final double oneToZeroTwo;
136 |   final double rotation;
137 | 
138 |   @override
139 |   Widget build(BuildContext context) {
140 |     final width = 0.2 * size;
141 |     final elementSpacing = 0.025 * size;
142 |     // green blobs as reference
143 |     final smallXaxis =
144 |         (width / 2 + elementSpacing + width + 0.05 * size) * oneToZero;
145 |     final smallYaxis = (-width / 2 - elementSpacing) * oneToZero;
146 | 
147 |     final largeXaxis = (width / 2 + elementSpacing) * oneToZero;
148 |     final largeYaxis = -0.25 * size * oneToZero;
149 | 
150 |     // final clipSize = size / 2 * oneToZeroTwo;
151 |     final yellowRadius = zeroToOne * width / 2;
152 | 
153 |     return Transform.scale(
154 |       scale: scale,
155 |       child: Transform.rotate(
156 |         angle: rotation,
157 |         child: Stack(
158 |           children: [
159 |             Center(
160 |               child: Transform.translate(
161 |                 offset: Offset(
162 |                   largeXaxis,
163 |                   largeYaxis,
164 |                 ),
165 |                 child: LargeBlob(
166 |                   width: width,
167 |                   color: SColors.green,
168 |                   scale: zeroToOne,
169 |                 ),
170 |               ),
171 |             ),
172 |             Center(
173 |               child: Transform.translate(
174 |                 offset: Offset(
175 |                   smallXaxis,
176 |                   smallYaxis,
177 |                 ),
178 |                 child: SmallBlob(
179 |                   width: width,
180 |                   color: SColors.green,
181 |                   turns: 0,
182 |                   radius: yellowRadius,
183 |                 ),
184 |               ),
185 |             ),
186 |             Center(
187 |               child: Transform.translate(
188 |                 offset: Offset(
189 |                   largeYaxis,
190 |                   -largeXaxis,
191 |                 ),
192 |                 child: RotatedBox(
193 |                   quarterTurns: 1,
194 |                   child: LargeBlob(
195 |                     width: width,
196 |                     color: SColors.blue,
197 |                     scale: zeroToOne,
198 |                   ),
199 |                 ),
200 |               ),
201 |             ),
202 |             Center(
203 |               child: Transform.translate(
204 |                 offset: Offset(
205 |                   smallYaxis,
206 |                   -smallXaxis,
207 |                 ),
208 |                 child: SmallBlob(
209 |                   width: width,
210 |                   color: SColors.blue,
211 |                   turns: 3,
212 |                   radius: yellowRadius,
213 |                 ),
214 |               ),
215 |             ),
216 |             Center(
217 |               child: Transform.translate(
218 |                 offset: Offset(
219 |                   -largeXaxis,
220 |                   -largeYaxis,
221 |                 ),
222 |                 child: LargeBlob(
223 |                   width: width,
224 |                   color: SColors.red,
225 |                   scale: zeroToOne,
226 |                 ),
227 |               ),
228 |             ),
229 |             Center(
230 |               child: Transform.translate(
231 |                 offset: Offset(
232 |                   -smallXaxis,
233 |                   -smallYaxis,
234 |                 ),
235 |                 child: SmallBlob(
236 |                   width: width,
237 |                   color: SColors.red,
238 |                   turns: 2,
239 |                   radius: yellowRadius,
240 |                 ),
241 |               ),
242 |             ),
243 |             Center(
244 |               child: Transform.translate(
245 |                 offset: Offset(
246 |                   -largeYaxis,
247 |                   largeXaxis,
248 |                 ),
249 |                 child: RotatedBox(
250 |                   quarterTurns: 1,
251 |                   child: LargeBlob(
252 |                     width: width,
253 |                     color: SColors.yellow,
254 |                     scale: zeroToOne,
255 |                   ),
256 |                 ),
257 |               ),
258 |             ),
259 |             Center(
260 |               child: Transform.translate(
261 |                 offset: Offset(
262 |                   -smallYaxis,
263 |                   smallXaxis,
264 |                 ),
265 |                 child: SmallBlob(
266 |                   width: width,
267 |                   color: SColors.yellow,
268 |                   turns: 1,
269 |                   radius: yellowRadius,
270 |                 ),
271 |               ),
272 |             ),
273 |           ],
274 |         ),
275 |       ),
276 |     );
277 |   }
278 | }
279 | 
280 | class SmallBlob extends StatelessWidget {
281 |   const SmallBlob({
282 |     Key? key,
283 |     required this.width,
284 |     required this.color,
285 |     required this.turns,
286 |     required this.radius,
287 |   }) : super(key: key);
288 | 
289 |   final double width;
290 |   final Color color;
291 |   final int turns;
292 |   final double radius;
293 | 
294 |   @override
295 |   Widget build(BuildContext context) {
296 |     return RotatedBox(
297 |       quarterTurns: turns,
298 |       child: Container(
299 |         width: width,
300 |         child: AspectRatio(
301 |           aspectRatio: 1,
302 |           child: Container(
303 |             decoration: BoxDecoration(
304 |               color: color,
305 |               borderRadius: BorderRadius.only(
306 |                 topLeft: Radius.circular(width / 2),
307 |                 topRight: Radius.circular(width / 2),
308 |                 bottomRight: Radius.circular(width / 2),
309 |                 bottomLeft: Radius.circular(radius),
310 |               ),
311 |             ),
312 |           ),
313 |         ),
314 |       ),
315 |     );
316 |   }
317 | }
318 | 
319 | class LargeBlob extends StatelessWidget {
320 |   const LargeBlob({
321 |     Key? key,
322 |     required this.width,
323 |     required this.color,
324 |     required this.scale,
325 |   }) : super(key: key);
326 | 
327 |   final double width;
328 |   final double scale;
329 |   final Color color;
330 | 
331 |   @override
332 |   Widget build(BuildContext context) {
333 |     return Container(
334 |       width: width,
335 |       height: width / (0.45 + scale * 0.55),
336 |       decoration: ShapeDecoration(
337 |         color: color,
338 |         shape: StadiumBorder(),
339 |       ),
340 |     );
341 |   }
342 | }
343 | 
344 | class SColors {
345 |   static const Color red = Color(0xFFE01E5A);
346 |   static const Color blue = Color(0xFF36C5F0);
347 |   static const Color yellow = Color(0xFFECB22E);
348 |   static const Color green = Color(0xFF2EB67D);
349 | }
350 | 
351 | class DecreasingCircleClipper extends CustomClipper {
352 |   final double radius;
353 | 
354 |   DecreasingCircleClipper(this.radius);
355 |   @override
356 |   Path getClip(Size size) {
357 |     final path = Path();
358 |     final oval = Rect.fromCircle(
359 |       center: Offset(
360 |         size.width / 2,
361 |         size.height / 2,
362 |       ),
363 |       radius: radius,
364 |     );
365 |     path.addOval(oval);
366 |     path.close();
367 |     return path;
368 |   }
369 | 
370 |   @override
371 |   bool shouldReclip(DecreasingCircleClipper oldClipper) => true;
372 | }
373 | 
--------------------------------------------------------------------------------
/lib/pages/explicit_animations.dart:
--------------------------------------------------------------------------------
 1 | import 'package:flutter/material.dart';
 2 | 
 3 | import 'explicit/explicit.dart';
 4 | 
 5 | class ExplicitAnimations extends StatelessWidget {
 6 |   @override
 7 |   Widget build(BuildContext context) {
 8 |     return ColoredBox(
 9 |       color: Colors.blue,
10 |       child: GridView.count(
11 |         crossAxisCount: 2,
12 |         children: [
13 |           AvatarAnimation(),
14 |           LogoWrapper(),
15 |           SlackLogo(),
16 |           DotsLoader(),
17 |           AnimatedRadiatingIcon(),
18 |         ],
19 |       ),
20 |     );
21 |   }
22 | }
23 | 
24 | class LogoWrapper extends StatelessWidget {
25 |   const LogoWrapper({
26 |     Key? key,
27 |   }) : super(key: key);
28 | 
29 |   @override
30 |   Widget build(BuildContext context) {
31 |     return LayoutBuilder(builder: (context, size) {
32 |       return ClipRect(
33 |         child: ColoredBox(
34 |           color: Colors.white,
35 |           child: FlutterAnimatedLogo(size: size.biggest.width),
36 |         ),
37 |       );
38 |     });
39 |   }
40 | }
41 | 
--------------------------------------------------------------------------------
/lib/pages/funvas.dart:
--------------------------------------------------------------------------------
 1 | import 'package:flutter/material.dart';
 2 | import 'package:funvas/funvas.dart';
 3 | import 'package:url_launcher/url_launcher.dart';
 4 | 
 5 | class FunvasDemo extends StatelessWidget {
 6 |   @override
 7 |   Widget build(BuildContext context) {
 8 |     final funvas = 'https://github.com/creativecreatorormaybenot/funvas';
 9 |     return Column(
10 |       children: [
11 |         Expanded(
12 |           child: AspectRatio(
13 |             aspectRatio: 1,
14 |             child: FunvasContainer(
15 |               funvas: OrbsFunvas(),
16 |             ),
17 |           ),
18 |         ),
19 |         Padding(
20 |           padding: const EdgeInsets.all(16.0),
21 |           child: InkWell(
22 |             onTap: () async {
23 |               if (await canLaunch(funvas)) {
24 |                 launch(funvas);
25 |               }
26 |             },
27 |             child: Text(funvas),
28 |           ),
29 |         ),
30 |       ],
31 |     );
32 |   }
33 | }
34 | 
35 | class OrbsFunvas extends Funvas {
36 |   @override
37 |   void u(double t) {
38 |     c.scale(x.width / 1920, x.height / 1080);
39 | 
40 |     final v = t + 400;
41 |     for (var q = 255; q > 0; q--) {
42 |       final paint = Paint()..color = R(q, q, q);
43 |       c.drawCircle(
44 |           Offset(
45 |             1920 / 2 + C(v - q) * (v + q),
46 |             540 + S(v - q) * (v - q),
47 |           ),
48 |           40,
49 |           paint);
50 |     }
51 |   }
52 | }
53 | 
--------------------------------------------------------------------------------
/lib/pages/gravity_simulation.dart:
--------------------------------------------------------------------------------
  1 | import 'package:flutter/material.dart';
  2 | import 'package:flutter/physics.dart';
  3 | 
  4 | class GravitySimulationWidget extends StatefulWidget {
  5 |   _GravitySimulationWidget createState() => _GravitySimulationWidget();
  6 | }
  7 | 
  8 | class _GravitySimulationWidget extends State
  9 |     with TickerProviderStateMixin {
 10 |   late BallGame game;
 11 |   @override
 12 |   void initState() {
 13 |     super.initState();
 14 |     game = BallGame(
 15 |       this,
 16 |       bounceFactor: 0.7,
 17 |     );
 18 |   }
 19 | 
 20 |   @override
 21 |   Widget build(BuildContext context) {
 22 |     return Padding(
 23 |       padding: const EdgeInsets.only(
 24 |         bottom: 16.0,
 25 |         top: 64.0,
 26 |       ),
 27 |       child: AnimatedBuilder(
 28 |         animation: game,
 29 |         builder: (context, child) {
 30 |           return CustomPaint(
 31 |             painter: BallPainter(game.yPosition),
 32 |             child: SizedBox.expand(
 33 |               child: Align(
 34 |                 alignment: Alignment.bottomRight,
 35 |                 child: ElevatedButton(
 36 |                   onPressed: () => game.start(),
 37 |                   child: Text('Drop The Ball'),
 38 |                 ),
 39 |               ),
 40 |             ),
 41 |           );
 42 |         },
 43 |       ),
 44 |     );
 45 |   }
 46 | 
 47 |   @override
 48 |   void dispose() {
 49 |     game.dispose();
 50 |     super.dispose();
 51 |   }
 52 | }
 53 | 
 54 | const acc = 9.81;
 55 | const scaleFactor = 10;
 56 | 
 57 | class BallGame extends ChangeNotifier {
 58 |   BallGame(
 59 |     this.vsync, {
 60 |     this.bounceFactor = 0.7,
 61 |   });
 62 | 
 63 |   AnimationController? controller;
 64 |   late GravitySimulation simulation;
 65 | 
 66 |   double get yPosition => controller?.value ?? _position;
 67 |   double _position = 0.0;
 68 |   double _velocity = 0.0;
 69 |   final TickerProvider vsync;
 70 |   final double bounceFactor;
 71 | 
 72 |   void onTick() {
 73 |     final currentVelocity = simulation.dx(controller!.velocity);
 74 |     _position = controller!.value;
 75 |     if (controller!.isCompleted) {
 76 |       simulation = GravitySimulation(
 77 |         acc,
 78 |         9.999, // must be different than the target value
 79 |         10,
 80 |         -_velocity * bounceFactor / scaleFactor,
 81 |       );
 82 |       stop();
 83 |       if (_velocity.abs() > 1) {
 84 |         bounce();
 85 |       }
 86 |     }
 87 |     _velocity = currentVelocity;
 88 |     notifyListeners();
 89 |   }
 90 | 
 91 |   void bounce() {
 92 |     controller = AnimationController(
 93 |       vsync: vsync,
 94 |       upperBound: 1500,
 95 |     );
 96 |     controller!.addListener(onTick);
 97 |     controller!.animateWith(simulation);
 98 |   }
 99 | 
100 |   void start() {
101 |     controller = AnimationController(
102 |       vsync: vsync,
103 |       upperBound: 1500,
104 |     );
105 |     simulation = GravitySimulation(
106 |       acc,
107 |       0,
108 |       10,
109 |       0,
110 |     );
111 |     bounce();
112 |   }
113 | 
114 |   void stop() {
115 |     controller?.dispose();
116 |     controller = null;
117 |   }
118 | 
119 |   @override
120 |   void dispose() {
121 |     super.dispose();
122 |     controller?.dispose();
123 |   }
124 | }
125 | 
126 | class BallPainter extends CustomPainter {
127 |   BallPainter(this.yPosition);
128 | 
129 |   final double yPosition;
130 | 
131 |   @override
132 |   void paint(Canvas canvas, Size size) {
133 |     final verticalUnit = size.height / scaleFactor;
134 | 
135 |     drawTicks(size, verticalUnit, canvas);
136 |     canvas.drawOval(
137 |       Rect.fromCenter(
138 |         center: Offset(
139 |           size.center(Offset.zero).dx,
140 |           yPosition * verticalUnit - 25,
141 |         ),
142 |         width: 50,
143 |         height: 50,
144 |       ),
145 |       Paint(),
146 |     );
147 |   }
148 | 
149 |   void drawTicks(Size size, double verticalUnit, Canvas canvas) {
150 |     for (final i in [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) {
151 |       final yPos = size.height - i * verticalUnit;
152 |       canvas.drawLine(
153 |         Offset(0, yPos),
154 |         Offset(20, yPos),
155 |         Paint()..color = Colors.black,
156 |       );
157 |       final TextPainter textPainter = TextPainter(
158 |         text: TextSpan(
159 |           text: i.toString(),
160 |           style: TextStyle(
161 |             color: Colors.black,
162 |             fontSize: 12,
163 |           ),
164 |         ),
165 |         textAlign: TextAlign.end,
166 |         textDirection: TextDirection.ltr,
167 |       )..layout(minWidth: 20);
168 |       textPainter.paint(canvas, Offset(0, yPos - 16));
169 |     }
170 |     canvas.drawLine(
171 |       Offset(0, size.height),
172 |       Offset(size.width, size.height),
173 |       Paint()..color = Colors.black,
174 |     );
175 |   }
176 | 
177 |   @override
178 |   bool shouldRepaint(covariant BallPainter oldDelegate) {
179 |     return yPosition != oldDelegate.yPosition;
180 |   }
181 | }
182 | 
--------------------------------------------------------------------------------
/lib/pages/helpers/staggered_animations_widgets.dart:
--------------------------------------------------------------------------------
  1 | part of '../staggered_animations.dart';
  2 | 
  3 | class _Row3 extends StatelessWidget {
  4 |   const _Row3({
  5 |     Key? key,
  6 |   }) : super(key: key);
  7 | 
  8 |   @override
  9 |   Widget build(BuildContext context) {
 10 |     final children = [
 11 |       Flexible(
 12 |         child: SmartCard(
 13 |           child: Column(
 14 |             crossAxisAlignment: CrossAxisAlignment.start,
 15 |             children: [
 16 |               Text(
 17 |                 'Parking',
 18 |                 style: Theme.of(context).textTheme.headline5,
 19 |               ),
 20 |               const Gap(16),
 21 |               _Indicator(),
 22 |               const Gap(16),
 23 |               const Center(
 24 |                 child: Icon(
 25 |                   LineIcons.car,
 26 |                   size: 48,
 27 |                 ),
 28 |               )
 29 |             ],
 30 |           ),
 31 |         ),
 32 |       ),
 33 |       Flexible(
 34 |         child: SmartCard(
 35 |           child: Column(
 36 |             crossAxisAlignment: CrossAxisAlignment.start,
 37 |             children: [
 38 |               Text(
 39 |                 'Kitchen',
 40 |                 style: Theme.of(context).textTheme.headline5,
 41 |               ),
 42 |               const Gap(16),
 43 |               _Indicator(),
 44 |               const Gap(16),
 45 |               const Center(
 46 |                 child: Icon(
 47 |                   LineIcons.cookie,
 48 |                   size: 48,
 49 |                 ),
 50 |               )
 51 |             ],
 52 |           ),
 53 |         ),
 54 |       ),
 55 |     ];
 56 | 
 57 |     return LayoutBuilder(
 58 |       builder: (context, size) {
 59 |         if (size.maxWidth > 600) {
 60 |           return Row(
 61 |             mainAxisAlignment: MainAxisAlignment.spaceBetween,
 62 |             children: children,
 63 |           );
 64 |         } else {
 65 |           return Column(
 66 |             mainAxisSize: MainAxisSize.min,
 67 |             children: children,
 68 |           );
 69 |         }
 70 |       },
 71 |     );
 72 |   }
 73 | }
 74 | 
 75 | class _Row2 extends StatelessWidget {
 76 |   const _Row2({
 77 |     Key? key,
 78 |   }) : super(key: key);
 79 | 
 80 |   @override
 81 |   Widget build(BuildContext context) {
 82 |     final children = [
 83 |       Flexible(
 84 |         // constraints: BoxConstraints(maxWidth: 500),
 85 |         child: SmartCard(
 86 |           child: Column(
 87 |             crossAxisAlignment: CrossAxisAlignment.start,
 88 |             children: [
 89 |               Text(
 90 |                 'Living Room',
 91 |                 style: Theme.of(context).textTheme.headline5,
 92 |               ),
 93 |               const Gap(16),
 94 |               _Indicator(),
 95 |               const Gap(16),
 96 |               SizedBox(
 97 |                 height: 64,
 98 |                 child: LineChart(
 99 |                   sampleData(),
100 |                 ),
101 |               ),
102 |             ],
103 |           ),
104 |         ),
105 |       ),
106 |       Flexible(
107 |         // constraints: BoxConstraints(maxWidth: 500),
108 |         child: SmartCard(
109 |           child: Column(
110 |             crossAxisAlignment: CrossAxisAlignment.start,
111 |             children: [
112 |               Text(
113 |                 'Bedroom',
114 |                 style: Theme.of(context).textTheme.headline5,
115 |               ),
116 |               const Gap(16),
117 |               _Indicator(),
118 |               const Gap(16),
119 |               SizedBox(
120 |                 height: 64,
121 |                 child: LineChart(
122 |                   sampleData(),
123 |                 ),
124 |               ),
125 |             ],
126 |           ),
127 |         ),
128 |       ),
129 |     ];
130 |     return LayoutBuilder(
131 |       builder: (context, size) {
132 |         if (size.maxWidth > 600) {
133 |           return Row(
134 |             mainAxisAlignment: MainAxisAlignment.spaceBetween,
135 |             children: children,
136 |           );
137 |         } else {
138 |           return Column(
139 |             mainAxisSize: MainAxisSize.min,
140 |             children: children,
141 |           );
142 |         }
143 |       },
144 |     );
145 |   }
146 | }
147 | 
148 | class _Row1 extends StatelessWidget {
149 |   const _Row1({
150 |     Key? key,
151 |   }) : super(key: key);
152 | 
153 |   @override
154 |   Widget build(BuildContext context) {
155 |     return Row(
156 |       children: [
157 |         Expanded(
158 |           child: SmartCard(
159 |             child: Column(
160 |               crossAxisAlignment: CrossAxisAlignment.start,
161 |               children: [
162 |                 Text(
163 |                   'Family Room',
164 |                   style: Theme.of(context).textTheme.headline5,
165 |                 ),
166 |                 Gap(16),
167 |                 OverflowBar(
168 |                   spacing: 16,
169 |                   children: [
170 |                     _Indicator(),
171 |                     Gap(16),
172 |                     _Indicator(),
173 |                   ],
174 |                 ),
175 |                 Gap(16),
176 |                 OverflowBar(
177 |                   spacing: 16,
178 |                   children: [
179 |                     _Indicator(),
180 |                     Gap(16),
181 |                     _Indicator(),
182 |                   ],
183 |                 ),
184 |               ],
185 |             ),
186 |           ),
187 |         ),
188 |       ],
189 |     );
190 |   }
191 | }
192 | 
193 | class _Header extends StatelessWidget {
194 |   const _Header({
195 |     Key? key,
196 |   }) : super(key: key);
197 | 
198 |   @override
199 |   Widget build(BuildContext context) {
200 |     return Padding(
201 |       padding: const EdgeInsets.symmetric(horizontal: 48.0),
202 |       child: Row(
203 |         children: [
204 |           const CircleAvatar(
205 |             child: Text('JS'),
206 |           ),
207 |           Gap(16),
208 |           Text(
209 |             'John Smith',
210 |             style: Theme.of(context).textTheme.headline5,
211 |           ),
212 |         ],
213 |       ),
214 |     );
215 |   }
216 | }
217 | 
218 | class _Indicator extends StatelessWidget {
219 |   const _Indicator({
220 |     Key? key,
221 |   }) : super(key: key);
222 | 
223 |   @override
224 |   Widget build(BuildContext context) {
225 |     return Row(
226 |       mainAxisSize: MainAxisSize.min,
227 |       children: [
228 |         const Icon(LineIcons.batteryAlt2Full),
229 |         const Gap(16),
230 |         Column(
231 |           crossAxisAlignment: CrossAxisAlignment.start,
232 |           children: const [
233 |             Text('42%'),
234 |             Text(
235 |               'John\'s battery',
236 |               overflow: TextOverflow.ellipsis,
237 |             ),
238 |           ],
239 |         ),
240 |       ],
241 |     );
242 |   }
243 | }
244 | 
245 | class SmartCard extends StatelessWidget {
246 |   const SmartCard({Key? key, this.child}) : super(key: key);
247 |   final Widget? child;
248 | 
249 |   @override
250 |   Widget build(BuildContext context) {
251 |     return Padding(
252 |       padding: const EdgeInsets.all(32.0),
253 |       child: DecoratedBox(
254 |         decoration: BoxDecoration(
255 |           borderRadius: BorderRadius.circular(32),
256 |           color: Colors.white,
257 |           boxShadow: [
258 |             const BoxShadow(
259 |               color: Colors.black12,
260 |               blurRadius: 32,
261 |               offset: Offset(6, 6),
262 |             ),
263 |           ],
264 |         ),
265 |         child: Padding(
266 |           padding: const EdgeInsets.all(32.0),
267 |           child: child,
268 |         ),
269 |       ),
270 |     );
271 |   }
272 | }
273 | 
274 | LineChartData sampleData() {
275 |   return LineChartData(
276 |     gridData: FlGridData(
277 |       show: false,
278 |     ),
279 |     titlesData: FlTitlesData(
280 |       topTitles: SideTitles(showTitles: false),
281 |       bottomTitles: SideTitles(
282 |         showTitles: true,
283 |         reservedSize: 6,
284 |         getTextStyles: (context, value) => const TextStyle(
285 |           color: Colors.black38,
286 |           fontWeight: FontWeight.bold,
287 |           fontSize: 11,
288 |         ),
289 |         interval: 1,
290 |         // margin: 10,
291 |         getTitles: (value) {
292 |           switch (value.toInt() % 7) {
293 |             case 1:
294 |               return 'MON';
295 |             // case 2:
296 |             //   return 'TUE';
297 |             case 3:
298 |               return 'WED';
299 |             // case 4:
300 |             //   return 'THU';
301 |             case 5:
302 |               return 'FRI';
303 |             case 7:
304 |               return 'SUN';
305 |           }
306 |           return '';
307 |         },
308 |       ),
309 |       rightTitles: SideTitles(showTitles: false),
310 |       leftTitles: SideTitles(
311 |         showTitles: true,
312 |         getTextStyles: (context, value) => const TextStyle(
313 |           color: Colors.black38,
314 |           fontWeight: FontWeight.bold,
315 |           fontSize: 11,
316 |         ),
317 | 
318 |         interval: 50,
319 |         // getTitles: (value) {
320 |         //   switch (value.toInt()) {
321 |         //     case 1:
322 |         //       return '';
323 |         //     case 2:
324 |         //       return '20';
325 |         //     case 3:
326 |         //       return '';
327 |         //     case 4:
328 |         //       return '22';
329 |         //   }
330 |         //   return '';
331 |         // },
332 |         margin: 4,
333 |         reservedSize: 30,
334 |       ),
335 |     ),
336 |     borderData: FlBorderData(
337 |       show: true,
338 |       border: const Border(
339 |         bottom: BorderSide(
340 |           color: Color(0xff4e4965),
341 |           width: 1,
342 |         ),
343 |         left: BorderSide(
344 |           color: Colors.transparent,
345 |         ),
346 |         right: BorderSide(
347 |           color: Colors.transparent,
348 |         ),
349 |         top: BorderSide(
350 |           color: Colors.transparent,
351 |         ),
352 |       ),
353 |     ),
354 |     minX: 0,
355 |     maxX: 14,
356 |     maxY: 100,
357 |     minY: 0,
358 |     lineBarsData: linesBarData1(),
359 |   );
360 | }
361 | 
362 | List linesBarData1() {
363 |   final LineChartBarData lineChartBarData1 = LineChartBarData(
364 |     spots: [
365 |       FlSpot(1, 80),
366 |       FlSpot(2, 40),
367 |       FlSpot(3, 30),
368 |       FlSpot(4, 60),
369 |       FlSpot(5, 80),
370 |       FlSpot(6, 70),
371 |       FlSpot(8, 30),
372 |       FlSpot(9, 100),
373 |       FlSpot(10, 85),
374 |       FlSpot(11, 64),
375 |       FlSpot(12, 62),
376 |       FlSpot(13, 49),
377 |     ],
378 |     isCurved: true,
379 |     colors: [
380 |       Colors.black54,
381 |     ],
382 |     barWidth: 4,
383 |     isStrokeCapRound: true,
384 |     dotData: FlDotData(
385 |       show: false,
386 |     ),
387 |     belowBarData: BarAreaData(
388 |       show: false,
389 |     ),
390 |   );
391 | 
392 |   return [
393 |     lineChartBarData1,
394 |   ];
395 | }
396 | 
--------------------------------------------------------------------------------
/lib/pages/implicit/implicit.dart:
--------------------------------------------------------------------------------
1 | export 'implicit_counter.dart';
2 | export 'implicit_loader.dart';
3 | 
--------------------------------------------------------------------------------
/lib/pages/implicit/implicit_counter.dart:
--------------------------------------------------------------------------------
 1 | import 'package:flutter/material.dart';
 2 | 
 3 | class SmoothCounter extends ImplicitlyAnimatedWidget {
 4 |   SmoothCounter({
 5 |     Key? key,
 6 |     required this.progress,
 7 |     Duration duration = const Duration(milliseconds: 700),
 8 |     Curve curve = Curves.easeOutCubic,
 9 |     this.style,
10 |   }) : super(duration: duration, curve: curve, key: key);
11 | 
12 |   final double progress;
13 |   final TextStyle? style;
14 | 
15 |   @override
16 |   ImplicitlyAnimatedWidgetState createState() =>
17 |       _SmoothLoadingIndicatorState();
18 | }
19 | 
20 | class _SmoothLoadingIndicatorState
21 |     extends AnimatedWidgetBaseState {
22 |   Tween? _progress;
23 | 
24 |   @override
25 |   Widget build(BuildContext context) {
26 |     final value = _progress?.evaluate(animation);
27 |     return SizedBox(
28 |       width: 120,
29 |       child: Text(
30 |         (value != null ? value.toStringAsFixed(0) : '0') + '%',
31 |         style: widget.style ??
32 |             TextStyle(
33 |               fontSize: 46,
34 |               fontWeight: FontWeight.bold,
35 |               fontFamily: 'Fira Code',
36 |             ),
37 |       ),
38 |     );
39 |   }
40 | 
41 |   @override
42 |   void forEachTween(TweenVisitor visitor) {
43 |     _progress = visitor(
44 |       _progress,
45 |       widget.progress,
46 |       (dynamic value) => Tween(begin: value as double?),
47 |     ) as Tween?;
48 |   }
49 | }
50 | 
--------------------------------------------------------------------------------
/lib/pages/implicit/implicit_loader.dart:
--------------------------------------------------------------------------------
 1 | import 'package:flutter/material.dart';
 2 | 
 3 | class SmoothLoadingIndicator extends ImplicitlyAnimatedWidget {
 4 |   SmoothLoadingIndicator({
 5 |     Key? key,
 6 |     required this.progress,
 7 |     Duration duration = const Duration(milliseconds: 200),
 8 |     Curve curve = Curves.linear,
 9 |     this.color = Colors.blue,
10 |     this.backgroundColor = const Color(0xFFBBDEFB),
11 |   }) : super(duration: duration, curve: curve, key: key);
12 | 
13 |   final double progress;
14 |   final Color color;
15 |   final Color backgroundColor;
16 | 
17 |   @override
18 |   ImplicitlyAnimatedWidgetState createState() =>
19 |       _SmoothLoadingIndicatorState();
20 | }
21 | 
22 | class _SmoothLoadingIndicatorState
23 |     extends AnimatedWidgetBaseState {
24 |   Tween? _progress;
25 | 
26 |   @override
27 |   Widget build(BuildContext context) {
28 |     return CircularProgressIndicator(
29 |       backgroundColor: widget.backgroundColor,
30 |       color: widget.color,
31 |       value: _progress!.evaluate(animation),
32 |       strokeWidth: 15,
33 |     );
34 |   }
35 | 
36 |   @override
37 |   void forEachTween(TweenVisitor visitor) {
38 |     _progress = visitor(
39 |       _progress,
40 |       (widget.progress).clamp(0.0, 1.0),
41 |       (dynamic value) => Tween(begin: value as double?),
42 |     ) as Tween?;
43 |   }
44 | }
45 | 
--------------------------------------------------------------------------------
/lib/pages/implicit_animations.dart:
--------------------------------------------------------------------------------
  1 | import 'dart:math' as math;
  2 | import 'package:animations_sample/pages/implicit/implicit_counter.dart';
  3 | import 'package:animations_sample/pages/implicit/implicit_loader.dart';
  4 | import 'package:flutter/material.dart';
  5 | 
  6 | class ImplicitAnimations extends StatefulWidget {
  7 |   @override
  8 |   _ImplicitAnimationsState createState() => _ImplicitAnimationsState();
  9 | }
 10 | 
 11 | class _ImplicitAnimationsState extends State {
 12 |   Alignment alignment = Alignment.center;
 13 | 
 14 |   int index = 0;
 15 |   final colors = [Colors.blue, Colors.deepPurple, Colors.green];
 16 |   final bColors = [Colors.transparent, Colors.purple, Colors.green[800]];
 17 |   final sizes = [150.0, 195.0, 300.0];
 18 |   final tSizes = [12.0, 16.0, 20.0];
 19 |   final radius = [0.0, 16.0, 90.0];
 20 |   final elevations = [0.0, 16.0, 32.0];
 21 |   final opacity = [1.0, 0.3, 0.01];
 22 | 
 23 |   @override
 24 |   Widget build(BuildContext context) {
 25 |     final text = 'Size: ${sizes[index]}, Radius: ${radius[index]}, '
 26 |         'Elevation: ${elevations[index]}';
 27 |     return ListView(
 28 |       children: [
 29 |         Text(text),
 30 |         Center(child: LoaderDemo()),
 31 |         OverflowBar(
 32 |           alignment: MainAxisAlignment.spaceEvenly,
 33 |           children: [
 34 |             InkWell(
 35 |               onTap: () {
 36 |                 setState(() {
 37 |                   index = (index + 1) % colors.length;
 38 |                 });
 39 |               },
 40 |               child: AnimatedPhysicalModel(
 41 |                 child: Padding(
 42 |                   padding: const EdgeInsets.all(32.0),
 43 |                   child: Text('AnimatedPhysicalModel'),
 44 |                 ),
 45 |                 duration: kThemeAnimationDuration,
 46 |                 shape: BoxShape.rectangle,
 47 |                 elevation: elevations[index],
 48 |                 color: Colors.blue[100]!,
 49 |                 shadowColor: colors[index],
 50 |               ),
 51 |             ),
 52 |             AnimatedContainer(
 53 |               width: sizes[index],
 54 |               height: sizes[index],
 55 |               decoration: BoxDecoration(
 56 |                 borderRadius: BorderRadius.circular(radius[index]),
 57 |                 color: colors[index],
 58 |                 boxShadow: [
 59 |                   BoxShadow(
 60 |                     color: Colors.black54,
 61 |                     blurRadius: radius[index],
 62 |                   ),
 63 |                 ],
 64 |                 border: Border.all(
 65 |                   color: bColors[index]!,
 66 |                   width: index * 10.0,
 67 |                 ),
 68 |               ),
 69 |               duration: kThemeAnimationDuration,
 70 |               curve: Curves.easeInOut,
 71 |               child: InkWell(
 72 |                 onTap: () {
 73 |                   setState(() {
 74 |                     index = (index + 1) % colors.length;
 75 |                   });
 76 |                 },
 77 |                 child: Center(
 78 |                   child: AnimatedDefaultTextStyle(
 79 |                     duration: kThemeAnimationDuration,
 80 |                     style: TextStyle(fontSize: tSizes[index]),
 81 |                     child: Text(
 82 |                       'AnimatedContainer',
 83 |                       textAlign: TextAlign.center,
 84 |                     ),
 85 |                   ),
 86 |                 ),
 87 |               ),
 88 |             ),
 89 |             AnimatedOpacity(
 90 |               opacity: opacity[index],
 91 |               duration: kThemeAnimationDuration,
 92 |               child: InkWell(
 93 |                 onTap: () {
 94 |                   setState(() {
 95 |                     index = (index + 1) % colors.length;
 96 |                   });
 97 |                 },
 98 |                 child: Padding(
 99 |                   padding: const EdgeInsets.all(32.0),
100 |                   child: Text('AnimatedOpacity ${opacity[index]}'),
101 |                 ),
102 |               ),
103 |             ),
104 |           ],
105 |         ),
106 |         SizedBox(
107 |           height: 400,
108 |           child: Stack(
109 |             children: [
110 |               AnimatedAlign(
111 |                 child: TextButton(
112 |                   onPressed: () {
113 |                     setState(() {
114 |                       final random1 = (math.Random().nextDouble() - 0.5);
115 |                       final random2 = (math.Random().nextDouble() - 0.5);
116 |                       alignment = Alignment(random1, random2);
117 |                     });
118 |                   },
119 |                   style:
120 |                       TextButton.styleFrom(textStyle: TextStyle(fontSize: 24)),
121 |                   child: Padding(
122 |                     padding: const EdgeInsets.all(16.0),
123 |                     child: Text('AnimatedAlign $alignment'),
124 |                   ),
125 |                 ),
126 |                 duration: kThemeAnimationDuration,
127 |                 alignment: alignment,
128 |               ),
129 |             ],
130 |           ),
131 |         ),
132 |       ],
133 |     );
134 |   }
135 | }
136 | 
137 | class LoaderDemo extends StatefulWidget {
138 |   const LoaderDemo({
139 |     Key? key,
140 |   }) : super(key: key);
141 | 
142 |   @override
143 |   _LoaderDemoState createState() => _LoaderDemoState();
144 | }
145 | 
146 | class _LoaderDemoState extends State {
147 |   double progress = 0.0;
148 | 
149 |   @override
150 |   Widget build(BuildContext context) {
151 |     return Padding(
152 |       padding: const EdgeInsets.all(32.0),
153 |       child: OverflowBar(
154 |         spacing: 16,
155 |         children: [
156 |           OutlinedButton(
157 |             onPressed: () {
158 |               setState(() {
159 |                 progress = progress + 0.1;
160 |               });
161 |               if (progress >= 1.0) {
162 |                 setState(() {
163 |                   progress = 0.0;
164 |                 });
165 |               }
166 |             },
167 |             child: Text('Progress: ${progress.toStringAsFixed(2)}'),
168 |           ),
169 |           SmoothCounter(progress: progress * 100),
170 |           SizedBox(
171 |             width: 50,
172 |             height: 50,
173 |             child: SmoothLoadingIndicator(
174 |               progress: progress,
175 |             ),
176 |           ),
177 |         ],
178 |       ),
179 |     );
180 |   }
181 | }
182 | 
--------------------------------------------------------------------------------
/lib/pages/material.dart:
--------------------------------------------------------------------------------
 1 | import 'package:flutter/material.dart';
 2 | 
 3 | import 'material/example.dart';
 4 | 
 5 | class MaterialAnimationsDemo extends StatelessWidget {
 6 |   @override
 7 |   Widget build(BuildContext context) {
 8 |     return OpenContainerTransformDemo();
 9 |   }
10 | }
11 | 
--------------------------------------------------------------------------------
/lib/pages/page.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | 
3 | class AppPage {
4 |   AppPage(this.title, this.widget);
5 |   final String title;
6 |   final Widget widget;
7 | }
8 | 
--------------------------------------------------------------------------------
/lib/pages/pages.dart:
--------------------------------------------------------------------------------
 1 | export 'about.dart';
 2 | export 'custom_controller.dart';
 3 | export 'explicit_animations.dart';
 4 | export 'funvas.dart';
 5 | export 'implicit_animations.dart';
 6 | export 'material.dart';
 7 | export 'page.dart';
 8 | export 'spring_simulation.dart';
 9 | export 'staggered_animations.dart';
10 | export 'tween_animation_builder.dart';
11 | export 'tweens.dart';
12 | 
--------------------------------------------------------------------------------
/lib/pages/spring_simulation.dart:
--------------------------------------------------------------------------------
 1 | import 'package:flutter/material.dart';
 2 | import 'package:flutter/physics.dart';
 3 | 
 4 | class PhysicsAnimation extends StatefulWidget {
 5 |   _PhysicsAnimation createState() => _PhysicsAnimation();
 6 | }
 7 | 
 8 | class _PhysicsAnimation extends State
 9 |     with SingleTickerProviderStateMixin {
10 |   late AnimationController controller;
11 | 
12 |   late SpringSimulation simulation;
13 | 
14 |   @override
15 |   void initState() {
16 |     super.initState();
17 | 
18 |     simulation = SpringSimulation(
19 |       SpringDescription(
20 |         mass: 2,
21 |         stiffness: 100,
22 |         damping: 1,
23 |       ),
24 |       0.0,
25 |       500.0,
26 |       10,
27 |     );
28 | 
29 |     controller = AnimationController(
30 |       vsync: this,
31 |       upperBound: 1500,
32 |     );
33 | 
34 |     controller.animateWith(simulation);
35 |   }
36 | 
37 |   @override
38 |   Widget build(BuildContext context) {
39 |     return AnimatedBuilder(
40 |       animation: controller,
41 |       builder: (context, child) {
42 |         return Stack(
43 |           children: [
44 |             Positioned(
45 |               top: controller.value,
46 |               left: 0,
47 |               right: 0,
48 |               child: Container(
49 |                 height: 100,
50 |                 color: Colors.redAccent,
51 |               ),
52 |             ),
53 |           ],
54 |         );
55 |       },
56 |     );
57 |   }
58 | 
59 |   @override
60 |   void dispose() {
61 |     controller.dispose();
62 |     super.dispose();
63 |   }
64 | }
65 | 
--------------------------------------------------------------------------------
/lib/pages/staggered_animations.dart:
--------------------------------------------------------------------------------
  1 | import 'package:fl_chart/fl_chart.dart';
  2 | import 'package:flutter/material.dart';
  3 | import 'package:gap/gap.dart';
  4 | import 'package:google_fonts/google_fonts.dart';
  5 | import 'package:line_icons/line_icons.dart';
  6 | 
  7 | part 'helpers/staggered_animations_widgets.dart';
  8 | 
  9 | class StaggeredAnimations extends StatefulWidget {
 10 |   @override
 11 |   _StaggeredAnimationsState createState() => _StaggeredAnimationsState();
 12 | }
 13 | 
 14 | class _StaggeredAnimationsState extends State
 15 |     with TickerProviderStateMixin {
 16 |   late AnimationController animationController;
 17 | 
 18 |   @override
 19 |   void initState() {
 20 |     super.initState();
 21 |     animationController = AnimationController(
 22 |       vsync: this,
 23 |       duration: Duration(seconds: 4),
 24 |     )
 25 |       ..forward()
 26 |       ..repeat();
 27 |   }
 28 | 
 29 |   @override
 30 |   void dispose() {
 31 |     animationController.dispose();
 32 |     super.dispose();
 33 |   }
 34 | 
 35 |   @override
 36 |   Widget build(BuildContext context) {
 37 |     return Theme(
 38 |       data: Theme.of(context).copyWith(
 39 |         textTheme: GoogleFonts.ralewayTextTheme(Theme.of(context).textTheme),
 40 |       ),
 41 |       child: PageLayout(controller: animationController),
 42 |     );
 43 |   }
 44 | }
 45 | 
 46 | class PageLayout extends StatelessWidget {
 47 |   const PageLayout({
 48 |     Key? key,
 49 |     required this.controller,
 50 |   }) : super(key: key);
 51 | 
 52 |   final AnimationController controller;
 53 | 
 54 |   @override
 55 |   Widget build(BuildContext context) {
 56 |     return SingleChildScrollView(
 57 |       child: Stack(
 58 |         children: [
 59 |           HomePageAnimatedBuilder(
 60 |             animation: controller,
 61 |             builder: (context, child, animation) {
 62 |               return Column(
 63 |                 children: [
 64 |                   Gap(16),
 65 |                   Opacity(
 66 |                     opacity: animation.headerOpacity.value,
 67 |                     child: const _Header(),
 68 |                   ),
 69 |                   SlideTransition(
 70 |                     position: animation.row1Offset,
 71 |                     child: const _Row1(),
 72 |                   ),
 73 |                   SlideTransition(
 74 |                     position: animation.row2Offset,
 75 |                     child: const _Row2(),
 76 |                   ),
 77 |                   SlideTransition(
 78 |                     position: animation.row3Offset,
 79 |                     child: const _Row3(),
 80 |                   ),
 81 |                 ],
 82 |               );
 83 |             },
 84 |           ),
 85 |           Positioned(
 86 |             right: 20,
 87 |             top: 20,
 88 |             child: IconButton(
 89 |               onPressed: () {
 90 |                 if (controller.isAnimating) {
 91 |                   controller.stop();
 92 |                 } else {
 93 |                   controller
 94 |                     ..forward()
 95 |                     ..repeat();
 96 |                 }
 97 |               },
 98 |               icon: Icon(Icons.pause_circle),
 99 |             ),
100 |           )
101 |         ],
102 |       ),
103 |     );
104 |   }
105 | }
106 | 
107 | class HomePageAnimatedBuilder extends StatelessWidget {
108 |   const HomePageAnimatedBuilder({
109 |     Key? key,
110 |     required this.builder,
111 |     required this.animation,
112 |     this.child,
113 |   }) : super(key: key);
114 | 
115 |   final MyTransitionBuilder builder;
116 |   final Listenable animation;
117 |   final Widget? child;
118 | 
119 |   @override
120 |   Widget build(BuildContext context) {
121 |     return AnimatedBuilder(
122 |       animation: animation,
123 |       builder: (context, child) {
124 |         return builder(
125 |           context,
126 |           child,
127 |           HomePageEnterAnimation(animation as AnimationController),
128 |         );
129 |       },
130 |       child: child,
131 |     );
132 |   }
133 | }
134 | 
135 | typedef MyTransitionBuilder = Widget Function(
136 |   BuildContext context,
137 |   Widget? child,
138 |   HomePageEnterAnimation animation,
139 | );
140 | 
141 | class HomePageEnterAnimation {
142 |   HomePageEnterAnimation(this.controller)
143 |       : headerOpacity = Tween(begin: 0, end: 1.0).animate(
144 |           CurvedAnimation(
145 |             parent: controller,
146 |             curve: Interval(0, 0.2, curve: Curves.easeIn),
147 |           ),
148 |         ),
149 |         row1Offset =
150 |             Tween(begin: Offset(0, 5), end: Offset.zero).animate(
151 |           CurvedAnimation(
152 |             parent: controller,
153 |             curve: Interval(0.1, 0.25, curve: Curves.easeOut),
154 |           ),
155 |         ),
156 |         row2Offset =
157 |             Tween(begin: Offset(0, 5), end: Offset.zero).animate(
158 |           CurvedAnimation(
159 |             parent: controller,
160 |             curve: Interval(0.15, 0.30, curve: Curves.easeOut),
161 |           ),
162 |         ),
163 |         row3Offset =
164 |             Tween(begin: Offset(0, 5), end: Offset.zero).animate(
165 |           CurvedAnimation(
166 |             parent: controller,
167 |             curve: Interval(0.2, 0.35, curve: Curves.easeOut),
168 |           ),
169 |         );
170 | 
171 |   final AnimationController controller;
172 |   final Animation headerOpacity;
173 |   final Animation row1Offset;
174 |   final Animation row2Offset;
175 |   final Animation row3Offset;
176 | }
177 | 
--------------------------------------------------------------------------------
/lib/pages/tween_animation_builder.dart:
--------------------------------------------------------------------------------
  1 | import 'dart:math';
  2 | 
  3 | import 'package:flutter/material.dart';
  4 | 
  5 | class TweenPageController extends StatefulWidget {
  6 |   @override
  7 |   _TweenPageControllerState createState() => _TweenPageControllerState();
  8 | }
  9 | 
 10 | class _TweenPageControllerState extends State {
 11 |   double scale = 1.0;
 12 | 
 13 |   @override
 14 |   Widget build(BuildContext context) {
 15 |     return ClipRect(
 16 |       child: Stack(
 17 |         children: [
 18 |           Column(
 19 |             mainAxisAlignment: MainAxisAlignment.spaceEvenly,
 20 |             children: [
 21 |               TweenAnimationDemo(
 22 |                 scale: scale,
 23 |               ),
 24 |               TweenAnimationRotationDemo(
 25 |                 scale: scale,
 26 |               ),
 27 |             ],
 28 |           ),
 29 |           Padding(
 30 |             padding: const EdgeInsets.all(32.0),
 31 |             child: Row(
 32 |               mainAxisAlignment: MainAxisAlignment.spaceEvenly,
 33 |               children: [
 34 |                 ElevatedButton(
 35 |                   onPressed: () {
 36 |                     setState(() {
 37 |                       scale = 1.0;
 38 |                     });
 39 |                   },
 40 |                   child: Text('x1.0'),
 41 |                 ),
 42 |                 ElevatedButton(
 43 |                   onPressed: () {
 44 |                     setState(() {
 45 |                       scale = 10.0;
 46 |                     });
 47 |                   },
 48 |                   child: Text('x10.0'),
 49 |                 ),
 50 |                 ElevatedButton(
 51 |                   onPressed: () {
 52 |                     setState(() {
 53 |                       scale = 30.0;
 54 |                     });
 55 |                   },
 56 |                   child: Text('x30.0'),
 57 |                 ),
 58 |               ],
 59 |             ),
 60 |           ),
 61 |         ],
 62 |       ),
 63 |     );
 64 |   }
 65 | }
 66 | 
 67 | class TweenAnimationDemo extends StatelessWidget {
 68 |   const TweenAnimationDemo({Key? key, this.scale}) : super(key: key);
 69 | 
 70 |   final double? scale;
 71 | 
 72 |   @override
 73 |   Widget build(BuildContext context) {
 74 |     return Center(
 75 |       child: TweenAnimationBuilder(
 76 |         duration: Duration(seconds: 2),
 77 |         tween: Tween(begin: 0.0, end: scale ?? 1.0),
 78 |         curve: Curves.easeInOut,
 79 |         builder: (context, dynamic value, child) {
 80 |           return Transform.scale(
 81 |             scale: value,
 82 |             child: child,
 83 |           );
 84 |         },
 85 |         child: Text(
 86 |           'Hello Flutter Meetup!',
 87 |           textAlign: TextAlign.center,
 88 |         ),
 89 |       ),
 90 |     );
 91 |   }
 92 | }
 93 | 
 94 | class TweenAnimationRotationDemo extends StatelessWidget {
 95 |   const TweenAnimationRotationDemo({Key? key, this.scale}) : super(key: key);
 96 | 
 97 |   final double? scale;
 98 | 
 99 |   @override
100 |   Widget build(BuildContext context) {
101 |     return Center(
102 |       child: TweenAnimationBuilder(
103 |         duration: Duration(seconds: 2),
104 |         tween: Tween(begin: 0.0, end: scale ?? 1.0),
105 |         curve: Curves.easeInOut,
106 |         builder: (context, dynamic value, child) {
107 |           return Transform.rotate(
108 |             angle: (value - 1) / 5 * pi,
109 |             child: child,
110 |           );
111 |         },
112 |         child: FlutterLogo(
113 |           size: 200,
114 |         ),
115 |       ),
116 |     );
117 |   }
118 | }
119 | 
--------------------------------------------------------------------------------
/lib/pages/tweens.dart:
--------------------------------------------------------------------------------
  1 | import 'package:flutter/material.dart';
  2 | import 'package:gap/gap.dart';
  3 | 
  4 | class Tweens extends StatefulWidget {
  5 |   @override
  6 |   _TweensState createState() => _TweensState();
  7 | }
  8 | 
  9 | class _TweensState extends State with TickerProviderStateMixin {
 10 |   AnimationController? animationController;
 11 | 
 12 |   final curves = {
 13 |     'Curves.linear': Curves.linear,
 14 |     'Curves.bounceIn': Curves.bounceIn,
 15 |     'Curves.decelerate': Curves.decelerate,
 16 |     'Curves.ease': Curves.ease,
 17 |     'Curves.easeInOut': Curves.easeInOut,
 18 |     'Curves.easeOutBack': Curves.easeOutBack,
 19 |     'Curves.easeOutExpo': Curves.easeOutExpo,
 20 |     'Curves.easeOutSine': Curves.easeOutSine,
 21 |     'Curves.easeInOutExpo': Curves.easeInOutExpo,
 22 |     'Curves.easeInOutCubicEmphasized': Curves.easeInOutCubicEmphasized,
 23 |     'Curves.elasticIn': Curves.elasticIn,
 24 |     'Curves.fastLinearToSlowEaseIn': Curves.fastLinearToSlowEaseIn,
 25 |     'Curves.slowMiddle': Curves.slowMiddle,
 26 |   };
 27 | 
 28 |   @override
 29 |   void initState() {
 30 |     super.initState();
 31 |     animationController = AnimationController(
 32 |       vsync: this,
 33 |       duration: Duration(seconds: 5),
 34 |     )
 35 |       ..forward()
 36 |       ..repeat();
 37 |   }
 38 | 
 39 |   @override
 40 |   void dispose() {
 41 |     animationController?.dispose();
 42 |     super.dispose();
 43 |   }
 44 | 
 45 |   Animation getTween(AnimationController _controller) {
 46 |     return Tween(
 47 |       begin: const Offset(-2.0, 0.0),
 48 |       end: const Offset(2.0, 0.0),
 49 |     ).animate(_controller);
 50 |   }
 51 | 
 52 |   Animation getCurvedTween(
 53 |       AnimationController _controller, Curve curve) {
 54 |     return Tween(
 55 |       begin: const Offset(-2.0, 0.0),
 56 |       end: const Offset(2.0, 0.0),
 57 |     ).animate(
 58 |       CurvedAnimation(
 59 |         parent: _controller,
 60 |         curve: curve,
 61 |       ),
 62 |     );
 63 |   }
 64 | 
 65 |   @override
 66 |   Widget build(BuildContext context) {
 67 |     final widget = ListView.separated(
 68 |       itemCount: curves.entries.length,
 69 |       separatorBuilder: (_, __) => const Gap(16),
 70 |       itemBuilder: (context, index) {
 71 |         final curve = curves.entries.elementAt(index);
 72 |         return Stack(
 73 |           children: [
 74 |             Center(
 75 |               child: AnimatedBuilder(
 76 |                 animation: animationController!,
 77 |                 builder: (context, child) {
 78 |                   final position =
 79 |                       getCurvedTween(animationController!, curve.value);
 80 |                   return SlideTransition(
 81 |                     position: position,
 82 |                     child: child,
 83 |                   );
 84 |                 },
 85 |                 child: Container(
 86 |                   height: 200,
 87 |                   width: 200,
 88 |                   color: Color.fromARGB(
 89 |                     255,
 90 |                     160 + 20 * (index % 3),
 91 |                     180 + 30 * (index % 2),
 92 |                     170 + 20 * (index % 5),
 93 |                   ),
 94 |                 ),
 95 |               ),
 96 |             ),
 97 |             SizedBox(
 98 |               height: 200,
 99 |               width: double.infinity,
100 |               child: CustomPaint(
101 |                 painter: CurvePainter(curve.value),
102 |               ),
103 |             ),
104 |             Align(
105 |               alignment: Alignment.topLeft,
106 |               child: Padding(
107 |                 padding: const EdgeInsets.all(8.0),
108 |                 child: Text(
109 |                   '${curve.key}',
110 |                   style: Theme.of(context).textTheme.headline6,
111 |                 ),
112 |               ),
113 |             ),
114 |           ],
115 |         );
116 |       },
117 |     );
118 | 
119 |     return ClipRect(
120 |       child: widget,
121 |     );
122 |   }
123 | }
124 | 
125 | class CurvePainter extends CustomPainter {
126 |   CurvePainter(this.curve);
127 | 
128 |   final Curve curve;
129 | 
130 |   @override
131 |   void paint(Canvas canvas, Size size) {
132 |     final path = Path();
133 |     for (var i = 0; i < size.width; i++) {
134 |       path.lineTo(i.toDouble(), curve.transform(i / size.width) * size.height);
135 |     }
136 |     canvas.drawPath(
137 |       path,
138 |       Paint()
139 |         ..color = Colors.black45
140 |         ..style = PaintingStyle.stroke
141 |         ..strokeWidth = 2,
142 |     );
143 |   }
144 | 
145 |   @override
146 |   bool shouldRepaint(covariant CustomPainter oldDelegate) {
147 |     return true;
148 |   }
149 | }
150 | 
--------------------------------------------------------------------------------
/linux/.gitignore:
--------------------------------------------------------------------------------
1 | flutter/ephemeral
2 | 
--------------------------------------------------------------------------------
/linux/CMakeLists.txt:
--------------------------------------------------------------------------------
  1 | cmake_minimum_required(VERSION 3.10)
  2 | project(runner LANGUAGES CXX)
  3 | 
  4 | set(BINARY_NAME "animations")
  5 | set(APPLICATION_ID "dev.roszkowski.animations")
  6 | 
  7 | cmake_policy(SET CMP0063 NEW)
  8 | 
  9 | set(CMAKE_INSTALL_RPATH "$ORIGIN/lib")
 10 | 
 11 | # Configure build options.
 12 | if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
 13 |   set(CMAKE_BUILD_TYPE "Debug" CACHE
 14 |     STRING "Flutter build mode" FORCE)
 15 |   set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS
 16 |     "Debug" "Profile" "Release")
 17 | endif()
 18 | 
 19 | # Compilation settings that should be applied to most targets.
 20 | function(APPLY_STANDARD_SETTINGS TARGET)
 21 |   target_compile_features(${TARGET} PUBLIC cxx_std_14)
 22 |   target_compile_options(${TARGET} PRIVATE -Wall -Werror)
 23 |   target_compile_options(${TARGET} PRIVATE "$<$>:-O3>")
 24 |   target_compile_definitions(${TARGET} PRIVATE "$<$>:NDEBUG>")
 25 | endfunction()
 26 | 
 27 | set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter")
 28 | 
 29 | # Flutter library and tool build rules.
 30 | add_subdirectory(${FLUTTER_MANAGED_DIR})
 31 | 
 32 | # System-level dependencies.
 33 | find_package(PkgConfig REQUIRED)
 34 | pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0)
 35 | 
 36 | add_definitions(-DAPPLICATION_ID="${APPLICATION_ID}")
 37 | 
 38 | # Application build
 39 | add_executable(${BINARY_NAME}
 40 |   "main.cc"
 41 |   "my_application.cc"
 42 |   "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc"
 43 | )
 44 | apply_standard_settings(${BINARY_NAME})
 45 | target_link_libraries(${BINARY_NAME} PRIVATE flutter)
 46 | target_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTK)
 47 | add_dependencies(${BINARY_NAME} flutter_assemble)
 48 | # Only the install-generated bundle's copy of the executable will launch
 49 | # correctly, since the resources must in the right relative locations. To avoid
 50 | # people trying to run the unbundled copy, put it in a subdirectory instead of
 51 | # the default top-level location.
 52 | set_target_properties(${BINARY_NAME}
 53 |   PROPERTIES
 54 |   RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/intermediates_do_not_run"
 55 | )
 56 | 
 57 | # Generated plugin build rules, which manage building the plugins and adding
 58 | # them to the application.
 59 | include(flutter/generated_plugins.cmake)
 60 | 
 61 | 
 62 | # === Installation ===
 63 | # By default, "installing" just makes a relocatable bundle in the build
 64 | # directory.
 65 | set(BUILD_BUNDLE_DIR "${PROJECT_BINARY_DIR}/bundle")
 66 | if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
 67 |   set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE)
 68 | endif()
 69 | 
 70 | # Start with a clean build bundle directory every time.
 71 | install(CODE "
 72 |   file(REMOVE_RECURSE \"${BUILD_BUNDLE_DIR}/\")
 73 |   " COMPONENT Runtime)
 74 | 
 75 | set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data")
 76 | set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib")
 77 | 
 78 | install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}"
 79 |   COMPONENT Runtime)
 80 | 
 81 | install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}"
 82 |   COMPONENT Runtime)
 83 | 
 84 | install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
 85 |   COMPONENT Runtime)
 86 | 
 87 | if(PLUGIN_BUNDLED_LIBRARIES)
 88 |   install(FILES "${PLUGIN_BUNDLED_LIBRARIES}"
 89 |     DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
 90 |     COMPONENT Runtime)
 91 | endif()
 92 | 
 93 | # Fully re-copy the assets directory on each build to avoid having stale files
 94 | # from a previous install.
 95 | set(FLUTTER_ASSET_DIR_NAME "flutter_assets")
 96 | install(CODE "
 97 |   file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\")
 98 |   " COMPONENT Runtime)
 99 | install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}"
100 |   DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime)
101 | 
102 | # Install the AOT library on non-Debug builds only.
103 | if(NOT CMAKE_BUILD_TYPE MATCHES "Debug")
104 |   install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
105 |     COMPONENT Runtime)
106 | endif()
107 | 
--------------------------------------------------------------------------------
/linux/flutter/CMakeLists.txt:
--------------------------------------------------------------------------------
 1 | cmake_minimum_required(VERSION 3.10)
 2 | 
 3 | set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral")
 4 | 
 5 | # Configuration provided via flutter tool.
 6 | include(${EPHEMERAL_DIR}/generated_config.cmake)
 7 | 
 8 | # TODO: Move the rest of this into files in ephemeral. See
 9 | # https://github.com/flutter/flutter/issues/57146.
10 | 
11 | # Serves the same purpose as list(TRANSFORM ... PREPEND ...),
12 | # which isn't available in 3.10.
13 | function(list_prepend LIST_NAME PREFIX)
14 |     set(NEW_LIST "")
15 |     foreach(element ${${LIST_NAME}})
16 |         list(APPEND NEW_LIST "${PREFIX}${element}")
17 |     endforeach(element)
18 |     set(${LIST_NAME} "${NEW_LIST}" PARENT_SCOPE)
19 | endfunction()
20 | 
21 | # === Flutter Library ===
22 | # System-level dependencies.
23 | find_package(PkgConfig REQUIRED)
24 | pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0)
25 | pkg_check_modules(GLIB REQUIRED IMPORTED_TARGET glib-2.0)
26 | pkg_check_modules(GIO REQUIRED IMPORTED_TARGET gio-2.0)
27 | pkg_check_modules(BLKID REQUIRED IMPORTED_TARGET blkid)
28 | pkg_check_modules(LZMA REQUIRED IMPORTED_TARGET liblzma)
29 | 
30 | set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/libflutter_linux_gtk.so")
31 | 
32 | # Published to parent scope for install step.
33 | set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE)
34 | set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE)
35 | set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE)
36 | set(AOT_LIBRARY "${PROJECT_DIR}/build/lib/libapp.so" PARENT_SCOPE)
37 | 
38 | list(APPEND FLUTTER_LIBRARY_HEADERS
39 |   "fl_basic_message_channel.h"
40 |   "fl_binary_codec.h"
41 |   "fl_binary_messenger.h"
42 |   "fl_dart_project.h"
43 |   "fl_engine.h"
44 |   "fl_json_message_codec.h"
45 |   "fl_json_method_codec.h"
46 |   "fl_message_codec.h"
47 |   "fl_method_call.h"
48 |   "fl_method_channel.h"
49 |   "fl_method_codec.h"
50 |   "fl_method_response.h"
51 |   "fl_plugin_registrar.h"
52 |   "fl_plugin_registry.h"
53 |   "fl_standard_message_codec.h"
54 |   "fl_standard_method_codec.h"
55 |   "fl_string_codec.h"
56 |   "fl_value.h"
57 |   "fl_view.h"
58 |   "flutter_linux.h"
59 | )
60 | list_prepend(FLUTTER_LIBRARY_HEADERS "${EPHEMERAL_DIR}/flutter_linux/")
61 | add_library(flutter INTERFACE)
62 | target_include_directories(flutter INTERFACE
63 |   "${EPHEMERAL_DIR}"
64 | )
65 | target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}")
66 | target_link_libraries(flutter INTERFACE
67 |   PkgConfig::GTK
68 |   PkgConfig::GLIB
69 |   PkgConfig::GIO
70 |   PkgConfig::BLKID
71 |   PkgConfig::LZMA
72 | )
73 | add_dependencies(flutter flutter_assemble)
74 | 
75 | # === Flutter tool backend ===
76 | # _phony_ is a non-existent file to force this command to run every time,
77 | # since currently there's no way to get a full input/output list from the
78 | # flutter tool.
79 | add_custom_command(
80 |   OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS}
81 |     ${CMAKE_CURRENT_BINARY_DIR}/_phony_
82 |   COMMAND ${CMAKE_COMMAND} -E env
83 |     ${FLUTTER_TOOL_ENVIRONMENT}
84 |     "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.sh"
85 |       linux-x64 ${CMAKE_BUILD_TYPE}
86 |   VERBATIM
87 | )
88 | add_custom_target(flutter_assemble DEPENDS
89 |   "${FLUTTER_LIBRARY}"
90 |   ${FLUTTER_LIBRARY_HEADERS}
91 | )
92 | 
--------------------------------------------------------------------------------
/linux/flutter/generated_plugin_registrant.cc:
--------------------------------------------------------------------------------
 1 | //
 2 | //  Generated file. Do not edit.
 3 | //
 4 | 
 5 | // clang-format off
 6 | 
 7 | #include "generated_plugin_registrant.h"
 8 | 
 9 | #include 
10 | 
11 | void fl_register_plugins(FlPluginRegistry* registry) {
12 |   g_autoptr(FlPluginRegistrar) url_launcher_linux_registrar =
13 |       fl_plugin_registry_get_registrar_for_plugin(registry, "UrlLauncherPlugin");
14 |   url_launcher_plugin_register_with_registrar(url_launcher_linux_registrar);
15 | }
16 | 
--------------------------------------------------------------------------------
/linux/flutter/generated_plugin_registrant.h:
--------------------------------------------------------------------------------
 1 | //
 2 | //  Generated file. Do not edit.
 3 | //
 4 | 
 5 | // clang-format off
 6 | 
 7 | #ifndef GENERATED_PLUGIN_REGISTRANT_
 8 | #define GENERATED_PLUGIN_REGISTRANT_
 9 | 
10 | #include 
11 | 
12 | // Registers Flutter plugins.
13 | void fl_register_plugins(FlPluginRegistry* registry);
14 | 
15 | #endif  // GENERATED_PLUGIN_REGISTRANT_
16 | 
--------------------------------------------------------------------------------
/linux/flutter/generated_plugins.cmake:
--------------------------------------------------------------------------------
 1 | #
 2 | # Generated file, do not edit.
 3 | #
 4 | 
 5 | list(APPEND FLUTTER_PLUGIN_LIST
 6 |   url_launcher_linux
 7 | )
 8 | 
 9 | set(PLUGIN_BUNDLED_LIBRARIES)
10 | 
11 | foreach(plugin ${FLUTTER_PLUGIN_LIST})
12 |   add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/linux plugins/${plugin})
13 |   target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin)
14 |   list(APPEND PLUGIN_BUNDLED_LIBRARIES $)
15 |   list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries})
16 | endforeach(plugin)
17 | 
--------------------------------------------------------------------------------
/linux/main.cc:
--------------------------------------------------------------------------------
1 | #include "my_application.h"
2 | 
3 | int main(int argc, char** argv) {
4 |   g_autoptr(MyApplication) app = my_application_new();
5 |   return g_application_run(G_APPLICATION(app), argc, argv);
6 | }
7 | 
--------------------------------------------------------------------------------
/linux/my_application.cc:
--------------------------------------------------------------------------------
  1 | #include "my_application.h"
  2 | 
  3 | #include 
  4 | #ifdef GDK_WINDOWING_X11
  5 | #include 
  6 | #endif
  7 | 
  8 | #include "flutter/generated_plugin_registrant.h"
  9 | 
 10 | struct _MyApplication {
 11 |   GtkApplication parent_instance;
 12 |   char** dart_entrypoint_arguments;
 13 | };
 14 | 
 15 | G_DEFINE_TYPE(MyApplication, my_application, GTK_TYPE_APPLICATION)
 16 | 
 17 | // Implements GApplication::activate.
 18 | static void my_application_activate(GApplication* application) {
 19 |   MyApplication* self = MY_APPLICATION(application);
 20 |   GtkWindow* window =
 21 |       GTK_WINDOW(gtk_application_window_new(GTK_APPLICATION(application)));
 22 | 
 23 |   // Use a header bar when running in GNOME as this is the common style used
 24 |   // by applications and is the setup most users will be using (e.g. Ubuntu
 25 |   // desktop).
 26 |   // If running on X and not using GNOME then just use a traditional title bar
 27 |   // in case the window manager does more exotic layout, e.g. tiling.
 28 |   // If running on Wayland assume the header bar will work (may need changing
 29 |   // if future cases occur).
 30 |   gboolean use_header_bar = TRUE;
 31 | #ifdef GDK_WINDOWING_X11
 32 |   GdkScreen *screen = gtk_window_get_screen(window);
 33 |   if (GDK_IS_X11_SCREEN(screen)) {
 34 |      const gchar* wm_name = gdk_x11_screen_get_window_manager_name(screen);
 35 |      if (g_strcmp0(wm_name, "GNOME Shell") != 0) {
 36 |        use_header_bar = FALSE;
 37 |      }
 38 |   }
 39 | #endif
 40 |   if (use_header_bar) {
 41 |     GtkHeaderBar *header_bar = GTK_HEADER_BAR(gtk_header_bar_new());
 42 |     gtk_widget_show(GTK_WIDGET(header_bar));
 43 |     gtk_header_bar_set_title(header_bar, "animations");
 44 |     gtk_header_bar_set_show_close_button(header_bar, TRUE);
 45 |     gtk_window_set_titlebar(window, GTK_WIDGET(header_bar));
 46 |   }
 47 |   else {
 48 |     gtk_window_set_title(window, "animations");
 49 |   }
 50 | 
 51 |   gtk_window_set_default_size(window, 1280, 720);
 52 |   gtk_widget_show(GTK_WIDGET(window));
 53 | 
 54 |   g_autoptr(FlDartProject) project = fl_dart_project_new();
 55 |   fl_dart_project_set_dart_entrypoint_arguments(project, self->dart_entrypoint_arguments);
 56 | 
 57 |   FlView* view = fl_view_new(project);
 58 |   gtk_widget_show(GTK_WIDGET(view));
 59 |   gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(view));
 60 | 
 61 |   fl_register_plugins(FL_PLUGIN_REGISTRY(view));
 62 | 
 63 |   gtk_widget_grab_focus(GTK_WIDGET(view));
 64 | }
 65 | 
 66 | // Implements GApplication::local_command_line.
 67 | static gboolean my_application_local_command_line(GApplication* application, gchar ***arguments, int *exit_status) {
 68 |   MyApplication* self = MY_APPLICATION(application);
 69 |   // Strip out the first argument as it is the binary name.
 70 |   self->dart_entrypoint_arguments = g_strdupv(*arguments + 1);
 71 | 
 72 |   g_autoptr(GError) error = nullptr;
 73 |   if (!g_application_register(application, nullptr, &error)) {
 74 |      g_warning("Failed to register: %s", error->message);
 75 |      *exit_status = 1;
 76 |      return TRUE;
 77 |   }
 78 | 
 79 |   g_application_activate(application);
 80 |   *exit_status = 0;
 81 | 
 82 |   return TRUE;
 83 | }
 84 | 
 85 | // Implements GObject::dispose.
 86 | static void my_application_dispose(GObject *object) {
 87 |   MyApplication* self = MY_APPLICATION(object);
 88 |   g_clear_pointer(&self->dart_entrypoint_arguments, g_strfreev);
 89 |   G_OBJECT_CLASS(my_application_parent_class)->dispose(object);
 90 | }
 91 | 
 92 | static void my_application_class_init(MyApplicationClass* klass) {
 93 |   G_APPLICATION_CLASS(klass)->activate = my_application_activate;
 94 |   G_APPLICATION_CLASS(klass)->local_command_line = my_application_local_command_line;
 95 |   G_OBJECT_CLASS(klass)->dispose = my_application_dispose;
 96 | }
 97 | 
 98 | static void my_application_init(MyApplication* self) {}
 99 | 
100 | MyApplication* my_application_new() {
101 |   return MY_APPLICATION(g_object_new(my_application_get_type(),
102 |                                      "application-id", APPLICATION_ID,
103 |                                      nullptr));
104 | }
105 | 
--------------------------------------------------------------------------------
/linux/my_application.h:
--------------------------------------------------------------------------------
 1 | #ifndef FLUTTER_MY_APPLICATION_H_
 2 | #define FLUTTER_MY_APPLICATION_H_
 3 | 
 4 | #include 
 5 | 
 6 | G_DECLARE_FINAL_TYPE(MyApplication, my_application, MY, APPLICATION,
 7 |                      GtkApplication)
 8 | 
 9 | /**
10 |  * my_application_new:
11 |  *
12 |  * Creates a new Flutter-based application.
13 |  *
14 |  * Returns: a new #MyApplication.
15 |  */
16 | MyApplication* my_application_new();
17 | 
18 | #endif  // FLUTTER_MY_APPLICATION_H_
19 | 
--------------------------------------------------------------------------------
/macos/.gitignore:
--------------------------------------------------------------------------------
1 | # Flutter-related
2 | **/Flutter/ephemeral/
3 | **/Pods/
4 | 
5 | # Xcode-related
6 | **/xcuserdata/
7 | 
--------------------------------------------------------------------------------
/macos/Flutter/Flutter-Debug.xcconfig:
--------------------------------------------------------------------------------
1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
2 | #include "ephemeral/Flutter-Generated.xcconfig"
3 | 
--------------------------------------------------------------------------------
/macos/Flutter/Flutter-Release.xcconfig:
--------------------------------------------------------------------------------
1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
2 | #include "ephemeral/Flutter-Generated.xcconfig"
3 | 
--------------------------------------------------------------------------------
/macos/Flutter/GeneratedPluginRegistrant.swift:
--------------------------------------------------------------------------------
 1 | //
 2 | //  Generated file. Do not edit.
 3 | //
 4 | 
 5 | import FlutterMacOS
 6 | import Foundation
 7 | 
 8 | import path_provider_macos
 9 | import url_launcher_macos
10 | 
11 | func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
12 |   PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
13 |   UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin"))
14 | }
15 | 
--------------------------------------------------------------------------------
/macos/Podfile:
--------------------------------------------------------------------------------
 1 | platform :osx, '10.11'
 2 | 
 3 | # CocoaPods analytics sends network stats synchronously affecting flutter build latency.
 4 | ENV['COCOAPODS_DISABLE_STATS'] = 'true'
 5 | 
 6 | project 'Runner', {
 7 |   'Debug' => :debug,
 8 |   'Profile' => :release,
 9 |   'Release' => :release,
10 | }
11 | 
12 | def flutter_root
13 |   generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'ephemeral', 'Flutter-Generated.xcconfig'), __FILE__)
14 |   unless File.exist?(generated_xcode_build_settings_path)
15 |     raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure \"flutter pub get\" is executed first"
16 |   end
17 | 
18 |   File.foreach(generated_xcode_build_settings_path) do |line|
19 |     matches = line.match(/FLUTTER_ROOT\=(.*)/)
20 |     return matches[1].strip if matches
21 |   end
22 |   raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Flutter-Generated.xcconfig, then run \"flutter pub get\""
23 | end
24 | 
25 | require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root)
26 | 
27 | flutter_macos_podfile_setup
28 | 
29 | target 'Runner' do
30 |   use_frameworks!
31 |   use_modular_headers!
32 | 
33 |   flutter_install_all_macos_pods File.dirname(File.realpath(__FILE__))
34 | end
35 | 
36 | post_install do |installer|
37 |   installer.pods_project.targets.each do |target|
38 |     flutter_additional_macos_build_settings(target)
39 |   end
40 | end
41 | 
--------------------------------------------------------------------------------
/macos/Podfile.lock:
--------------------------------------------------------------------------------
 1 | PODS:
 2 |   - FlutterMacOS (1.0.0)
 3 |   - path_provider_macos (0.0.1):
 4 |     - FlutterMacOS
 5 |   - url_launcher_macos (0.0.1):
 6 |     - FlutterMacOS
 7 | 
 8 | DEPENDENCIES:
 9 |   - FlutterMacOS (from `Flutter/ephemeral`)
10 |   - path_provider_macos (from `Flutter/ephemeral/.symlinks/plugins/path_provider_macos/macos`)
11 |   - url_launcher_macos (from `Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos`)
12 | 
13 | EXTERNAL SOURCES:
14 |   FlutterMacOS:
15 |     :path: Flutter/ephemeral
16 |   path_provider_macos:
17 |     :path: Flutter/ephemeral/.symlinks/plugins/path_provider_macos/macos
18 |   url_launcher_macos:
19 |     :path: Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos
20 | 
21 | SPEC CHECKSUMS:
22 |   FlutterMacOS: 57701585bf7de1b3fc2bb61f6378d73bbdea8424
23 |   path_provider_macos: 160cab0d5461f0c0e02995469a98f24bdb9a3f1f
24 |   url_launcher_macos: 45af3d61de06997666568a7149c1be98b41c95d4
25 | 
26 | PODFILE CHECKSUM: 6eac6b3292e5142cfc23bdeb71848a40ec51c14c
27 | 
28 | COCOAPODS: 1.11.2
29 | 
--------------------------------------------------------------------------------
/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 | 
2 | 
3 | 
4 | 
5 | 	IDEDidComputeMac32BitWarning
6 | 	
7 | 
8 | 
9 | 
--------------------------------------------------------------------------------
/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 |       
64 |    
65 |    
71 |       
73 |          
79 |          
80 |       
81 |    
82 |    
84 |    
85 |    
88 |    
89 | 
90 | 
--------------------------------------------------------------------------------
/macos/Runner.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
 1 | 
 2 | 
 4 |    
 6 |    
 7 |    
 9 |    
10 | 
11 | 
--------------------------------------------------------------------------------
/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 | 
2 | 
3 | 
4 | 
5 | 	IDEDidComputeMac32BitWarning
6 | 	
7 | 
8 | 
9 | 
--------------------------------------------------------------------------------
/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 | 
--------------------------------------------------------------------------------
/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 | 
--------------------------------------------------------------------------------
/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orestesgaolin/animations_samples/3680de04ece1eea8d4338f0dabf353fc8e9fec4e/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png
--------------------------------------------------------------------------------
/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orestesgaolin/animations_samples/3680de04ece1eea8d4338f0dabf353fc8e9fec4e/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png
--------------------------------------------------------------------------------
/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orestesgaolin/animations_samples/3680de04ece1eea8d4338f0dabf353fc8e9fec4e/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png
--------------------------------------------------------------------------------
/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orestesgaolin/animations_samples/3680de04ece1eea8d4338f0dabf353fc8e9fec4e/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png
--------------------------------------------------------------------------------
/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orestesgaolin/animations_samples/3680de04ece1eea8d4338f0dabf353fc8e9fec4e/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png
--------------------------------------------------------------------------------
/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orestesgaolin/animations_samples/3680de04ece1eea8d4338f0dabf353fc8e9fec4e/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png
--------------------------------------------------------------------------------
/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orestesgaolin/animations_samples/3680de04ece1eea8d4338f0dabf353fc8e9fec4e/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png
--------------------------------------------------------------------------------
/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 = animations
 9 | 
10 | // The application's bundle identifier
11 | PRODUCT_BUNDLE_IDENTIFIER = dev.roszkowski.animations
12 | 
13 | // The copyright displayed in application information
14 | PRODUCT_COPYRIGHT = Copyright © 2021 dev.roszkowski. All rights reserved.
15 | 
--------------------------------------------------------------------------------
/macos/Runner/Configs/Debug.xcconfig:
--------------------------------------------------------------------------------
1 | #include "../../Flutter/Flutter-Debug.xcconfig"
2 | #include "Warnings.xcconfig"
3 | 
--------------------------------------------------------------------------------
/macos/Runner/Configs/Release.xcconfig:
--------------------------------------------------------------------------------
1 | #include "../../Flutter/Flutter-Release.xcconfig"
2 | #include "Warnings.xcconfig"
3 | 
--------------------------------------------------------------------------------
/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 | 
--------------------------------------------------------------------------------
/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.client
10 | 	
11 | 	com.apple.security.network.server
12 | 	
13 | 
14 | 
15 | 
--------------------------------------------------------------------------------
/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 | 	LSMinimumSystemVersion
24 | 	$(MACOSX_DEPLOYMENT_TARGET)
25 | 	NSHumanReadableCopyright
26 | 	$(PRODUCT_COPYRIGHT)
27 | 	NSMainNibFile
28 | 	MainMenu
29 | 	NSPrincipalClass
30 | 	NSApplication
31 | 	LSApplicationQueriesSchemes
32 | 	
33 | 	https
34 | 	http
35 | 	
36 | 
37 | 
38 | 
--------------------------------------------------------------------------------
/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 | 
--------------------------------------------------------------------------------
/macos/Runner/Release.entitlements:
--------------------------------------------------------------------------------
1 | 
2 | 
3 | 
4 | 
5 | 	com.apple.security.app-sandbox
6 | 	
7 | 
8 | 
9 | 
--------------------------------------------------------------------------------
/pubspec.yaml:
--------------------------------------------------------------------------------
 1 | name: animations_sample
 2 | description: A new Flutter project.
 3 | 
 4 | publish_to: "none"
 5 | 
 6 | version: 1.0.0+1
 7 | 
 8 | environment:
 9 |   sdk: ">=2.12.0 <3.0.0"
10 | 
11 | dependencies:
12 |   flutter:
13 |     sdk: flutter
14 |   animations: ^2.0.0
15 |   cupertino_icons: ^1.0.2
16 |   fl_chart: ^0.40.2
17 |   funvas: ^0.1.3
18 |   fps_widget: ^1.0.1+1
19 |   gap: ^2.0.0
20 |   google_fonts: ^2.0.0
21 |   line_icons: ^2.0.1
22 |   provider: ^6.0.1
23 |   url_launcher: ^6.0.12
24 | 
25 | dev_dependencies:
26 |   flutter_test:
27 |     sdk: flutter
28 |   very_good_analysis: ^2.3.0
29 |   build_web_compilers: ^3.2.1
30 |   build_runner: ^2.1.4
31 | 
32 | flutter:
33 |   uses-material-design: true
34 |   assets:
35 |     - assets/
36 | 
--------------------------------------------------------------------------------
/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:animations_sample/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(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 | 
--------------------------------------------------------------------------------
/web/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orestesgaolin/animations_samples/3680de04ece1eea8d4338f0dabf353fc8e9fec4e/web/favicon.png
--------------------------------------------------------------------------------
/web/icons/Icon-192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orestesgaolin/animations_samples/3680de04ece1eea8d4338f0dabf353fc8e9fec4e/web/icons/Icon-192.png
--------------------------------------------------------------------------------
/web/icons/Icon-512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orestesgaolin/animations_samples/3680de04ece1eea8d4338f0dabf353fc8e9fec4e/web/icons/Icon-512.png
--------------------------------------------------------------------------------
/web/index.html:
--------------------------------------------------------------------------------
 1 | 
 2 | 
 3 | 
 4 |   
14 |   
15 | 
16 |   
17 |   
18 |   
19 | 
20 |   
21 |   
22 |   
23 |   
24 |   
25 | 
26 |   
27 |   
28 | 
29 |   animations
30 |   
31 | 
32 | 
33 |   
36 |   
43 |   
44 | 
45 | 
46 | 
--------------------------------------------------------------------------------
/web/manifest.json:
--------------------------------------------------------------------------------
 1 | {
 2 |     "name": "animations",
 3 |     "short_name": "animations",
 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 | }
24 | 
--------------------------------------------------------------------------------
/windows/.gitignore:
--------------------------------------------------------------------------------
 1 | flutter/ephemeral/
 2 | 
 3 | # Visual Studio user-specific files.
 4 | *.suo
 5 | *.user
 6 | *.userosscache
 7 | *.sln.docstates
 8 | 
 9 | # Visual Studio build-related files.
10 | x64/
11 | x86/
12 | 
13 | # Visual Studio cache files
14 | # files ending in .cache can be ignored
15 | *.[Cc]ache
16 | # but keep track of directories ending in .cache
17 | !*.[Cc]ache/
18 | 
--------------------------------------------------------------------------------
/windows/CMakeLists.txt:
--------------------------------------------------------------------------------
 1 | cmake_minimum_required(VERSION 3.15)
 2 | project(animations LANGUAGES CXX)
 3 | 
 4 | set(BINARY_NAME "animations")
 5 | 
 6 | cmake_policy(SET CMP0063 NEW)
 7 | 
 8 | set(CMAKE_INSTALL_RPATH "$ORIGIN/lib")
 9 | 
10 | # Configure build options.
11 | get_property(IS_MULTICONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
12 | if(IS_MULTICONFIG)
13 |   set(CMAKE_CONFIGURATION_TYPES "Debug;Profile;Release"
14 |     CACHE STRING "" FORCE)
15 | else()
16 |   if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
17 |     set(CMAKE_BUILD_TYPE "Debug" CACHE
18 |       STRING "Flutter build mode" FORCE)
19 |     set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS
20 |       "Debug" "Profile" "Release")
21 |   endif()
22 | endif()
23 | 
24 | set(CMAKE_EXE_LINKER_FLAGS_PROFILE "${CMAKE_EXE_LINKER_FLAGS_RELEASE}")
25 | set(CMAKE_SHARED_LINKER_FLAGS_PROFILE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE}")
26 | set(CMAKE_C_FLAGS_PROFILE "${CMAKE_C_FLAGS_RELEASE}")
27 | set(CMAKE_CXX_FLAGS_PROFILE "${CMAKE_CXX_FLAGS_RELEASE}")
28 | 
29 | # Use Unicode for all projects.
30 | add_definitions(-DUNICODE -D_UNICODE)
31 | 
32 | # Compilation settings that should be applied to most targets.
33 | function(APPLY_STANDARD_SETTINGS TARGET)
34 |   target_compile_features(${TARGET} PUBLIC cxx_std_17)
35 |   target_compile_options(${TARGET} PRIVATE /W4 /WX /wd"4100")
36 |   target_compile_options(${TARGET} PRIVATE /EHsc)
37 |   target_compile_definitions(${TARGET} PRIVATE "_HAS_EXCEPTIONS=0")
38 |   target_compile_definitions(${TARGET} PRIVATE "$<$:_DEBUG>")
39 | endfunction()
40 | 
41 | set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter")
42 | 
43 | # Flutter library and tool build rules.
44 | add_subdirectory(${FLUTTER_MANAGED_DIR})
45 | 
46 | # Application build
47 | add_subdirectory("runner")
48 | 
49 | # Generated plugin build rules, which manage building the plugins and adding
50 | # them to the application.
51 | include(flutter/generated_plugins.cmake)
52 | 
53 | 
54 | # === Installation ===
55 | # Support files are copied into place next to the executable, so that it can
56 | # run in place. This is done instead of making a separate bundle (as on Linux)
57 | # so that building and running from within Visual Studio will work.
58 | set(BUILD_BUNDLE_DIR "$")
59 | # Make the "install" step default, as it's required to run.
60 | set(CMAKE_VS_INCLUDE_INSTALL_TO_DEFAULT_BUILD 1)
61 | if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
62 |   set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE)
63 | endif()
64 | 
65 | set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data")
66 | set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}")
67 | 
68 | install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}"
69 |   COMPONENT Runtime)
70 | 
71 | install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}"
72 |   COMPONENT Runtime)
73 | 
74 | install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
75 |   COMPONENT Runtime)
76 | 
77 | if(PLUGIN_BUNDLED_LIBRARIES)
78 |   install(FILES "${PLUGIN_BUNDLED_LIBRARIES}"
79 |     DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
80 |     COMPONENT Runtime)
81 | endif()
82 | 
83 | # Fully re-copy the assets directory on each build to avoid having stale files
84 | # from a previous install.
85 | set(FLUTTER_ASSET_DIR_NAME "flutter_assets")
86 | install(CODE "
87 |   file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\")
88 |   " COMPONENT Runtime)
89 | install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}"
90 |   DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime)
91 | 
92 | # Install the AOT library on non-Debug builds only.
93 | install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}"
94 |   CONFIGURATIONS Profile;Release
95 |   COMPONENT Runtime)
96 | 
--------------------------------------------------------------------------------
/windows/flutter/CMakeLists.txt:
--------------------------------------------------------------------------------
  1 | cmake_minimum_required(VERSION 3.15)
  2 | 
  3 | set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral")
  4 | 
  5 | # Configuration provided via flutter tool.
  6 | include(${EPHEMERAL_DIR}/generated_config.cmake)
  7 | 
  8 | # TODO: Move the rest of this into files in ephemeral. See
  9 | # https://github.com/flutter/flutter/issues/57146.
 10 | set(WRAPPER_ROOT "${EPHEMERAL_DIR}/cpp_client_wrapper")
 11 | 
 12 | # === Flutter Library ===
 13 | set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/flutter_windows.dll")
 14 | 
 15 | # Published to parent scope for install step.
 16 | set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE)
 17 | set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE)
 18 | set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE)
 19 | set(AOT_LIBRARY "${PROJECT_DIR}/build/windows/app.so" PARENT_SCOPE)
 20 | 
 21 | list(APPEND FLUTTER_LIBRARY_HEADERS
 22 |   "flutter_export.h"
 23 |   "flutter_windows.h"
 24 |   "flutter_messenger.h"
 25 |   "flutter_plugin_registrar.h"
 26 |   "flutter_texture_registrar.h"
 27 | )
 28 | list(TRANSFORM FLUTTER_LIBRARY_HEADERS PREPEND "${EPHEMERAL_DIR}/")
 29 | add_library(flutter INTERFACE)
 30 | target_include_directories(flutter INTERFACE
 31 |   "${EPHEMERAL_DIR}"
 32 | )
 33 | target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}.lib")
 34 | add_dependencies(flutter flutter_assemble)
 35 | 
 36 | # === Wrapper ===
 37 | list(APPEND CPP_WRAPPER_SOURCES_CORE
 38 |   "core_implementations.cc"
 39 |   "standard_codec.cc"
 40 | )
 41 | list(TRANSFORM CPP_WRAPPER_SOURCES_CORE PREPEND "${WRAPPER_ROOT}/")
 42 | list(APPEND CPP_WRAPPER_SOURCES_PLUGIN
 43 |   "plugin_registrar.cc"
 44 | )
 45 | list(TRANSFORM CPP_WRAPPER_SOURCES_PLUGIN PREPEND "${WRAPPER_ROOT}/")
 46 | list(APPEND CPP_WRAPPER_SOURCES_APP
 47 |   "flutter_engine.cc"
 48 |   "flutter_view_controller.cc"
 49 | )
 50 | list(TRANSFORM CPP_WRAPPER_SOURCES_APP PREPEND "${WRAPPER_ROOT}/")
 51 | 
 52 | # Wrapper sources needed for a plugin.
 53 | add_library(flutter_wrapper_plugin STATIC
 54 |   ${CPP_WRAPPER_SOURCES_CORE}
 55 |   ${CPP_WRAPPER_SOURCES_PLUGIN}
 56 | )
 57 | apply_standard_settings(flutter_wrapper_plugin)
 58 | set_target_properties(flutter_wrapper_plugin PROPERTIES
 59 |   POSITION_INDEPENDENT_CODE ON)
 60 | set_target_properties(flutter_wrapper_plugin PROPERTIES
 61 |   CXX_VISIBILITY_PRESET hidden)
 62 | target_link_libraries(flutter_wrapper_plugin PUBLIC flutter)
 63 | target_include_directories(flutter_wrapper_plugin PUBLIC
 64 |   "${WRAPPER_ROOT}/include"
 65 | )
 66 | add_dependencies(flutter_wrapper_plugin flutter_assemble)
 67 | 
 68 | # Wrapper sources needed for the runner.
 69 | add_library(flutter_wrapper_app STATIC
 70 |   ${CPP_WRAPPER_SOURCES_CORE}
 71 |   ${CPP_WRAPPER_SOURCES_APP}
 72 | )
 73 | apply_standard_settings(flutter_wrapper_app)
 74 | target_link_libraries(flutter_wrapper_app PUBLIC flutter)
 75 | target_include_directories(flutter_wrapper_app PUBLIC
 76 |   "${WRAPPER_ROOT}/include"
 77 | )
 78 | add_dependencies(flutter_wrapper_app flutter_assemble)
 79 | 
 80 | # === Flutter tool backend ===
 81 | # _phony_ is a non-existent file to force this command to run every time,
 82 | # since currently there's no way to get a full input/output list from the
 83 | # flutter tool.
 84 | set(PHONY_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/_phony_")
 85 | set_source_files_properties("${PHONY_OUTPUT}" PROPERTIES SYMBOLIC TRUE)
 86 | add_custom_command(
 87 |   OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS}
 88 |     ${CPP_WRAPPER_SOURCES_CORE} ${CPP_WRAPPER_SOURCES_PLUGIN}
 89 |     ${CPP_WRAPPER_SOURCES_APP}
 90 |     ${PHONY_OUTPUT}
 91 |   COMMAND ${CMAKE_COMMAND} -E env
 92 |     ${FLUTTER_TOOL_ENVIRONMENT}
 93 |     "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.bat"
 94 |       windows-x64 $
 95 |   VERBATIM
 96 | )
 97 | add_custom_target(flutter_assemble DEPENDS
 98 |   "${FLUTTER_LIBRARY}"
 99 |   ${FLUTTER_LIBRARY_HEADERS}
100 |   ${CPP_WRAPPER_SOURCES_CORE}
101 |   ${CPP_WRAPPER_SOURCES_PLUGIN}
102 |   ${CPP_WRAPPER_SOURCES_APP}
103 | )
104 | 
--------------------------------------------------------------------------------
/windows/flutter/generated_plugin_registrant.cc:
--------------------------------------------------------------------------------
 1 | //
 2 | //  Generated file. Do not edit.
 3 | //
 4 | 
 5 | // clang-format off
 6 | 
 7 | #include "generated_plugin_registrant.h"
 8 | 
 9 | #include 
10 | 
11 | void RegisterPlugins(flutter::PluginRegistry* registry) {
12 |   UrlLauncherWindowsRegisterWithRegistrar(
13 |       registry->GetRegistrarForPlugin("UrlLauncherWindows"));
14 | }
15 | 
--------------------------------------------------------------------------------
/windows/flutter/generated_plugin_registrant.h:
--------------------------------------------------------------------------------
 1 | //
 2 | //  Generated file. Do not edit.
 3 | //
 4 | 
 5 | // clang-format off
 6 | 
 7 | #ifndef GENERATED_PLUGIN_REGISTRANT_
 8 | #define GENERATED_PLUGIN_REGISTRANT_
 9 | 
10 | #include 
11 | 
12 | // Registers Flutter plugins.
13 | void RegisterPlugins(flutter::PluginRegistry* registry);
14 | 
15 | #endif  // GENERATED_PLUGIN_REGISTRANT_
16 | 
--------------------------------------------------------------------------------
/windows/flutter/generated_plugins.cmake:
--------------------------------------------------------------------------------
 1 | #
 2 | # Generated file, do not edit.
 3 | #
 4 | 
 5 | list(APPEND FLUTTER_PLUGIN_LIST
 6 |   url_launcher_windows
 7 | )
 8 | 
 9 | set(PLUGIN_BUNDLED_LIBRARIES)
10 | 
11 | foreach(plugin ${FLUTTER_PLUGIN_LIST})
12 |   add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/windows plugins/${plugin})
13 |   target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin)
14 |   list(APPEND PLUGIN_BUNDLED_LIBRARIES $)
15 |   list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries})
16 | endforeach(plugin)
17 | 
--------------------------------------------------------------------------------
/windows/runner/CMakeLists.txt:
--------------------------------------------------------------------------------
 1 | cmake_minimum_required(VERSION 3.15)
 2 | project(runner LANGUAGES CXX)
 3 | 
 4 | add_executable(${BINARY_NAME} WIN32
 5 |   "flutter_window.cpp"
 6 |   "main.cpp"
 7 |   "run_loop.cpp"
 8 |   "utils.cpp"
 9 |   "win32_window.cpp"
10 |   "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc"
11 |   "Runner.rc"
12 |   "runner.exe.manifest"
13 | )
14 | apply_standard_settings(${BINARY_NAME})
15 | target_compile_definitions(${BINARY_NAME} PRIVATE "NOMINMAX")
16 | target_link_libraries(${BINARY_NAME} PRIVATE flutter flutter_wrapper_app)
17 | target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}")
18 | add_dependencies(${BINARY_NAME} flutter_assemble)
19 | 
--------------------------------------------------------------------------------
/windows/runner/Runner.rc:
--------------------------------------------------------------------------------
  1 | // Microsoft Visual C++ generated resource script.
  2 | //
  3 | #pragma code_page(65001)
  4 | #include "resource.h"
  5 | 
  6 | #define APSTUDIO_READONLY_SYMBOLS
  7 | /////////////////////////////////////////////////////////////////////////////
  8 | //
  9 | // Generated from the TEXTINCLUDE 2 resource.
 10 | //
 11 | #include "winres.h"
 12 | 
 13 | /////////////////////////////////////////////////////////////////////////////
 14 | #undef APSTUDIO_READONLY_SYMBOLS
 15 | 
 16 | /////////////////////////////////////////////////////////////////////////////
 17 | // English (United States) resources
 18 | 
 19 | #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
 20 | LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
 21 | 
 22 | #ifdef APSTUDIO_INVOKED
 23 | /////////////////////////////////////////////////////////////////////////////
 24 | //
 25 | // TEXTINCLUDE
 26 | //
 27 | 
 28 | 1 TEXTINCLUDE
 29 | BEGIN
 30 |     "resource.h\0"
 31 | END
 32 | 
 33 | 2 TEXTINCLUDE
 34 | BEGIN
 35 |     "#include ""winres.h""\r\n"
 36 |     "\0"
 37 | END
 38 | 
 39 | 3 TEXTINCLUDE
 40 | BEGIN
 41 |     "\r\n"
 42 |     "\0"
 43 | END
 44 | 
 45 | #endif    // APSTUDIO_INVOKED
 46 | 
 47 | 
 48 | /////////////////////////////////////////////////////////////////////////////
 49 | //
 50 | // Icon
 51 | //
 52 | 
 53 | // Icon with lowest ID value placed first to ensure application icon
 54 | // remains consistent on all systems.
 55 | IDI_APP_ICON            ICON                    "resources\\app_icon.ico"
 56 | 
 57 | 
 58 | /////////////////////////////////////////////////////////////////////////////
 59 | //
 60 | // Version
 61 | //
 62 | 
 63 | #ifdef FLUTTER_BUILD_NUMBER
 64 | #define VERSION_AS_NUMBER FLUTTER_BUILD_NUMBER
 65 | #else
 66 | #define VERSION_AS_NUMBER 1,0,0
 67 | #endif
 68 | 
 69 | #ifdef FLUTTER_BUILD_NAME
 70 | #define VERSION_AS_STRING #FLUTTER_BUILD_NAME
 71 | #else
 72 | #define VERSION_AS_STRING "1.0.0"
 73 | #endif
 74 | 
 75 | VS_VERSION_INFO VERSIONINFO
 76 |  FILEVERSION VERSION_AS_NUMBER
 77 |  PRODUCTVERSION VERSION_AS_NUMBER
 78 |  FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
 79 | #ifdef _DEBUG
 80 |  FILEFLAGS VS_FF_DEBUG
 81 | #else
 82 |  FILEFLAGS 0x0L
 83 | #endif
 84 |  FILEOS VOS__WINDOWS32
 85 |  FILETYPE VFT_APP
 86 |  FILESUBTYPE 0x0L
 87 | BEGIN
 88 |     BLOCK "StringFileInfo"
 89 |     BEGIN
 90 |         BLOCK "040904e4"
 91 |         BEGIN
 92 |             VALUE "CompanyName", "dev.roszkowski" "\0"
 93 |             VALUE "FileDescription", "A new Flutter project." "\0"
 94 |             VALUE "FileVersion", VERSION_AS_STRING "\0"
 95 |             VALUE "InternalName", "animations" "\0"
 96 |             VALUE "LegalCopyright", "Copyright (C) 2021 dev.roszkowski. All rights reserved." "\0"
 97 |             VALUE "OriginalFilename", "animations.exe" "\0"
 98 |             VALUE "ProductName", "animations" "\0"
 99 |             VALUE "ProductVersion", VERSION_AS_STRING "\0"
100 |         END
101 |     END
102 |     BLOCK "VarFileInfo"
103 |     BEGIN
104 |         VALUE "Translation", 0x409, 1252
105 |     END
106 | END
107 | 
108 | #endif    // English (United States) resources
109 | /////////////////////////////////////////////////////////////////////////////
110 | 
111 | 
112 | 
113 | #ifndef APSTUDIO_INVOKED
114 | /////////////////////////////////////////////////////////////////////////////
115 | //
116 | // Generated from the TEXTINCLUDE 3 resource.
117 | //
118 | 
119 | 
120 | /////////////////////////////////////////////////////////////////////////////
121 | #endif    // not APSTUDIO_INVOKED
122 | 
--------------------------------------------------------------------------------
/windows/runner/flutter_window.cpp:
--------------------------------------------------------------------------------
 1 | #include "flutter_window.h"
 2 | 
 3 | #include 
 4 | 
 5 | #include "flutter/generated_plugin_registrant.h"
 6 | 
 7 | FlutterWindow::FlutterWindow(RunLoop* run_loop,
 8 |                              const flutter::DartProject& project)
 9 |     : run_loop_(run_loop), project_(project) {}
10 | 
11 | FlutterWindow::~FlutterWindow() {}
12 | 
13 | bool FlutterWindow::OnCreate() {
14 |   if (!Win32Window::OnCreate()) {
15 |     return false;
16 |   }
17 | 
18 |   RECT frame = GetClientArea();
19 | 
20 |   // The size here must match the window dimensions to avoid unnecessary surface
21 |   // creation / destruction in the startup path.
22 |   flutter_controller_ = std::make_unique(
23 |       frame.right - frame.left, frame.bottom - frame.top, project_);
24 |   // Ensure that basic setup of the controller was successful.
25 |   if (!flutter_controller_->engine() || !flutter_controller_->view()) {
26 |     return false;
27 |   }
28 |   RegisterPlugins(flutter_controller_->engine());
29 |   run_loop_->RegisterFlutterInstance(flutter_controller_->engine());
30 |   SetChildContent(flutter_controller_->view()->GetNativeWindow());
31 |   return true;
32 | }
33 | 
34 | void FlutterWindow::OnDestroy() {
35 |   if (flutter_controller_) {
36 |     run_loop_->UnregisterFlutterInstance(flutter_controller_->engine());
37 |     flutter_controller_ = nullptr;
38 |   }
39 | 
40 |   Win32Window::OnDestroy();
41 | }
42 | 
43 | LRESULT
44 | FlutterWindow::MessageHandler(HWND hwnd, UINT const message,
45 |                               WPARAM const wparam,
46 |                               LPARAM const lparam) noexcept {
47 |   // Give Flutter, including plugins, an opporutunity to handle window messages.
48 |   if (flutter_controller_) {
49 |     std::optional result =
50 |         flutter_controller_->HandleTopLevelWindowProc(hwnd, message, wparam,
51 |                                                       lparam);
52 |     if (result) {
53 |       return *result;
54 |     }
55 |   }
56 | 
57 |   switch (message) {
58 |     case WM_FONTCHANGE:
59 |       flutter_controller_->engine()->ReloadSystemFonts();
60 |       break;
61 |   }
62 | 
63 |   return Win32Window::MessageHandler(hwnd, message, wparam, lparam);
64 | }
65 | 
--------------------------------------------------------------------------------
/windows/runner/flutter_window.h:
--------------------------------------------------------------------------------
 1 | #ifndef RUNNER_FLUTTER_WINDOW_H_
 2 | #define RUNNER_FLUTTER_WINDOW_H_
 3 | 
 4 | #include 
 5 | #include 
 6 | 
 7 | #include 
 8 | 
 9 | #include "run_loop.h"
10 | #include "win32_window.h"
11 | 
12 | // A window that does nothing but host a Flutter view.
13 | class FlutterWindow : public Win32Window {
14 |  public:
15 |   // Creates a new FlutterWindow driven by the |run_loop|, hosting a
16 |   // Flutter view running |project|.
17 |   explicit FlutterWindow(RunLoop* run_loop,
18 |                          const flutter::DartProject& project);
19 |   virtual ~FlutterWindow();
20 | 
21 |  protected:
22 |   // Win32Window:
23 |   bool OnCreate() override;
24 |   void OnDestroy() override;
25 |   LRESULT MessageHandler(HWND window, UINT const message, WPARAM const wparam,
26 |                          LPARAM const lparam) noexcept override;
27 | 
28 |  private:
29 |   // The run loop driving events for this window.
30 |   RunLoop* run_loop_;
31 | 
32 |   // The project to run.
33 |   flutter::DartProject project_;
34 | 
35 |   // The Flutter instance hosted by this window.
36 |   std::unique_ptr flutter_controller_;
37 | };
38 | 
39 | #endif  // RUNNER_FLUTTER_WINDOW_H_
40 | 
--------------------------------------------------------------------------------
/windows/runner/main.cpp:
--------------------------------------------------------------------------------
 1 | #include 
 2 | #include 
 3 | #include 
 4 | 
 5 | #include "flutter_window.h"
 6 | #include "run_loop.h"
 7 | #include "utils.h"
 8 | 
 9 | int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev,
10 |                       _In_ wchar_t *command_line, _In_ int show_command) {
11 |   // Attach to console when present (e.g., 'flutter run') or create a
12 |   // new console when running with a debugger.
13 |   if (!::AttachConsole(ATTACH_PARENT_PROCESS) && ::IsDebuggerPresent()) {
14 |     CreateAndAttachConsole();
15 |   }
16 | 
17 |   // Initialize COM, so that it is available for use in the library and/or
18 |   // plugins.
19 |   ::CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);
20 | 
21 |   RunLoop run_loop;
22 | 
23 |   flutter::DartProject project(L"data");
24 | 
25 |   std::vector command_line_arguments =
26 |       GetCommandLineArguments();
27 | 
28 |   project.set_dart_entrypoint_arguments(std::move(command_line_arguments));
29 | 
30 |   FlutterWindow window(&run_loop, project);
31 |   Win32Window::Point origin(10, 10);
32 |   Win32Window::Size size(1280, 720);
33 |   if (!window.CreateAndShow(L"animations", origin, size)) {
34 |     return EXIT_FAILURE;
35 |   }
36 |   window.SetQuitOnClose(true);
37 | 
38 |   run_loop.Run();
39 | 
40 |   ::CoUninitialize();
41 |   return EXIT_SUCCESS;
42 | }
43 | 
--------------------------------------------------------------------------------
/windows/runner/resource.h:
--------------------------------------------------------------------------------
 1 | //{{NO_DEPENDENCIES}}
 2 | // Microsoft Visual C++ generated include file.
 3 | // Used by Runner.rc
 4 | //
 5 | #define IDI_APP_ICON                    101
 6 | 
 7 | // Next default values for new objects
 8 | //
 9 | #ifdef APSTUDIO_INVOKED
10 | #ifndef APSTUDIO_READONLY_SYMBOLS
11 | #define _APS_NEXT_RESOURCE_VALUE        102
12 | #define _APS_NEXT_COMMAND_VALUE         40001
13 | #define _APS_NEXT_CONTROL_VALUE         1001
14 | #define _APS_NEXT_SYMED_VALUE           101
15 | #endif
16 | #endif
17 | 
--------------------------------------------------------------------------------
/windows/runner/resources/app_icon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orestesgaolin/animations_samples/3680de04ece1eea8d4338f0dabf353fc8e9fec4e/windows/runner/resources/app_icon.ico
--------------------------------------------------------------------------------
/windows/runner/run_loop.cpp:
--------------------------------------------------------------------------------
 1 | #include "run_loop.h"
 2 | 
 3 | #include 
 4 | 
 5 | #include 
 6 | 
 7 | RunLoop::RunLoop() {}
 8 | 
 9 | RunLoop::~RunLoop() {}
10 | 
11 | void RunLoop::Run() {
12 |   bool keep_running = true;
13 |   TimePoint next_flutter_event_time = TimePoint::clock::now();
14 |   while (keep_running) {
15 |     std::chrono::nanoseconds wait_duration =
16 |         std::max(std::chrono::nanoseconds(0),
17 |                  next_flutter_event_time - TimePoint::clock::now());
18 |     ::MsgWaitForMultipleObjects(
19 |         0, nullptr, FALSE, static_cast(wait_duration.count() / 1000),
20 |         QS_ALLINPUT);
21 |     bool processed_events = false;
22 |     MSG message;
23 |     // All pending Windows messages must be processed; MsgWaitForMultipleObjects
24 |     // won't return again for items left in the queue after PeekMessage.
25 |     while (::PeekMessage(&message, nullptr, 0, 0, PM_REMOVE)) {
26 |       processed_events = true;
27 |       if (message.message == WM_QUIT) {
28 |         keep_running = false;
29 |         break;
30 |       }
31 |       ::TranslateMessage(&message);
32 |       ::DispatchMessage(&message);
33 |       // Allow Flutter to process messages each time a Windows message is
34 |       // processed, to prevent starvation.
35 |       next_flutter_event_time =
36 |           std::min(next_flutter_event_time, ProcessFlutterMessages());
37 |     }
38 |     // If the PeekMessage loop didn't run, process Flutter messages.
39 |     if (!processed_events) {
40 |       next_flutter_event_time =
41 |           std::min(next_flutter_event_time, ProcessFlutterMessages());
42 |     }
43 |   }
44 | }
45 | 
46 | void RunLoop::RegisterFlutterInstance(
47 |     flutter::FlutterEngine* flutter_instance) {
48 |   flutter_instances_.insert(flutter_instance);
49 | }
50 | 
51 | void RunLoop::UnregisterFlutterInstance(
52 |     flutter::FlutterEngine* flutter_instance) {
53 |   flutter_instances_.erase(flutter_instance);
54 | }
55 | 
56 | RunLoop::TimePoint RunLoop::ProcessFlutterMessages() {
57 |   TimePoint next_event_time = TimePoint::max();
58 |   for (auto instance : flutter_instances_) {
59 |     std::chrono::nanoseconds wait_duration = instance->ProcessMessages();
60 |     if (wait_duration != std::chrono::nanoseconds::max()) {
61 |       next_event_time =
62 |           std::min(next_event_time, TimePoint::clock::now() + wait_duration);
63 |     }
64 |   }
65 |   return next_event_time;
66 | }
67 | 
--------------------------------------------------------------------------------
/windows/runner/run_loop.h:
--------------------------------------------------------------------------------
 1 | #ifndef RUNNER_RUN_LOOP_H_
 2 | #define RUNNER_RUN_LOOP_H_
 3 | 
 4 | #include 
 5 | 
 6 | #include 
 7 | #include 
 8 | 
 9 | // A runloop that will service events for Flutter instances as well
10 | // as native messages.
11 | class RunLoop {
12 |  public:
13 |   RunLoop();
14 |   ~RunLoop();
15 | 
16 |   // Prevent copying
17 |   RunLoop(RunLoop const&) = delete;
18 |   RunLoop& operator=(RunLoop const&) = delete;
19 | 
20 |   // Runs the run loop until the application quits.
21 |   void Run();
22 | 
23 |   // Registers the given Flutter instance for event servicing.
24 |   void RegisterFlutterInstance(
25 |       flutter::FlutterEngine* flutter_instance);
26 | 
27 |   // Unregisters the given Flutter instance from event servicing.
28 |   void UnregisterFlutterInstance(
29 |       flutter::FlutterEngine* flutter_instance);
30 | 
31 |  private:
32 |   using TimePoint = std::chrono::steady_clock::time_point;
33 | 
34 |   // Processes all currently pending messages for registered Flutter instances.
35 |   TimePoint ProcessFlutterMessages();
36 | 
37 |   std::set flutter_instances_;
38 | };
39 | 
40 | #endif  // RUNNER_RUN_LOOP_H_
41 | 
--------------------------------------------------------------------------------
/windows/runner/runner.exe.manifest:
--------------------------------------------------------------------------------
 1 | 
 2 | 
 3 |   
 4 |     
 5 |       PerMonitorV2
 6 |     
 7 |   
 8 |   
 9 |     
10 |       
11 |       
12 |       
13 |       
14 |       
15 |       
16 |       
17 |       
18 |     
19 |   
20 | 
21 | 
--------------------------------------------------------------------------------
/windows/runner/utils.cpp:
--------------------------------------------------------------------------------
 1 | #include "utils.h"
 2 | 
 3 | #include 
 4 | #include 
 5 | #include 
 6 | #include 
 7 | 
 8 | #include 
 9 | 
10 | void CreateAndAttachConsole() {
11 |   if (::AllocConsole()) {
12 |     FILE *unused;
13 |     if (freopen_s(&unused, "CONOUT$", "w", stdout)) {
14 |       _dup2(_fileno(stdout), 1);
15 |     }
16 |     if (freopen_s(&unused, "CONOUT$", "w", stderr)) {
17 |       _dup2(_fileno(stdout), 2);
18 |     }
19 |     std::ios::sync_with_stdio();
20 |     FlutterDesktopResyncOutputStreams();
21 |   }
22 | }
23 | 
24 | std::vector GetCommandLineArguments() {
25 |   // Convert the UTF-16 command line arguments to UTF-8 for the Engine to use.
26 |   int argc;
27 |   wchar_t** argv = ::CommandLineToArgvW(::GetCommandLineW(), &argc);
28 |   if (argv == nullptr) {
29 |     return std::vector();
30 |   }
31 | 
32 |   std::vector command_line_arguments;
33 | 
34 |   // Skip the first argument as it's the binary name.
35 |   for (int i = 1; i < argc; i++) {
36 |     command_line_arguments.push_back(Utf8FromUtf16(argv[i]));
37 |   }
38 | 
39 |   ::LocalFree(argv);
40 | 
41 |   return command_line_arguments;
42 | }
43 | 
44 | std::string Utf8FromUtf16(const wchar_t* utf16_string) {
45 |   if (utf16_string == nullptr) {
46 |     return std::string();
47 |   }
48 |   int target_length = ::WideCharToMultiByte(
49 |       CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string,
50 |       -1, nullptr, 0, nullptr, nullptr);
51 |   if (target_length == 0) {
52 |     return std::string();
53 |   }
54 |   std::string utf8_string;
55 |   utf8_string.resize(target_length);
56 |   int converted_length = ::WideCharToMultiByte(
57 |       CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string,
58 |       -1, utf8_string.data(),
59 |       target_length, nullptr, nullptr);
60 |   if (converted_length == 0) {
61 |     return std::string();
62 |   }
63 |   return utf8_string;
64 | }
65 | 
--------------------------------------------------------------------------------
/windows/runner/utils.h:
--------------------------------------------------------------------------------
 1 | #ifndef RUNNER_UTILS_H_
 2 | #define RUNNER_UTILS_H_
 3 | 
 4 | #include 
 5 | #include 
 6 | 
 7 | // Creates a console for the process, and redirects stdout and stderr to
 8 | // it for both the runner and the Flutter library.
 9 | void CreateAndAttachConsole();
10 | 
11 | // Takes a null-terminated wchar_t* encoded in UTF-16 and returns a std::string
12 | // encoded in UTF-8. Returns an empty std::string on failure.
13 | std::string Utf8FromUtf16(const wchar_t* utf16_string);
14 | 
15 | // Gets the command line arguments passed in as a std::vector,
16 | // encoded in UTF-8. Returns an empty std::vector on failure.
17 | std::vector GetCommandLineArguments();
18 | 
19 | #endif  // RUNNER_UTILS_H_
20 | 
--------------------------------------------------------------------------------
/windows/runner/win32_window.cpp:
--------------------------------------------------------------------------------
  1 | #include "win32_window.h"
  2 | 
  3 | #include 
  4 | 
  5 | #include "resource.h"
  6 | 
  7 | namespace {
  8 | 
  9 | constexpr const wchar_t kWindowClassName[] = L"FLUTTER_RUNNER_WIN32_WINDOW";
 10 | 
 11 | // The number of Win32Window objects that currently exist.
 12 | static int g_active_window_count = 0;
 13 | 
 14 | using EnableNonClientDpiScaling = BOOL __stdcall(HWND hwnd);
 15 | 
 16 | // Scale helper to convert logical scaler values to physical using passed in
 17 | // scale factor
 18 | int Scale(int source, double scale_factor) {
 19 |   return static_cast(source * scale_factor);
 20 | }
 21 | 
 22 | // Dynamically loads the |EnableNonClientDpiScaling| from the User32 module.
 23 | // This API is only needed for PerMonitor V1 awareness mode.
 24 | void EnableFullDpiSupportIfAvailable(HWND hwnd) {
 25 |   HMODULE user32_module = LoadLibraryA("User32.dll");
 26 |   if (!user32_module) {
 27 |     return;
 28 |   }
 29 |   auto enable_non_client_dpi_scaling =
 30 |       reinterpret_cast(
 31 |           GetProcAddress(user32_module, "EnableNonClientDpiScaling"));
 32 |   if (enable_non_client_dpi_scaling != nullptr) {
 33 |     enable_non_client_dpi_scaling(hwnd);
 34 |     FreeLibrary(user32_module);
 35 |   }
 36 | }
 37 | 
 38 | }  // namespace
 39 | 
 40 | // Manages the Win32Window's window class registration.
 41 | class WindowClassRegistrar {
 42 |  public:
 43 |   ~WindowClassRegistrar() = default;
 44 | 
 45 |   // Returns the singleton registar instance.
 46 |   static WindowClassRegistrar* GetInstance() {
 47 |     if (!instance_) {
 48 |       instance_ = new WindowClassRegistrar();
 49 |     }
 50 |     return instance_;
 51 |   }
 52 | 
 53 |   // Returns the name of the window class, registering the class if it hasn't
 54 |   // previously been registered.
 55 |   const wchar_t* GetWindowClass();
 56 | 
 57 |   // Unregisters the window class. Should only be called if there are no
 58 |   // instances of the window.
 59 |   void UnregisterWindowClass();
 60 | 
 61 |  private:
 62 |   WindowClassRegistrar() = default;
 63 | 
 64 |   static WindowClassRegistrar* instance_;
 65 | 
 66 |   bool class_registered_ = false;
 67 | };
 68 | 
 69 | WindowClassRegistrar* WindowClassRegistrar::instance_ = nullptr;
 70 | 
 71 | const wchar_t* WindowClassRegistrar::GetWindowClass() {
 72 |   if (!class_registered_) {
 73 |     WNDCLASS window_class{};
 74 |     window_class.hCursor = LoadCursor(nullptr, IDC_ARROW);
 75 |     window_class.lpszClassName = kWindowClassName;
 76 |     window_class.style = CS_HREDRAW | CS_VREDRAW;
 77 |     window_class.cbClsExtra = 0;
 78 |     window_class.cbWndExtra = 0;
 79 |     window_class.hInstance = GetModuleHandle(nullptr);
 80 |     window_class.hIcon =
 81 |         LoadIcon(window_class.hInstance, MAKEINTRESOURCE(IDI_APP_ICON));
 82 |     window_class.hbrBackground = 0;
 83 |     window_class.lpszMenuName = nullptr;
 84 |     window_class.lpfnWndProc = Win32Window::WndProc;
 85 |     RegisterClass(&window_class);
 86 |     class_registered_ = true;
 87 |   }
 88 |   return kWindowClassName;
 89 | }
 90 | 
 91 | void WindowClassRegistrar::UnregisterWindowClass() {
 92 |   UnregisterClass(kWindowClassName, nullptr);
 93 |   class_registered_ = false;
 94 | }
 95 | 
 96 | Win32Window::Win32Window() {
 97 |   ++g_active_window_count;
 98 | }
 99 | 
100 | Win32Window::~Win32Window() {
101 |   --g_active_window_count;
102 |   Destroy();
103 | }
104 | 
105 | bool Win32Window::CreateAndShow(const std::wstring& title,
106 |                                 const Point& origin,
107 |                                 const Size& size) {
108 |   Destroy();
109 | 
110 |   const wchar_t* window_class =
111 |       WindowClassRegistrar::GetInstance()->GetWindowClass();
112 | 
113 |   const POINT target_point = {static_cast(origin.x),
114 |                               static_cast(origin.y)};
115 |   HMONITOR monitor = MonitorFromPoint(target_point, MONITOR_DEFAULTTONEAREST);
116 |   UINT dpi = FlutterDesktopGetDpiForMonitor(monitor);
117 |   double scale_factor = dpi / 96.0;
118 | 
119 |   HWND window = CreateWindow(
120 |       window_class, title.c_str(), WS_OVERLAPPEDWINDOW | WS_VISIBLE,
121 |       Scale(origin.x, scale_factor), Scale(origin.y, scale_factor),
122 |       Scale(size.width, scale_factor), Scale(size.height, scale_factor),
123 |       nullptr, nullptr, GetModuleHandle(nullptr), this);
124 | 
125 |   if (!window) {
126 |     return false;
127 |   }
128 | 
129 |   return OnCreate();
130 | }
131 | 
132 | // static
133 | LRESULT CALLBACK Win32Window::WndProc(HWND const window,
134 |                                       UINT const message,
135 |                                       WPARAM const wparam,
136 |                                       LPARAM const lparam) noexcept {
137 |   if (message == WM_NCCREATE) {
138 |     auto window_struct = reinterpret_cast(lparam);
139 |     SetWindowLongPtr(window, GWLP_USERDATA,
140 |                      reinterpret_cast(window_struct->lpCreateParams));
141 | 
142 |     auto that = static_cast(window_struct->lpCreateParams);
143 |     EnableFullDpiSupportIfAvailable(window);
144 |     that->window_handle_ = window;
145 |   } else if (Win32Window* that = GetThisFromHandle(window)) {
146 |     return that->MessageHandler(window, message, wparam, lparam);
147 |   }
148 | 
149 |   return DefWindowProc(window, message, wparam, lparam);
150 | }
151 | 
152 | LRESULT
153 | Win32Window::MessageHandler(HWND hwnd,
154 |                             UINT const message,
155 |                             WPARAM const wparam,
156 |                             LPARAM const lparam) noexcept {
157 |   switch (message) {
158 |     case WM_DESTROY:
159 |       window_handle_ = nullptr;
160 |       Destroy();
161 |       if (quit_on_close_) {
162 |         PostQuitMessage(0);
163 |       }
164 |       return 0;
165 | 
166 |     case WM_DPICHANGED: {
167 |       auto newRectSize = reinterpret_cast(lparam);
168 |       LONG newWidth = newRectSize->right - newRectSize->left;
169 |       LONG newHeight = newRectSize->bottom - newRectSize->top;
170 | 
171 |       SetWindowPos(hwnd, nullptr, newRectSize->left, newRectSize->top, newWidth,
172 |                    newHeight, SWP_NOZORDER | SWP_NOACTIVATE);
173 | 
174 |       return 0;
175 |     }
176 |     case WM_SIZE: {
177 |       RECT rect = GetClientArea();
178 |       if (child_content_ != nullptr) {
179 |         // Size and position the child window.
180 |         MoveWindow(child_content_, rect.left, rect.top, rect.right - rect.left,
181 |                    rect.bottom - rect.top, TRUE);
182 |       }
183 |       return 0;
184 |     }
185 | 
186 |     case WM_ACTIVATE:
187 |       if (child_content_ != nullptr) {
188 |         SetFocus(child_content_);
189 |       }
190 |       return 0;
191 |   }
192 | 
193 |   return DefWindowProc(window_handle_, message, wparam, lparam);
194 | }
195 | 
196 | void Win32Window::Destroy() {
197 |   OnDestroy();
198 | 
199 |   if (window_handle_) {
200 |     DestroyWindow(window_handle_);
201 |     window_handle_ = nullptr;
202 |   }
203 |   if (g_active_window_count == 0) {
204 |     WindowClassRegistrar::GetInstance()->UnregisterWindowClass();
205 |   }
206 | }
207 | 
208 | Win32Window* Win32Window::GetThisFromHandle(HWND const window) noexcept {
209 |   return reinterpret_cast(
210 |       GetWindowLongPtr(window, GWLP_USERDATA));
211 | }
212 | 
213 | void Win32Window::SetChildContent(HWND content) {
214 |   child_content_ = content;
215 |   SetParent(content, window_handle_);
216 |   RECT frame = GetClientArea();
217 | 
218 |   MoveWindow(content, frame.left, frame.top, frame.right - frame.left,
219 |              frame.bottom - frame.top, true);
220 | 
221 |   SetFocus(child_content_);
222 | }
223 | 
224 | RECT Win32Window::GetClientArea() {
225 |   RECT frame;
226 |   GetClientRect(window_handle_, &frame);
227 |   return frame;
228 | }
229 | 
230 | HWND Win32Window::GetHandle() {
231 |   return window_handle_;
232 | }
233 | 
234 | void Win32Window::SetQuitOnClose(bool quit_on_close) {
235 |   quit_on_close_ = quit_on_close;
236 | }
237 | 
238 | bool Win32Window::OnCreate() {
239 |   // No-op; provided for subclasses.
240 |   return true;
241 | }
242 | 
243 | void Win32Window::OnDestroy() {
244 |   // No-op; provided for subclasses.
245 | }
246 | 
--------------------------------------------------------------------------------
/windows/runner/win32_window.h:
--------------------------------------------------------------------------------
 1 | #ifndef RUNNER_WIN32_WINDOW_H_
 2 | #define RUNNER_WIN32_WINDOW_H_
 3 | 
 4 | #include 
 5 | 
 6 | #include 
 7 | #include 
 8 | #include 
 9 | 
10 | // A class abstraction for a high DPI-aware Win32 Window. Intended to be
11 | // inherited from by classes that wish to specialize with custom
12 | // rendering and input handling
13 | class Win32Window {
14 |  public:
15 |   struct Point {
16 |     unsigned int x;
17 |     unsigned int y;
18 |     Point(unsigned int x, unsigned int y) : x(x), y(y) {}
19 |   };
20 | 
21 |   struct Size {
22 |     unsigned int width;
23 |     unsigned int height;
24 |     Size(unsigned int width, unsigned int height)
25 |         : width(width), height(height) {}
26 |   };
27 | 
28 |   Win32Window();
29 |   virtual ~Win32Window();
30 | 
31 |   // Creates and shows a win32 window with |title| and position and size using
32 |   // |origin| and |size|. New windows are created on the default monitor. Window
33 |   // sizes are specified to the OS in physical pixels, hence to ensure a
34 |   // consistent size to will treat the width height passed in to this function
35 |   // as logical pixels and scale to appropriate for the default monitor. Returns
36 |   // true if the window was created successfully.
37 |   bool CreateAndShow(const std::wstring& title,
38 |                      const Point& origin,
39 |                      const Size& size);
40 | 
41 |   // Release OS resources associated with window.
42 |   void Destroy();
43 | 
44 |   // Inserts |content| into the window tree.
45 |   void SetChildContent(HWND content);
46 | 
47 |   // Returns the backing Window handle to enable clients to set icon and other
48 |   // window properties. Returns nullptr if the window has been destroyed.
49 |   HWND GetHandle();
50 | 
51 |   // If true, closing this window will quit the application.
52 |   void SetQuitOnClose(bool quit_on_close);
53 | 
54 |   // Return a RECT representing the bounds of the current client area.
55 |   RECT GetClientArea();
56 | 
57 |  protected:
58 |   // Processes and route salient window messages for mouse handling,
59 |   // size change and DPI. Delegates handling of these to member overloads that
60 |   // inheriting classes can handle.
61 |   virtual LRESULT MessageHandler(HWND window,
62 |                                  UINT const message,
63 |                                  WPARAM const wparam,
64 |                                  LPARAM const lparam) noexcept;
65 | 
66 |   // Called when CreateAndShow is called, allowing subclass window-related
67 |   // setup. Subclasses should return false if setup fails.
68 |   virtual bool OnCreate();
69 | 
70 |   // Called when Destroy is called.
71 |   virtual void OnDestroy();
72 | 
73 |  private:
74 |   friend class WindowClassRegistrar;
75 | 
76 |   // OS callback called by message pump. Handles the WM_NCCREATE message which
77 |   // is passed when the non-client area is being created and enables automatic
78 |   // non-client DPI scaling so that the non-client area automatically
79 |   // responsponds to changes in DPI. All other messages are handled by
80 |   // MessageHandler.
81 |   static LRESULT CALLBACK WndProc(HWND const window,
82 |                                   UINT const message,
83 |                                   WPARAM const wparam,
84 |                                   LPARAM const lparam) noexcept;
85 | 
86 |   // Retrieves a class instance pointer for |window|
87 |   static Win32Window* GetThisFromHandle(HWND const window) noexcept;
88 | 
89 |   bool quit_on_close_ = false;
90 | 
91 |   // window handle for top level window.
92 |   HWND window_handle_ = nullptr;
93 | 
94 |   // window handle for hosted content.
95 |   HWND child_content_ = nullptr;
96 | };
97 | 
98 | #endif  // RUNNER_WIN32_WINDOW_H_
99 | 
--------------------------------------------------------------------------------