├── .gitignore
├── .metadata
├── LICENSE
├── README.md
├── analysis_options.yaml
├── android
├── .gitignore
├── app
│ ├── build.gradle
│ └── src
│ │ ├── debug
│ │ └── AndroidManifest.xml
│ │ ├── main
│ │ ├── AndroidManifest.xml
│ │ ├── kotlin
│ │ │ └── com
│ │ │ │ └── jideguru
│ │ │ │ └── animation_playground
│ │ │ │ └── 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
└── images
│ ├── cat.jpeg
│ └── dvd-logo.png
├── gifs
├── 3d-card.gif
├── bouncing-ball.gif
├── bouncing-dvd.gif
├── clock_loader.gif
├── fading-grid.gif
├── grid-magn.gif
├── metaball-fab.gif
├── particle-emitter.gif
├── pixel-painting.gif
├── pyramid-shader.gif
├── rain.gif
└── simple-particle-system.gif
├── ios
├── .gitignore
├── Flutter
│ ├── AppFrameworkInfo.plist
│ ├── Debug.xcconfig
│ └── Release.xcconfig
├── Runner.xcodeproj
│ ├── project.pbxproj
│ ├── project.xcworkspace
│ │ ├── contents.xcworkspacedata
│ │ └── xcshareddata
│ │ │ ├── IDEWorkspaceChecks.plist
│ │ │ └── WorkspaceSettings.xcsettings
│ └── xcshareddata
│ │ └── xcschemes
│ │ └── Runner.xcscheme
├── Runner.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ ├── IDEWorkspaceChecks.plist
│ │ └── WorkspaceSettings.xcsettings
└── Runner
│ ├── AppDelegate.swift
│ ├── Assets.xcassets
│ ├── AppIcon.appiconset
│ │ ├── Contents.json
│ │ ├── Icon-App-1024x1024@1x.png
│ │ ├── Icon-App-20x20@1x.png
│ │ ├── Icon-App-20x20@2x.png
│ │ ├── Icon-App-20x20@3x.png
│ │ ├── Icon-App-29x29@1x.png
│ │ ├── Icon-App-29x29@2x.png
│ │ ├── Icon-App-29x29@3x.png
│ │ ├── Icon-App-40x40@1x.png
│ │ ├── Icon-App-40x40@2x.png
│ │ ├── Icon-App-40x40@3x.png
│ │ ├── Icon-App-60x60@2x.png
│ │ ├── Icon-App-60x60@3x.png
│ │ ├── Icon-App-76x76@1x.png
│ │ ├── Icon-App-76x76@2x.png
│ │ └── Icon-App-83.5x83.5@2x.png
│ └── LaunchImage.imageset
│ │ ├── Contents.json
│ │ ├── LaunchImage.png
│ │ ├── LaunchImage@2x.png
│ │ ├── LaunchImage@3x.png
│ │ └── README.md
│ ├── Base.lproj
│ ├── LaunchScreen.storyboard
│ └── Main.storyboard
│ ├── Info.plist
│ └── Runner-Bridging-Header.h
├── lib
├── animations
│ ├── card
│ │ ├── barrel.dart
│ │ └── three_dimensional_card.dart
│ ├── coding_train_challenges
│ │ ├── barrel.dart
│ │ ├── bouncing_ball.dart
│ │ ├── bouncing_dvd.dart
│ │ ├── painting_with_pixels.dart
│ │ ├── particle_system_with_emitters.dart
│ │ ├── rain.dart
│ │ └── simple_particle_system.dart
│ ├── grid_magnification
│ │ ├── barrel.dart
│ │ ├── fading_grid.dart
│ │ └── grid_magnification.dart
│ ├── loaders
│ │ ├── barrel.dart
│ │ └── clock_loader.dart
│ ├── morphing_segmented_bar.dart
│ └── segmented_bar_flip.dart
├── animations_list.dart
├── buildcontext_extension.dart
├── list_page.dart
├── main.dart
├── random_extension.dart
├── routes.dart
├── shaders
│ ├── barrel.dart
│ ├── fractal_pyramid.dart
│ └── metaball_fab.dart
└── utils.dart
├── macos
├── .gitignore
├── Flutter
│ ├── Flutter-Debug.xcconfig
│ ├── Flutter-Release.xcconfig
│ └── GeneratedPluginRegistrant.swift
├── Runner.xcodeproj
│ ├── project.pbxproj
│ ├── project.xcworkspace
│ │ └── xcshareddata
│ │ │ └── IDEWorkspaceChecks.plist
│ └── xcshareddata
│ │ └── xcschemes
│ │ └── Runner.xcscheme
├── Runner.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ └── IDEWorkspaceChecks.plist
└── Runner
│ ├── AppDelegate.swift
│ ├── Assets.xcassets
│ └── AppIcon.appiconset
│ │ ├── Contents.json
│ │ ├── app_icon_1024.png
│ │ ├── app_icon_128.png
│ │ ├── app_icon_16.png
│ │ ├── app_icon_256.png
│ │ ├── app_icon_32.png
│ │ ├── app_icon_512.png
│ │ └── app_icon_64.png
│ ├── Base.lproj
│ └── MainMenu.xib
│ ├── Configs
│ ├── AppInfo.xcconfig
│ ├── Debug.xcconfig
│ ├── Release.xcconfig
│ └── Warnings.xcconfig
│ ├── DebugProfile.entitlements
│ ├── Info.plist
│ ├── MainFlutterWindow.swift
│ └── Release.entitlements
├── pubspec.lock
├── pubspec.yaml
├── shaders
├── metaball_shader.frag
└── pyramid.glsl
├── test
└── widget_test.dart
└── web
├── favicon.png
├── icons
├── Icon-192.png
├── Icon-512.png
├── Icon-maskable-192.png
└── Icon-maskable-512.png
├── index.html
└── manifest.json
/.gitignore:
--------------------------------------------------------------------------------
1 | # Miscellaneous
2 | *.class
3 | *.log
4 | *.pyc
5 | *.swp
6 | .DS_Store
7 | .atom/
8 | .build/
9 | .buildlog/
10 | .history
11 | .svn/
12 | .swiftpm/
13 | migrate_working_dir/
14 |
15 | # IntelliJ related
16 | *.iml
17 | *.ipr
18 | *.iws
19 | .idea/
20 |
21 | # The .vscode folder contains launch configuration and tasks you configure in
22 | # VS Code which you may wish to be included in version control, so this line
23 | # is commented out by default.
24 | #.vscode/
25 |
26 | # Flutter/Dart/Pub related
27 | **/doc/api/
28 | **/ios/Flutter/.last_build_id
29 | .dart_tool/
30 | .flutter-plugins
31 | .flutter-plugins-dependencies
32 | .packages
33 | .pub-cache/
34 | .pub/
35 | /build/
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 |
48 |
49 | .firebaserc
50 | firebase.json
--------------------------------------------------------------------------------
/.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: "5dcb86f68f239346676ceb1ed1ea385bd215fba1"
8 | channel: "stable"
9 |
10 | project_type: app
11 |
12 | # Tracks metadata for the flutter migrate command
13 | migration:
14 | platforms:
15 | - platform: root
16 | create_revision: 5dcb86f68f239346676ceb1ed1ea385bd215fba1
17 | base_revision: 5dcb86f68f239346676ceb1ed1ea385bd215fba1
18 | - platform: web
19 | create_revision: 5dcb86f68f239346676ceb1ed1ea385bd215fba1
20 | base_revision: 5dcb86f68f239346676ceb1ed1ea385bd215fba1
21 |
22 | # User provided section
23 |
24 | # List of Local paths (relative to this file) that should be
25 | # ignored by the migrate tool.
26 | #
27 | # Files that are not part of the templates will be ignored by default.
28 | unmanaged_files:
29 | - 'lib/main.dart'
30 | - 'ios/Runner.xcodeproj/project.pbxproj'
31 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright [2022] [JideGuru]
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Animations Playground 
2 |
3 | 
4 | [](LICENSE)
5 | 
6 | 
7 |
8 | This repo contains some animations that i implemented using Flutter in my free time.
9 |
10 | You can see the animations on my [Twitter Profile](https://twitter.com/iamjideguru)
11 |
12 | Try out the demos here [animation-playground.jideguru.dev](https://animation-playground.jideguru.dev/)
13 |
14 | Feel free to star, fork and contribute.
15 |
16 | ## Animation Demos
17 |
18 | #### Fading Grid || [Link to code](https://github.com/JideGuru/animation_playground/blob/master/lib/animations/grid_magnification/fading_grid.dart)
19 | 
20 |
21 | ---
22 |
23 | #### Grid Magnification || [Link to code](https://github.com/JideGuru/animation_playground/blob/master/lib/animations/grid_magnification/grid_magnification.dart)
24 | 
25 |
26 | ---
27 |
28 | #### 3D Card || [Link to code](https://github.com/JideGuru/animation_playground/blob/master/lib/animations/card/three_dimensional_card.dart)
29 | 
30 |
31 | ---
32 |
33 | #### Bouncing DVD || [Link to code](https://github.com/JideGuru/animation_playground/blob/master/lib/animations/coding_train_challenges/bouncing_dvd.dart)
34 | 
35 |
36 | ---
37 |
38 | #### Rain Animation || [Link to code](https://github.com/JideGuru/animation_playground/blob/master/lib/animations/coding_train_challenges/rain.dart)
39 | 
40 |
41 | ---
42 |
43 | #### Clock Loader || [Link to code](https://github.com/JideGuru/animation_playground/blob/master/lib/animations/loaders/clock_loader.dart)
44 | 
45 |
46 |
47 | ---
48 |
49 | #### Fractal Pyramid Shader || [Link to code](https://github.com/JideGuru/animation_playground/blob/master/lib/shaders/fractal_pyramid.dart)
50 | 
51 |
52 |
53 | ---
54 |
55 | #### Metaball FAB || [Link to code](https://github.com/JideGuru/animation_playground/blob/master/lib/shaders/metaball_fab.dart)
56 | 
57 |
58 |
59 | ---
60 |
61 | #### Simple Particle System || [Link to code](https://github.com/JideGuru/animation_playground/blob/master/lib/animations/coding_train_challenges/simple_particle_system.dart)
62 | 
63 |
64 |
65 | ---
66 |
67 | #### The Bouncing Ball || [Link to code](https://github.com/JideGuru/animation_playground/blob/master/lib/animations/coding_train_challenges/bouncing_ball.dart)
68 | 
69 |
70 |
71 | ---
72 |
73 | #### Particle System with Emitters || [Link to code](https://github.com/JideGuru/animation_playground/blob/master/lib/animations/coding_train_challenges/particle_system_with_emitters.dart)
74 | 
75 |
76 |
77 | ---
78 |
79 | #### Painting with Pixels || [Link to code](https://github.com/JideGuru/animation_playground/blob/master/lib/animations/coding_train_challenges/painting_with_pixels.dart)
80 | 
81 |
82 |
83 | ## Getting Started
84 |
85 | This project is a starting point for a Flutter application.
86 |
87 | A few resources to get you started if this is your first Flutter project:
88 |
89 | - [Lab: Write your first Flutter app](https://docs.flutter.dev/get-started/codelab)
90 | - [Cookbook: Useful Flutter samples](https://docs.flutter.dev/cookbook)
91 |
92 | For help getting started with Flutter development, view the
93 | [online documentation](https://docs.flutter.dev/), which offers tutorials,
94 | samples, guidance on mobile development, and a full API reference.
95 |
--------------------------------------------------------------------------------
/analysis_options.yaml:
--------------------------------------------------------------------------------
1 | # This file configures the analyzer, which statically analyzes Dart code to
2 | # check for errors, warnings, and lints.
3 | #
4 | # The issues identified by the analyzer are surfaced in the UI of Dart-enabled
5 | # IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be
6 | # invoked from the command line by running `flutter analyze`.
7 |
8 | # The following line activates a set of recommended lints for Flutter apps,
9 | # packages, and plugins designed to encourage good coding practices.
10 | include: package:flutter_lints/flutter.yaml
11 |
12 | linter:
13 | # The lint rules applied to this project can be customized in the
14 | # section below to disable rules from the `package:flutter_lints/flutter.yaml`
15 | # included above or to enable additional rules. A list of all available lints
16 | # and their documentation is published at
17 | # https://dart-lang.github.io/linter/lints/index.html.
18 | #
19 | # Instead of disabling a lint rule for the entire project in the
20 | # section below, it can also be suppressed for a single line of code
21 | # or a specific dart file by using the `// ignore: name_of_lint` and
22 | # `// ignore_for_file: name_of_lint` syntax on the line or in the file
23 | # producing the lint.
24 | rules:
25 | # avoid_print: false # Uncomment to disable the `avoid_print` rule
26 | # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule
27 |
28 | # Additional information about this file can be found at
29 | # https://dart.dev/guides/language/analysis-options
30 |
--------------------------------------------------------------------------------
/android/.gitignore:
--------------------------------------------------------------------------------
1 | gradle-wrapper.jar
2 | /.gradle
3 | /captures/
4 | /gradlew
5 | /gradlew.bat
6 | /local.properties
7 | GeneratedPluginRegistrant.java
8 |
9 | # Remember to never publicly share your keystore.
10 | # See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app
11 | key.properties
12 | **/*.keystore
13 | **/*.jks
14 |
--------------------------------------------------------------------------------
/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 flutter.compileSdkVersion
30 | ndkVersion flutter.ndkVersion
31 |
32 | compileOptions {
33 | sourceCompatibility JavaVersion.VERSION_1_8
34 | targetCompatibility JavaVersion.VERSION_1_8
35 | }
36 |
37 | kotlinOptions {
38 | jvmTarget = '1.8'
39 | }
40 |
41 | sourceSets {
42 | main.java.srcDirs += 'src/main/kotlin'
43 | }
44 |
45 | defaultConfig {
46 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
47 | applicationId "com.jideguru.animation_playground"
48 | // You can update the following values to match your application needs.
49 | // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-build-configuration.
50 | minSdkVersion flutter.minSdkVersion
51 | targetSdkVersion flutter.targetSdkVersion
52 | versionCode flutterVersionCode.toInteger()
53 | versionName flutterVersionName
54 | }
55 |
56 | buildTypes {
57 | release {
58 | // TODO: Add your own signing config for the release build.
59 | // Signing with the debug keys for now, so `flutter run --release` works.
60 | signingConfig signingConfigs.debug
61 | }
62 | }
63 | }
64 |
65 | flutter {
66 | source '../..'
67 | }
68 |
69 | dependencies {
70 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
71 | }
72 |
--------------------------------------------------------------------------------
/android/app/src/debug/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/android/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
7 |
15 |
19 |
23 |
24 |
25 |
26 |
27 |
28 |
30 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/android/app/src/main/kotlin/com/jideguru/animation_playground/MainActivity.kt:
--------------------------------------------------------------------------------
1 | package com.jideguru.animation_playground
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/JideGuru/animation_playground/b53a541c25039b11aadbabb5c173964242e980da/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JideGuru/animation_playground/b53a541c25039b11aadbabb5c173964242e980da/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JideGuru/animation_playground/b53a541c25039b11aadbabb5c173964242e980da/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JideGuru/animation_playground/b53a541c25039b11aadbabb5c173964242e980da/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JideGuru/animation_playground/b53a541c25039b11aadbabb5c173964242e980da/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 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/android/build.gradle:
--------------------------------------------------------------------------------
1 | buildscript {
2 | ext.kotlin_version = '1.6.10'
3 | repositories {
4 | google()
5 | mavenCentral()
6 | }
7 |
8 | dependencies {
9 | classpath 'com.android.tools.build:gradle:7.1.2'
10 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
11 | }
12 | }
13 |
14 | allprojects {
15 | repositories {
16 | google()
17 | mavenCentral()
18 | }
19 | }
20 |
21 | rootProject.buildDir = '../build'
22 | subprojects {
23 | project.buildDir = "${rootProject.buildDir}/${project.name}"
24 | }
25 | subprojects {
26 | project.evaluationDependsOn(':app')
27 | }
28 |
29 | 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 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | zipStoreBase=GRADLE_USER_HOME
4 | zipStorePath=wrapper/dists
5 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-all.zip
6 |
--------------------------------------------------------------------------------
/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/images/cat.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JideGuru/animation_playground/b53a541c25039b11aadbabb5c173964242e980da/assets/images/cat.jpeg
--------------------------------------------------------------------------------
/assets/images/dvd-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JideGuru/animation_playground/b53a541c25039b11aadbabb5c173964242e980da/assets/images/dvd-logo.png
--------------------------------------------------------------------------------
/gifs/3d-card.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JideGuru/animation_playground/b53a541c25039b11aadbabb5c173964242e980da/gifs/3d-card.gif
--------------------------------------------------------------------------------
/gifs/bouncing-ball.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JideGuru/animation_playground/b53a541c25039b11aadbabb5c173964242e980da/gifs/bouncing-ball.gif
--------------------------------------------------------------------------------
/gifs/bouncing-dvd.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JideGuru/animation_playground/b53a541c25039b11aadbabb5c173964242e980da/gifs/bouncing-dvd.gif
--------------------------------------------------------------------------------
/gifs/clock_loader.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JideGuru/animation_playground/b53a541c25039b11aadbabb5c173964242e980da/gifs/clock_loader.gif
--------------------------------------------------------------------------------
/gifs/fading-grid.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JideGuru/animation_playground/b53a541c25039b11aadbabb5c173964242e980da/gifs/fading-grid.gif
--------------------------------------------------------------------------------
/gifs/grid-magn.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JideGuru/animation_playground/b53a541c25039b11aadbabb5c173964242e980da/gifs/grid-magn.gif
--------------------------------------------------------------------------------
/gifs/metaball-fab.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JideGuru/animation_playground/b53a541c25039b11aadbabb5c173964242e980da/gifs/metaball-fab.gif
--------------------------------------------------------------------------------
/gifs/particle-emitter.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JideGuru/animation_playground/b53a541c25039b11aadbabb5c173964242e980da/gifs/particle-emitter.gif
--------------------------------------------------------------------------------
/gifs/pixel-painting.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JideGuru/animation_playground/b53a541c25039b11aadbabb5c173964242e980da/gifs/pixel-painting.gif
--------------------------------------------------------------------------------
/gifs/pyramid-shader.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JideGuru/animation_playground/b53a541c25039b11aadbabb5c173964242e980da/gifs/pyramid-shader.gif
--------------------------------------------------------------------------------
/gifs/rain.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JideGuru/animation_playground/b53a541c25039b11aadbabb5c173964242e980da/gifs/rain.gif
--------------------------------------------------------------------------------
/gifs/simple-particle-system.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JideGuru/animation_playground/b53a541c25039b11aadbabb5c173964242e980da/gifs/simple-particle-system.gif
--------------------------------------------------------------------------------
/ios/.gitignore:
--------------------------------------------------------------------------------
1 | **/dgph
2 | *.mode1v3
3 | *.mode2v3
4 | *.moved-aside
5 | *.pbxuser
6 | *.perspectivev3
7 | **/*sync/
8 | .sconsign.dblite
9 | .tags*
10 | **/.vagrant/
11 | **/DerivedData/
12 | Icon?
13 | **/Pods/
14 | **/.symlinks/
15 | profile
16 | xcuserdata
17 | **/.generated/
18 | Flutter/App.framework
19 | Flutter/Flutter.framework
20 | Flutter/Flutter.podspec
21 | Flutter/Generated.xcconfig
22 | Flutter/ephemeral/
23 | Flutter/app.flx
24 | Flutter/app.zip
25 | Flutter/flutter_assets/
26 | Flutter/flutter_export_environment.sh
27 | ServiceDefinitions.json
28 | Runner/GeneratedPluginRegistrant.*
29 |
30 | # Exceptions to above rules.
31 | !default.mode1v3
32 | !default.mode2v3
33 | !default.pbxuser
34 | !default.perspectivev3
35 |
--------------------------------------------------------------------------------
/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 | 12.0
25 |
26 |
27 |
--------------------------------------------------------------------------------
/ios/Flutter/Debug.xcconfig:
--------------------------------------------------------------------------------
1 | #include "Generated.xcconfig"
2 |
--------------------------------------------------------------------------------
/ios/Flutter/Release.xcconfig:
--------------------------------------------------------------------------------
1 | #include "Generated.xcconfig"
2 |
--------------------------------------------------------------------------------
/ios/Runner.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 54;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
11 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
12 | 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
13 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
14 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
15 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
16 | /* End PBXBuildFile section */
17 |
18 | /* Begin PBXCopyFilesBuildPhase section */
19 | 9705A1C41CF9048500538489 /* Embed Frameworks */ = {
20 | isa = PBXCopyFilesBuildPhase;
21 | buildActionMask = 2147483647;
22 | dstPath = "";
23 | dstSubfolderSpec = 10;
24 | files = (
25 | );
26 | name = "Embed Frameworks";
27 | runOnlyForDeploymentPostprocessing = 0;
28 | };
29 | /* End PBXCopyFilesBuildPhase section */
30 |
31 | /* Begin PBXFileReference section */
32 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; };
33 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; };
34 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; };
35 | 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; };
36 | 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
37 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; };
38 | 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; };
39 | 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; };
40 | 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
41 | 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
42 | 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
43 | 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
44 | 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
45 | /* End PBXFileReference section */
46 |
47 | /* Begin PBXFrameworksBuildPhase section */
48 | 97C146EB1CF9000F007C117D /* Frameworks */ = {
49 | isa = PBXFrameworksBuildPhase;
50 | buildActionMask = 2147483647;
51 | files = (
52 | );
53 | runOnlyForDeploymentPostprocessing = 0;
54 | };
55 | /* End PBXFrameworksBuildPhase section */
56 |
57 | /* Begin PBXGroup section */
58 | 9740EEB11CF90186004384FC /* Flutter */ = {
59 | isa = PBXGroup;
60 | children = (
61 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */,
62 | 9740EEB21CF90195004384FC /* Debug.xcconfig */,
63 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */,
64 | 9740EEB31CF90195004384FC /* Generated.xcconfig */,
65 | );
66 | name = Flutter;
67 | sourceTree = "";
68 | };
69 | 97C146E51CF9000F007C117D = {
70 | isa = PBXGroup;
71 | children = (
72 | 9740EEB11CF90186004384FC /* Flutter */,
73 | 97C146F01CF9000F007C117D /* Runner */,
74 | 97C146EF1CF9000F007C117D /* Products */,
75 | );
76 | sourceTree = "";
77 | };
78 | 97C146EF1CF9000F007C117D /* Products */ = {
79 | isa = PBXGroup;
80 | children = (
81 | 97C146EE1CF9000F007C117D /* Runner.app */,
82 | );
83 | name = Products;
84 | sourceTree = "";
85 | };
86 | 97C146F01CF9000F007C117D /* Runner */ = {
87 | isa = PBXGroup;
88 | children = (
89 | 97C146FA1CF9000F007C117D /* Main.storyboard */,
90 | 97C146FD1CF9000F007C117D /* Assets.xcassets */,
91 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */,
92 | 97C147021CF9000F007C117D /* Info.plist */,
93 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */,
94 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */,
95 | 74858FAE1ED2DC5600515810 /* AppDelegate.swift */,
96 | 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */,
97 | );
98 | path = Runner;
99 | sourceTree = "";
100 | };
101 | /* End PBXGroup section */
102 |
103 | /* Begin PBXNativeTarget section */
104 | 97C146ED1CF9000F007C117D /* Runner */ = {
105 | isa = PBXNativeTarget;
106 | buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
107 | buildPhases = (
108 | 9740EEB61CF901F6004384FC /* Run Script */,
109 | 97C146EA1CF9000F007C117D /* Sources */,
110 | 97C146EB1CF9000F007C117D /* Frameworks */,
111 | 97C146EC1CF9000F007C117D /* Resources */,
112 | 9705A1C41CF9048500538489 /* Embed Frameworks */,
113 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */,
114 | );
115 | buildRules = (
116 | );
117 | dependencies = (
118 | );
119 | name = Runner;
120 | productName = Runner;
121 | productReference = 97C146EE1CF9000F007C117D /* Runner.app */;
122 | productType = "com.apple.product-type.application";
123 | };
124 | /* End PBXNativeTarget section */
125 |
126 | /* Begin PBXProject section */
127 | 97C146E61CF9000F007C117D /* Project object */ = {
128 | isa = PBXProject;
129 | attributes = {
130 | LastUpgradeCheck = 1510;
131 | ORGANIZATIONNAME = "";
132 | TargetAttributes = {
133 | 97C146ED1CF9000F007C117D = {
134 | CreatedOnToolsVersion = 7.3.1;
135 | LastSwiftMigration = 1100;
136 | };
137 | };
138 | };
139 | buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */;
140 | compatibilityVersion = "Xcode 9.3";
141 | developmentRegion = en;
142 | hasScannedForEncodings = 0;
143 | knownRegions = (
144 | en,
145 | Base,
146 | );
147 | mainGroup = 97C146E51CF9000F007C117D;
148 | productRefGroup = 97C146EF1CF9000F007C117D /* Products */;
149 | projectDirPath = "";
150 | projectRoot = "";
151 | targets = (
152 | 97C146ED1CF9000F007C117D /* Runner */,
153 | );
154 | };
155 | /* End PBXProject section */
156 |
157 | /* Begin PBXResourcesBuildPhase section */
158 | 97C146EC1CF9000F007C117D /* Resources */ = {
159 | isa = PBXResourcesBuildPhase;
160 | buildActionMask = 2147483647;
161 | files = (
162 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */,
163 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */,
164 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,
165 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */,
166 | );
167 | runOnlyForDeploymentPostprocessing = 0;
168 | };
169 | /* End PBXResourcesBuildPhase section */
170 |
171 | /* Begin PBXShellScriptBuildPhase section */
172 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
173 | isa = PBXShellScriptBuildPhase;
174 | alwaysOutOfDate = 1;
175 | buildActionMask = 2147483647;
176 | files = (
177 | );
178 | inputPaths = (
179 | "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}",
180 | );
181 | name = "Thin Binary";
182 | outputPaths = (
183 | );
184 | runOnlyForDeploymentPostprocessing = 0;
185 | shellPath = /bin/sh;
186 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin";
187 | };
188 | 9740EEB61CF901F6004384FC /* Run Script */ = {
189 | isa = PBXShellScriptBuildPhase;
190 | alwaysOutOfDate = 1;
191 | buildActionMask = 2147483647;
192 | files = (
193 | );
194 | inputPaths = (
195 | );
196 | name = "Run Script";
197 | outputPaths = (
198 | );
199 | runOnlyForDeploymentPostprocessing = 0;
200 | shellPath = /bin/sh;
201 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
202 | };
203 | /* End PBXShellScriptBuildPhase section */
204 |
205 | /* Begin PBXSourcesBuildPhase section */
206 | 97C146EA1CF9000F007C117D /* Sources */ = {
207 | isa = PBXSourcesBuildPhase;
208 | buildActionMask = 2147483647;
209 | files = (
210 | 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */,
211 | 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */,
212 | );
213 | runOnlyForDeploymentPostprocessing = 0;
214 | };
215 | /* End PBXSourcesBuildPhase section */
216 |
217 | /* Begin PBXVariantGroup section */
218 | 97C146FA1CF9000F007C117D /* Main.storyboard */ = {
219 | isa = PBXVariantGroup;
220 | children = (
221 | 97C146FB1CF9000F007C117D /* Base */,
222 | );
223 | name = Main.storyboard;
224 | sourceTree = "";
225 | };
226 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = {
227 | isa = PBXVariantGroup;
228 | children = (
229 | 97C147001CF9000F007C117D /* Base */,
230 | );
231 | name = LaunchScreen.storyboard;
232 | sourceTree = "";
233 | };
234 | /* End PBXVariantGroup section */
235 |
236 | /* Begin XCBuildConfiguration section */
237 | 249021D3217E4FDB00AE95B9 /* Profile */ = {
238 | isa = XCBuildConfiguration;
239 | buildSettings = {
240 | ALWAYS_SEARCH_USER_PATHS = NO;
241 | CLANG_ANALYZER_NONNULL = YES;
242 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
243 | CLANG_CXX_LIBRARY = "libc++";
244 | CLANG_ENABLE_MODULES = YES;
245 | CLANG_ENABLE_OBJC_ARC = YES;
246 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
247 | CLANG_WARN_BOOL_CONVERSION = YES;
248 | CLANG_WARN_COMMA = YES;
249 | CLANG_WARN_CONSTANT_CONVERSION = YES;
250 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
251 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
252 | CLANG_WARN_EMPTY_BODY = YES;
253 | CLANG_WARN_ENUM_CONVERSION = YES;
254 | CLANG_WARN_INFINITE_RECURSION = YES;
255 | CLANG_WARN_INT_CONVERSION = YES;
256 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
257 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
258 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
259 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
260 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
261 | CLANG_WARN_STRICT_PROTOTYPES = YES;
262 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
263 | CLANG_WARN_UNREACHABLE_CODE = YES;
264 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
265 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
266 | COPY_PHASE_STRIP = NO;
267 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
268 | ENABLE_NS_ASSERTIONS = NO;
269 | ENABLE_STRICT_OBJC_MSGSEND = YES;
270 | GCC_C_LANGUAGE_STANDARD = gnu99;
271 | GCC_NO_COMMON_BLOCKS = YES;
272 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
273 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
274 | GCC_WARN_UNDECLARED_SELECTOR = YES;
275 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
276 | GCC_WARN_UNUSED_FUNCTION = YES;
277 | GCC_WARN_UNUSED_VARIABLE = YES;
278 | IPHONEOS_DEPLOYMENT_TARGET = 12.0;
279 | MTL_ENABLE_DEBUG_INFO = NO;
280 | SDKROOT = iphoneos;
281 | SUPPORTED_PLATFORMS = iphoneos;
282 | TARGETED_DEVICE_FAMILY = "1,2";
283 | VALIDATE_PRODUCT = YES;
284 | };
285 | name = Profile;
286 | };
287 | 249021D4217E4FDB00AE95B9 /* Profile */ = {
288 | isa = XCBuildConfiguration;
289 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
290 | buildSettings = {
291 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
292 | CLANG_ENABLE_MODULES = YES;
293 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
294 | DEVELOPMENT_TEAM = 6U5CJ2ZVM3;
295 | ENABLE_BITCODE = NO;
296 | INFOPLIST_FILE = Runner/Info.plist;
297 | LD_RUNPATH_SEARCH_PATHS = (
298 | "$(inherited)",
299 | "@executable_path/Frameworks",
300 | );
301 | PRODUCT_BUNDLE_IDENTIFIER = com.jideguru.animationPlayground;
302 | PRODUCT_NAME = "$(TARGET_NAME)";
303 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
304 | SWIFT_VERSION = 5.0;
305 | VERSIONING_SYSTEM = "apple-generic";
306 | };
307 | name = Profile;
308 | };
309 | 97C147031CF9000F007C117D /* Debug */ = {
310 | isa = XCBuildConfiguration;
311 | buildSettings = {
312 | ALWAYS_SEARCH_USER_PATHS = NO;
313 | CLANG_ANALYZER_NONNULL = YES;
314 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
315 | CLANG_CXX_LIBRARY = "libc++";
316 | CLANG_ENABLE_MODULES = YES;
317 | CLANG_ENABLE_OBJC_ARC = YES;
318 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
319 | CLANG_WARN_BOOL_CONVERSION = YES;
320 | CLANG_WARN_COMMA = YES;
321 | CLANG_WARN_CONSTANT_CONVERSION = YES;
322 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
323 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
324 | CLANG_WARN_EMPTY_BODY = YES;
325 | CLANG_WARN_ENUM_CONVERSION = YES;
326 | CLANG_WARN_INFINITE_RECURSION = YES;
327 | CLANG_WARN_INT_CONVERSION = YES;
328 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
329 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
330 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
331 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
332 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
333 | CLANG_WARN_STRICT_PROTOTYPES = YES;
334 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
335 | CLANG_WARN_UNREACHABLE_CODE = YES;
336 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
337 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
338 | COPY_PHASE_STRIP = NO;
339 | DEBUG_INFORMATION_FORMAT = dwarf;
340 | ENABLE_STRICT_OBJC_MSGSEND = YES;
341 | ENABLE_TESTABILITY = YES;
342 | GCC_C_LANGUAGE_STANDARD = gnu99;
343 | GCC_DYNAMIC_NO_PIC = NO;
344 | GCC_NO_COMMON_BLOCKS = YES;
345 | GCC_OPTIMIZATION_LEVEL = 0;
346 | GCC_PREPROCESSOR_DEFINITIONS = (
347 | "DEBUG=1",
348 | "$(inherited)",
349 | );
350 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
351 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
352 | GCC_WARN_UNDECLARED_SELECTOR = YES;
353 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
354 | GCC_WARN_UNUSED_FUNCTION = YES;
355 | GCC_WARN_UNUSED_VARIABLE = YES;
356 | IPHONEOS_DEPLOYMENT_TARGET = 12.0;
357 | MTL_ENABLE_DEBUG_INFO = YES;
358 | ONLY_ACTIVE_ARCH = YES;
359 | SDKROOT = iphoneos;
360 | TARGETED_DEVICE_FAMILY = "1,2";
361 | };
362 | name = Debug;
363 | };
364 | 97C147041CF9000F007C117D /* Release */ = {
365 | isa = XCBuildConfiguration;
366 | buildSettings = {
367 | ALWAYS_SEARCH_USER_PATHS = NO;
368 | CLANG_ANALYZER_NONNULL = YES;
369 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
370 | CLANG_CXX_LIBRARY = "libc++";
371 | CLANG_ENABLE_MODULES = YES;
372 | CLANG_ENABLE_OBJC_ARC = YES;
373 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
374 | CLANG_WARN_BOOL_CONVERSION = YES;
375 | CLANG_WARN_COMMA = YES;
376 | CLANG_WARN_CONSTANT_CONVERSION = YES;
377 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
378 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
379 | CLANG_WARN_EMPTY_BODY = YES;
380 | CLANG_WARN_ENUM_CONVERSION = YES;
381 | CLANG_WARN_INFINITE_RECURSION = YES;
382 | CLANG_WARN_INT_CONVERSION = YES;
383 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
384 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
385 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
386 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
387 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
388 | CLANG_WARN_STRICT_PROTOTYPES = YES;
389 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
390 | CLANG_WARN_UNREACHABLE_CODE = YES;
391 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
392 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
393 | COPY_PHASE_STRIP = NO;
394 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
395 | ENABLE_NS_ASSERTIONS = NO;
396 | ENABLE_STRICT_OBJC_MSGSEND = YES;
397 | GCC_C_LANGUAGE_STANDARD = gnu99;
398 | GCC_NO_COMMON_BLOCKS = YES;
399 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
400 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
401 | GCC_WARN_UNDECLARED_SELECTOR = YES;
402 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
403 | GCC_WARN_UNUSED_FUNCTION = YES;
404 | GCC_WARN_UNUSED_VARIABLE = YES;
405 | IPHONEOS_DEPLOYMENT_TARGET = 12.0;
406 | MTL_ENABLE_DEBUG_INFO = NO;
407 | SDKROOT = iphoneos;
408 | SUPPORTED_PLATFORMS = iphoneos;
409 | SWIFT_COMPILATION_MODE = wholemodule;
410 | SWIFT_OPTIMIZATION_LEVEL = "-O";
411 | TARGETED_DEVICE_FAMILY = "1,2";
412 | VALIDATE_PRODUCT = YES;
413 | };
414 | name = Release;
415 | };
416 | 97C147061CF9000F007C117D /* Debug */ = {
417 | isa = XCBuildConfiguration;
418 | baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
419 | buildSettings = {
420 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
421 | CLANG_ENABLE_MODULES = YES;
422 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
423 | DEVELOPMENT_TEAM = 6U5CJ2ZVM3;
424 | ENABLE_BITCODE = NO;
425 | INFOPLIST_FILE = Runner/Info.plist;
426 | LD_RUNPATH_SEARCH_PATHS = (
427 | "$(inherited)",
428 | "@executable_path/Frameworks",
429 | );
430 | PRODUCT_BUNDLE_IDENTIFIER = com.jideguru.animationPlayground;
431 | PRODUCT_NAME = "$(TARGET_NAME)";
432 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
433 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
434 | SWIFT_VERSION = 5.0;
435 | VERSIONING_SYSTEM = "apple-generic";
436 | };
437 | name = Debug;
438 | };
439 | 97C147071CF9000F007C117D /* Release */ = {
440 | isa = XCBuildConfiguration;
441 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
442 | buildSettings = {
443 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
444 | CLANG_ENABLE_MODULES = YES;
445 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
446 | DEVELOPMENT_TEAM = 6U5CJ2ZVM3;
447 | ENABLE_BITCODE = NO;
448 | INFOPLIST_FILE = Runner/Info.plist;
449 | LD_RUNPATH_SEARCH_PATHS = (
450 | "$(inherited)",
451 | "@executable_path/Frameworks",
452 | );
453 | PRODUCT_BUNDLE_IDENTIFIER = com.jideguru.animationPlayground;
454 | PRODUCT_NAME = "$(TARGET_NAME)";
455 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
456 | SWIFT_VERSION = 5.0;
457 | VERSIONING_SYSTEM = "apple-generic";
458 | };
459 | name = Release;
460 | };
461 | /* End XCBuildConfiguration section */
462 |
463 | /* Begin XCConfigurationList section */
464 | 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = {
465 | isa = XCConfigurationList;
466 | buildConfigurations = (
467 | 97C147031CF9000F007C117D /* Debug */,
468 | 97C147041CF9000F007C117D /* Release */,
469 | 249021D3217E4FDB00AE95B9 /* Profile */,
470 | );
471 | defaultConfigurationIsVisible = 0;
472 | defaultConfigurationName = Release;
473 | };
474 | 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = {
475 | isa = XCConfigurationList;
476 | buildConfigurations = (
477 | 97C147061CF9000F007C117D /* Debug */,
478 | 97C147071CF9000F007C117D /* Release */,
479 | 249021D4217E4FDB00AE95B9 /* Profile */,
480 | );
481 | defaultConfigurationIsVisible = 0;
482 | defaultConfigurationName = Release;
483 | };
484 | /* End XCConfigurationList section */
485 | };
486 | rootObject = 97C146E61CF9000F007C117D /* Project object */;
487 | }
488 |
--------------------------------------------------------------------------------
/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 |
37 |
38 |
39 |
40 |
41 |
42 |
53 |
55 |
61 |
62 |
63 |
64 |
70 |
72 |
78 |
79 |
80 |
81 |
83 |
84 |
87 |
88 |
89 |
--------------------------------------------------------------------------------
/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 | @main
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/JideGuru/animation_playground/b53a541c25039b11aadbabb5c173964242e980da/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/JideGuru/animation_playground/b53a541c25039b11aadbabb5c173964242e980da/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/JideGuru/animation_playground/b53a541c25039b11aadbabb5c173964242e980da/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/JideGuru/animation_playground/b53a541c25039b11aadbabb5c173964242e980da/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/JideGuru/animation_playground/b53a541c25039b11aadbabb5c173964242e980da/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/JideGuru/animation_playground/b53a541c25039b11aadbabb5c173964242e980da/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/JideGuru/animation_playground/b53a541c25039b11aadbabb5c173964242e980da/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/JideGuru/animation_playground/b53a541c25039b11aadbabb5c173964242e980da/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/JideGuru/animation_playground/b53a541c25039b11aadbabb5c173964242e980da/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/JideGuru/animation_playground/b53a541c25039b11aadbabb5c173964242e980da/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/JideGuru/animation_playground/b53a541c25039b11aadbabb5c173964242e980da/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/JideGuru/animation_playground/b53a541c25039b11aadbabb5c173964242e980da/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/JideGuru/animation_playground/b53a541c25039b11aadbabb5c173964242e980da/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/JideGuru/animation_playground/b53a541c25039b11aadbabb5c173964242e980da/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/JideGuru/animation_playground/b53a541c25039b11aadbabb5c173964242e980da/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/JideGuru/animation_playground/b53a541c25039b11aadbabb5c173964242e980da/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JideGuru/animation_playground/b53a541c25039b11aadbabb5c173964242e980da/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JideGuru/animation_playground/b53a541c25039b11aadbabb5c173964242e980da/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 | CFBundleDisplayName
8 | Animation Playground
9 | CFBundleExecutable
10 | $(EXECUTABLE_NAME)
11 | CFBundleIdentifier
12 | $(PRODUCT_BUNDLE_IDENTIFIER)
13 | CFBundleInfoDictionaryVersion
14 | 6.0
15 | CFBundleName
16 | animation_playground
17 | CFBundlePackageType
18 | APPL
19 | CFBundleShortVersionString
20 | $(FLUTTER_BUILD_NAME)
21 | CFBundleSignature
22 | ????
23 | CFBundleVersion
24 | $(FLUTTER_BUILD_NUMBER)
25 | LSRequiresIPhoneOS
26 |
27 | UILaunchStoryboardName
28 | LaunchScreen
29 | UIMainStoryboardFile
30 | Main
31 | UISupportedInterfaceOrientations
32 |
33 | UIInterfaceOrientationPortrait
34 | UIInterfaceOrientationLandscapeLeft
35 | UIInterfaceOrientationLandscapeRight
36 |
37 | UISupportedInterfaceOrientations~ipad
38 |
39 | UIInterfaceOrientationPortrait
40 | UIInterfaceOrientationPortraitUpsideDown
41 | UIInterfaceOrientationLandscapeLeft
42 | UIInterfaceOrientationLandscapeRight
43 |
44 | UIViewControllerBasedStatusBarAppearance
45 |
46 | CADisableMinimumFrameDurationOnPhone
47 |
48 | UIApplicationSupportsIndirectInputEvents
49 |
50 |
51 |
52 |
--------------------------------------------------------------------------------
/ios/Runner/Runner-Bridging-Header.h:
--------------------------------------------------------------------------------
1 | #import "GeneratedPluginRegistrant.h"
2 |
--------------------------------------------------------------------------------
/lib/animations/card/barrel.dart:
--------------------------------------------------------------------------------
1 | export 'three_dimensional_card.dart';
2 |
--------------------------------------------------------------------------------
/lib/animations/card/three_dimensional_card.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | class ThreeDimensionalCard extends StatefulWidget {
4 | const ThreeDimensionalCard({Key? key}) : super(key: key);
5 |
6 | @override
7 | State createState() => _ThreeDimensionalCardState();
8 | }
9 |
10 | class _ThreeDimensionalCardState extends State {
11 | Offset location = Offset.zero;
12 | @override
13 | Widget build(BuildContext context) {
14 | Size screenSize = MediaQuery.of(context).size;
15 | const height = 256.0;
16 | final width = screenSize.width > 400 ? 400.0 : screenSize.width * 0.9;
17 |
18 | const cardHeight = height - 7;
19 | final cardWidth = width - 7;
20 | return Scaffold(
21 | appBar: AppBar(
22 | title: const Text('3D Card'),
23 | ),
24 | backgroundColor: Colors.black,
25 | body: Center(
26 | child: Stack(
27 | children: [
28 | Align(
29 | alignment: Alignment.center,
30 | child: Container(
31 | height: 256,
32 | width: width,
33 | decoration: BoxDecoration(
34 | gradient: const SweepGradient(colors: [
35 | Colors.cyanAccent,
36 | Colors.pinkAccent,
37 | Colors.yellowAccent,
38 | Colors.cyanAccent
39 | ]),
40 | borderRadius: BorderRadius.circular(20),
41 | ),
42 | ),
43 | ),
44 | Align(
45 | alignment: Alignment.center,
46 | child: Transform(
47 | transform: Matrix4.identity()
48 | ..setEntry(3, 2, 0.002) // perspective
49 | ..rotateX(0.001 * location.dy)
50 | ..rotateY(-0.001 * location.dx),
51 | alignment: FractionalOffset.center,
52 | child: GestureDetector(
53 | onPanUpdate: (details) {
54 | location += details.delta;
55 | setState(() {});
56 | },
57 | onPanEnd: (details) {
58 | location = Offset.zero;
59 | setState(() {});
60 | },
61 | child: Container(
62 | height: cardHeight,
63 | width: cardWidth,
64 | decoration: BoxDecoration(
65 | borderRadius: BorderRadius.circular(20),
66 | color: Colors.black,
67 | ),
68 | padding: const EdgeInsets.only(left: 20, bottom: 20),
69 | child: Align(
70 | alignment: Alignment.bottomLeft,
71 | child: Row(
72 | children: [
73 | Container(
74 | height: 50,
75 | width: 50,
76 | decoration: BoxDecoration(
77 | color: Colors.grey.shade800,
78 | shape: BoxShape.circle,
79 | ),
80 | ),
81 | const SizedBox(width: 10),
82 | Column(
83 | crossAxisAlignment: CrossAxisAlignment.start,
84 | mainAxisSize: MainAxisSize.min,
85 | children: [
86 | Container(
87 | height: 20,
88 | width: 80 * 2,
89 | decoration: BoxDecoration(
90 | color: Colors.grey.shade800,
91 | borderRadius: BorderRadius.circular(20),
92 | ),
93 | ),
94 | const SizedBox(height: 8),
95 | Container(
96 | height: 20,
97 | width: 80,
98 | decoration: BoxDecoration(
99 | color: Colors.grey.shade800,
100 | borderRadius: BorderRadius.circular(20),
101 | ),
102 | ),
103 | ],
104 | ),
105 | ],
106 | ),
107 | ),
108 | ),
109 | ),
110 | ),
111 | )
112 | ],
113 | ),
114 | ),
115 | );
116 | }
117 | }
118 |
--------------------------------------------------------------------------------
/lib/animations/coding_train_challenges/barrel.dart:
--------------------------------------------------------------------------------
1 | export 'bouncing_dvd.dart';
2 | export 'rain.dart';
3 | export 'simple_particle_system.dart' hide Particle;
4 | export 'bouncing_ball.dart';
5 | export 'particle_system_with_emitters.dart' hide Particle;
6 | export 'painting_with_pixels.dart';
7 |
--------------------------------------------------------------------------------
/lib/animations/coding_train_challenges/bouncing_ball.dart:
--------------------------------------------------------------------------------
1 | import 'dart:async';
2 | import 'dart:math';
3 |
4 | import 'package:flutter/material.dart';
5 | import 'package:flutter/scheduler.dart';
6 |
7 | class BouncingBall extends StatefulWidget {
8 | const BouncingBall({Key? key}) : super(key: key);
9 |
10 | @override
11 | State createState() => _BouncingBallState();
12 | }
13 |
14 | class _BouncingBallState extends State with SingleTickerProviderStateMixin {
15 | late final Ticker _ticker;
16 | double _vx = 5, _vy = 5, _x = 170, _y = 400;
17 | final _ballWidth = 30, _ballHeight = 30;
18 |
19 | @override
20 | void initState() {
21 | super.initState();
22 | Timer(const Duration(microseconds: 300), () {
23 | _x = Random().nextDouble() * (MediaQuery.of(context).size.width + _ballWidth);
24 | _y = Random().nextDouble() * (MediaQuery.of(context).size.height + _ballHeight);
25 | setState(() {});
26 | _ticker = createTicker((elapsed) {
27 | _x += _vx;
28 | _y += _vy;
29 |
30 | final size = MediaQuery.of(context).size;
31 | if (_x <= 0 || _x >= size.width - _ballWidth) {
32 | _vx = -_vx;
33 | }
34 | if (_y <= 0 || _y >= size.height - _ballHeight) {
35 | _vy = -_vy;
36 | }
37 | setState(() {});
38 | });
39 | _ticker.start();
40 | });
41 |
42 | }
43 |
44 | @override
45 | void dispose() {
46 | super.dispose();
47 | _ticker.dispose();
48 | }
49 |
50 | @override
51 | Widget build(BuildContext context) {
52 | return Scaffold(
53 | backgroundColor: Colors.black,
54 | body: Stack(
55 | children: [
56 | Transform.translate(
57 | offset: Offset(_x, _y),
58 | child: Container(
59 | height: 30,
60 | width: 30,
61 | decoration: const BoxDecoration(
62 | color: Colors.white,
63 | shape: BoxShape.circle,
64 | ),
65 | ),
66 | ),
67 | ],
68 | ),
69 | );
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/lib/animations/coding_train_challenges/bouncing_dvd.dart:
--------------------------------------------------------------------------------
1 | import 'dart:async';
2 | import 'dart:math';
3 |
4 | import 'package:flutter/material.dart';
5 |
6 | class BouncingDVD extends StatefulWidget {
7 | const BouncingDVD({Key? key}) : super(key: key);
8 |
9 | @override
10 | State createState() => _BouncingDVDState();
11 | }
12 |
13 | class _BouncingDVDState extends State {
14 | Random random = Random();
15 | Color dvdColor = Colors.pink;
16 | double dvdWidth = 150, dvdHeight = 80;
17 | double x = 90, y = 30, xSpeed = 50, ySpeed = 50, speed = 150;
18 |
19 | pickColor() {
20 | // removing the timer will make the dvd color change before bouncing
21 | // off the edge
22 | Timer(const Duration(milliseconds: 100), () {
23 | int r = random.nextInt(255);
24 | int g = random.nextInt(255);
25 | int b = random.nextInt(255);
26 | dvdColor = Color.fromRGBO(r, g, b, 1);
27 | });
28 | }
29 |
30 | @override
31 | initState() {
32 | super.initState();
33 | update();
34 | }
35 |
36 | update() {
37 | Timer.periodic(Duration(milliseconds: speed.toInt()), (timer) {
38 | double screenWidth = MediaQuery.of(context).size.width;
39 | double screenHeight = MediaQuery.of(context).size.height;
40 | x += xSpeed;
41 | y += ySpeed;
42 |
43 | if (x + dvdWidth >= screenWidth) {
44 | xSpeed = -xSpeed;
45 | x = screenWidth - dvdWidth;
46 | pickColor();
47 | } else if (x <= 0) {
48 | xSpeed = -xSpeed;
49 | x = 0;
50 | pickColor();
51 | }
52 |
53 | if (y + dvdHeight >= screenHeight) {
54 | ySpeed = -ySpeed;
55 | y = screenHeight - dvdHeight;
56 | pickColor();
57 | } else if (y <= 0) {
58 | ySpeed = -ySpeed;
59 | y = 0;
60 | pickColor();
61 | }
62 |
63 | setState(() {});
64 | });
65 | }
66 |
67 | @override
68 | Widget build(BuildContext context) {
69 | return Scaffold(
70 | backgroundColor: Colors.black,
71 | appBar: AppBar(
72 | title: const Text('Bouncing DVD'),
73 | ),
74 | body: Stack(
75 | children: [
76 | AnimatedPositioned(
77 | duration: Duration(milliseconds: speed.toInt()),
78 | left: x,
79 | top: y,
80 | child: Image.asset(
81 | 'assets/images/dvd-logo.png',
82 | color: dvdColor,
83 | height: dvdHeight,
84 | width: dvdWidth,
85 | ),
86 | ),
87 | ],
88 | ),
89 | );
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/lib/animations/coding_train_challenges/painting_with_pixels.dart:
--------------------------------------------------------------------------------
1 | import 'dart:math' as math;
2 | import 'dart:ui' as ui;
3 |
4 | import 'package:flutter/material.dart' hide Image;
5 | import 'package:flutter/scheduler.dart';
6 | import 'package:flutter/services.dart' show rootBundle;
7 | import 'package:image/image.dart' as img;
8 |
9 | class PaintingWithPixels extends StatefulWidget {
10 | const PaintingWithPixels({Key? key}) : super(key: key);
11 |
12 | @override
13 | State createState() => _PaintingWithPixelsState();
14 | }
15 |
16 | class _PaintingWithPixelsState extends State
17 | with SingleTickerProviderStateMixin {
18 | late ui.Image image;
19 | late img.Image imagePixels;
20 | bool _loading = true;
21 | List offsets = List.empty(growable: true);
22 | final math.Random _random = math.Random();
23 | late final Ticker _ticker;
24 |
25 | @override
26 | void initState() {
27 | super.initState();
28 | loadImage();
29 | _ticker = createTicker((elapsed) {
30 | if (!_loading) {
31 | for (int i = 1; i < 100; i++) {
32 | randomizePoints();
33 | }
34 | }
35 | setState(() {});
36 | });
37 | _ticker.start();
38 | }
39 |
40 | void loadImage() async {
41 | var data = await rootBundle.load('assets/images/cat.jpeg');
42 | final buffer = data.buffer;
43 | var bytes = buffer.asUint8List(data.offsetInBytes, data.lengthInBytes);
44 | image = await decodeImageFromList(bytes);
45 | imagePixels = img.decodeJpg(bytes)!;
46 | _loading = false;
47 | randomizePoints();
48 | setState(() {});
49 | }
50 |
51 | randomizePoints() {
52 | int x = _random.nextInt(imagePixels.width);
53 | int y = _random.nextInt(imagePixels.height);
54 |
55 | Offset offset = Offset(x.toDouble(), y.toDouble());
56 | if (!offsets.contains(offset)) {
57 | offsets.add(offset);
58 | } else {
59 | randomizePoints();
60 | }
61 | }
62 |
63 | @override
64 | void dispose() {
65 | _ticker.dispose();
66 | super.dispose();
67 | }
68 |
69 | @override
70 | Widget build(BuildContext context) {
71 | final size = MediaQuery.of(context).size;
72 | return Scaffold(
73 | appBar: AppBar(title: const Text('Painting With Pixels')),
74 | backgroundColor: Colors.white,
75 | body: _loading
76 | ? const SizedBox.shrink()
77 | : Center(
78 | child: CustomPaint(
79 | painter: _PixelPainter(
80 | image: image,
81 | imagePixels: imagePixels,
82 | offsets: offsets,
83 | ),
84 | child: SizedBox(height: size.height, width: size.width),
85 | ),
86 | ),
87 | );
88 | }
89 | }
90 |
91 | class _PixelPainter extends CustomPainter {
92 | ui.Image image;
93 | img.Image imagePixels;
94 | final List offsets;
95 |
96 | _PixelPainter({
97 | required this.image,
98 | required this.imagePixels,
99 | required this.offsets,
100 | });
101 |
102 | @override
103 | void paint(Canvas canvas, Size size) {
104 | for (Offset offset in offsets) {
105 | img.Pixel pixel =
106 | imagePixels.getPixelSafe(offset.dx.toInt(), offset.dy.toInt());
107 | List colorList = pixel.toList();
108 | canvas.drawCircle(
109 | offset,
110 | 3,
111 | Paint()
112 | ..color =
113 | Color.fromARGB(255, colorList[0], colorList[1], colorList[2]),
114 | );
115 | }
116 | }
117 |
118 | @override
119 | bool shouldRepaint(covariant CustomPainter oldDelegate) => true;
120 | }
121 |
--------------------------------------------------------------------------------
/lib/animations/coding_train_challenges/particle_system_with_emitters.dart:
--------------------------------------------------------------------------------
1 | import 'package:animation_playground/utils.dart';
2 | import 'package:flutter/material.dart';
3 | import 'package:flutter/scheduler.dart';
4 |
5 | class ParticleSystemWithEmitters extends StatefulWidget {
6 | const ParticleSystemWithEmitters({Key? key}) : super(key: key);
7 |
8 | @override
9 | State createState() =>
10 | _ParticleSystemWithEmittersState();
11 | }
12 |
13 | class _ParticleSystemWithEmittersState extends State
14 | with SingleTickerProviderStateMixin {
15 | late List emitters;
16 | late Ticker _ticker;
17 |
18 | @override
19 | void initState() {
20 | super.initState();
21 | emitters = List.empty(growable: true);
22 | _ticker = createTicker((elapsed) {
23 | setState(() {});
24 | });
25 | _ticker.start();
26 | }
27 |
28 | @override
29 | void dispose() {
30 | _ticker.dispose();
31 | super.dispose();
32 | }
33 |
34 | @override
35 | Widget build(BuildContext context) {
36 | final size = MediaQuery.of(context).size;
37 | return Scaffold(
38 | backgroundColor: Colors.black,
39 | appBar: AppBar(
40 | title: const Text('Tap on the screen to display Particles'),
41 | ),
42 | body: GestureDetector(
43 | onTapDown: (details) {
44 | if (emitters.length < 38) {
45 | emitters.add(Emitter(position: details.localPosition));
46 | }
47 | },
48 | child: SizedBox(
49 | height: size.height,
50 | width: size.width,
51 | child: CustomPaint(
52 | painter: _ParticlePainter(
53 | emitters: emitters,
54 | ),
55 | ),
56 | ),
57 | ),
58 | );
59 | }
60 | }
61 |
62 | class _ParticlePainter extends CustomPainter {
63 | final List emitters;
64 |
65 | _ParticlePainter({
66 | required this.emitters,
67 | });
68 |
69 | @override
70 | void paint(Canvas canvas, Size size) {
71 | for (var emitter in emitters) {
72 | emitter.update();
73 | for (var particle in emitter.particles) {
74 | particle.update();
75 | canvas.drawCircle(
76 | Offset(particle.x, particle.y),
77 | 10,
78 | Paint()
79 | ..color = Color.fromARGB(
80 | particle.alpha,
81 | 255,
82 | 255,
83 | 255,
84 | ),
85 | );
86 | }
87 | }
88 | }
89 |
90 | @override
91 | bool shouldRepaint(covariant CustomPainter oldDelegate) => true;
92 | }
93 |
94 | class Particle {
95 | double x, y;
96 | double vx = doubleInRange(-1, 1);
97 | double vy = doubleInRange(5, 1);
98 | int alpha = 255;
99 |
100 | Particle({
101 | required this.x,
102 | required this.y,
103 | });
104 |
105 | update() {
106 | x += vx;
107 | y += vy;
108 | alpha -= 5;
109 | }
110 |
111 | bool finished() {
112 | return alpha <= 0;
113 | }
114 | }
115 |
116 | class Emitter {
117 | final Offset position;
118 | List particles;
119 | List particlesToRemove = List.empty(growable: true);
120 |
121 | Emitter({required this.position})
122 | : particles = List.generate(
123 | 1,
124 | (index) => Particle(
125 | x: position.dx,
126 | y: position.dy,
127 | ),
128 | );
129 |
130 | update() {
131 | particles.add(Particle(x: position.dx, y: position.dy));
132 | for (var particle in particles) {
133 | if (particle.finished()) particlesToRemove.add(particle);
134 | }
135 |
136 | for (var particle in particlesToRemove) {
137 | particles.remove(particle);
138 | }
139 | }
140 | }
141 |
--------------------------------------------------------------------------------
/lib/animations/coding_train_challenges/rain.dart:
--------------------------------------------------------------------------------
1 | import 'dart:math';
2 |
3 | import 'package:animation_playground/utils.dart';
4 | import 'package:flutter/material.dart';
5 | import 'package:flutter/scheduler.dart';
6 |
7 | class RainAnimation extends StatelessWidget {
8 | const RainAnimation({Key? key}) : super(key: key);
9 |
10 | @override
11 | Widget build(BuildContext context) {
12 | final screenSize = MediaQuery.of(context).size;
13 | return Scaffold(
14 | backgroundColor: Colors.black,
15 | appBar: AppBar(
16 | title: const Text('Rain Simulation'),
17 | ),
18 | body: Stack(
19 | children: [
20 | for (int index = 0; index < 300; index++)
21 | _RainDrop(
22 | screenHeight: screenSize.height,
23 | screenWidth: screenSize.width,
24 | ),
25 | ],
26 | ),
27 | );
28 | }
29 | }
30 |
31 | class _RainDrop extends StatefulWidget {
32 | final double screenHeight, screenWidth;
33 |
34 | const _RainDrop({
35 | Key? key,
36 | required this.screenHeight,
37 | required this.screenWidth,
38 | }) : super(key: key);
39 |
40 | @override
41 | State<_RainDrop> createState() => _RainDropState();
42 | }
43 |
44 | class _RainDropState extends State<_RainDrop> with SingleTickerProviderStateMixin {
45 | // vy(velocity Y) for the speed on the yAxis
46 | late double dx, dy, length, z, vy;
47 |
48 | Random random = Random();
49 | double get screenHeight => widget.screenHeight;
50 |
51 | double get screenWidth => widget.screenWidth;
52 | late final Ticker _ticker;
53 |
54 | @override
55 | void initState() {
56 | super.initState();
57 | randomizeValues();
58 | _ticker = createTicker((elapsed) {
59 | dy += vy;
60 | if (dy >= screenHeight + 100) {
61 | randomizeValues();
62 | }
63 | setState(() {});
64 | });
65 | _ticker.start();
66 | }
67 |
68 | randomizeValues() {
69 | dx = random.nextDouble() * screenWidth;
70 | dy = -500 - (random.nextDouble() * -500);
71 | z = random.nextDouble() * 20;
72 | length = rangeMap(z, 0, 20, 10, 20);
73 | vy = rangeMap(z, 0, 20, 15, 5);
74 | }
75 |
76 | @override
77 | void dispose() {
78 | _ticker.dispose();
79 | super.dispose();
80 | }
81 |
82 | @override
83 | Widget build(BuildContext context) {
84 | return Transform.translate(
85 | offset: Offset(dx, dy),
86 | child: Container(
87 | height: length,
88 | width: 2,
89 | decoration: BoxDecoration(
90 | borderRadius: BorderRadius.circular(5),
91 | color: Colors.white,
92 | border: Border.all(width: rangeMap(z, 0, 20, 1, 3)),
93 | ),
94 | ),
95 | );
96 | }
97 | }
98 |
--------------------------------------------------------------------------------
/lib/animations/coding_train_challenges/simple_particle_system.dart:
--------------------------------------------------------------------------------
1 | import 'package:animation_playground/utils.dart';
2 | import 'package:flutter/material.dart';
3 | import 'package:flutter/scheduler.dart';
4 |
5 | class SimpleParticleSystem extends StatefulWidget {
6 | const SimpleParticleSystem({Key? key}) : super(key: key);
7 |
8 | @override
9 | State createState() => _SimpleParticleSystemState();
10 | }
11 |
12 | class _SimpleParticleSystemState extends State
13 | with SingleTickerProviderStateMixin {
14 | late List particles;
15 | late List particlesToRemove;
16 | late final Ticker _ticker;
17 |
18 | @override
19 | void initState() {
20 | super.initState();
21 | particles = List.generate(1, (index) => Particle());
22 | particlesToRemove = List.empty(growable: true);
23 |
24 | _ticker = createTicker((elapsed) {
25 | particles.add(Particle());
26 | for (var particle in particlesToRemove) {
27 | particles.remove(particle);
28 | }
29 | setState(() {});
30 | });
31 | _ticker.start();
32 | }
33 |
34 | @override
35 | void dispose() {
36 | _ticker.dispose();
37 | super.dispose();
38 | }
39 |
40 | @override
41 | Widget build(BuildContext context) {
42 | final size = MediaQuery.of(context).size;
43 | return Scaffold(
44 | appBar: AppBar(
45 | title: const Text('Simple Particle System'),
46 | ),
47 | backgroundColor: Colors.black,
48 | body: SizedBox(
49 | width: size.width,
50 | height: size.height,
51 | child: CustomPaint(
52 | painter: ParticlePainter(
53 | particles: particles,
54 | particlesToRemove: particlesToRemove,
55 | ),
56 | ),
57 | ),
58 | );
59 | }
60 | }
61 |
62 | class ParticlePainter extends CustomPainter {
63 | List particles;
64 | List particlesToRemove;
65 |
66 | ParticlePainter({required this.particles, required this.particlesToRemove});
67 |
68 | @override
69 | void paint(Canvas canvas, Size size) {
70 | for (var particle in particles) {
71 | particle.setPosition(particle.x * size.width, particle.y * size.height);
72 | particle.update();
73 | var paint = Paint()
74 | ..color = Color.fromARGB(particle.opacity, 255, 255, 255)
75 | ..strokeWidth = 3.0;
76 | canvas.drawCircle(Offset(particle.x, particle.y), 13.0, paint);
77 | if (particle.finished()) particlesToRemove.add(particle);
78 | }
79 | }
80 |
81 | @override
82 | bool shouldRepaint(CustomPainter oldDelegate) => true;
83 | }
84 |
85 | class Particle {
86 | double x = 0.5;
87 | double y = 0.9;
88 | double vx = doubleInRange(-1, 1);
89 | double vy = doubleInRange(-5, -1);
90 | int opacity = 255;
91 |
92 | Particle();
93 |
94 | setPosition(double xPos, double yPos) {
95 | if (x < 1 && y < 1) {
96 | x = xPos;
97 | y = yPos;
98 | }
99 | }
100 |
101 | update() {
102 | x += vx;
103 | y += vy;
104 | if (opacity > 0) {
105 | opacity -= 3;
106 | }
107 | }
108 |
109 | bool finished() {
110 | return opacity <= 0;
111 | }
112 | }
113 |
--------------------------------------------------------------------------------
/lib/animations/grid_magnification/barrel.dart:
--------------------------------------------------------------------------------
1 | export 'fading_grid.dart';
2 | export 'grid_magnification.dart';
3 |
--------------------------------------------------------------------------------
/lib/animations/grid_magnification/fading_grid.dart:
--------------------------------------------------------------------------------
1 | import 'dart:math';
2 |
3 | import 'package:flutter/material.dart';
4 |
5 | class FadingGrid extends StatefulWidget {
6 | const FadingGrid({Key? key}) : super(key: key);
7 |
8 | @override
9 | State createState() => _FadingGridState();
10 | }
11 |
12 | class _FadingGridState extends State {
13 | Offset location = Offset.zero;
14 |
15 | @override
16 | Widget build(BuildContext context) {
17 | Size screenSize = MediaQuery.of(context).size;
18 | int squareAmountHorizontal = screenSize.width ~/ 32.7;
19 | double squareContainerSize = screenSize.width / squareAmountHorizontal;
20 | double squarePadding = 10;
21 | double squareSize = squareContainerSize - squarePadding;
22 | int squareAmountVertical =
23 | (screenSize.height / squareContainerSize).floor() - 3;
24 | return Scaffold(
25 | backgroundColor: Colors.black,
26 | appBar: AppBar(
27 | title: const Text('Fading Grid'),
28 | ),
29 | body: Center(
30 | child: GestureDetector(
31 | onPanDown: (details) {
32 | location = details.globalPosition;
33 | setState(() {});
34 | },
35 | onPanUpdate: (details) {
36 | location = details.globalPosition;
37 | setState(() {});
38 | },
39 | onPanEnd: (details) {
40 | location = Offset.zero;
41 | setState(() {});
42 | },
43 | child: SizedBox(
44 | width: screenSize.width,
45 | height: squareAmountVertical * squareContainerSize,
46 | child: CustomPaint(
47 | size: Size(
48 | screenSize.width, squareAmountVertical * squareContainerSize),
49 | painter: _GridPainter(
50 | squareAmountHorizontal: squareAmountHorizontal,
51 | squareAmountVertical: squareAmountVertical,
52 | squareContainerSize: squareContainerSize,
53 | padding: squarePadding,
54 | squareSize: squareSize,
55 | location: location,
56 | ),
57 | ),
58 | ),
59 | ),
60 | ),
61 | );
62 | }
63 | }
64 |
65 | class _GridPainter extends CustomPainter {
66 | final int squareAmountHorizontal;
67 | final int squareAmountVertical;
68 | final double squareContainerSize;
69 | final double padding;
70 | final double squareSize;
71 | final Offset location;
72 |
73 | _GridPainter({
74 | required this.squareAmountHorizontal,
75 | required this.squareAmountVertical,
76 | required this.squareContainerSize,
77 | required this.padding,
78 | required this.squareSize,
79 | required this.location,
80 | });
81 |
82 | @override
83 | void paint(Canvas canvas, Size size) {
84 | var gradient = const SweepGradient(
85 | colors: [Colors.cyan, Colors.pink, Colors.yellow, Colors.cyan]);
86 | Rect canvasRect = Rect.fromCenter(
87 | center: size.center(Offset.zero),
88 | width: size.width / 2,
89 | height: size.height / 2,
90 | );
91 | Paint paint = Paint()..shader = gradient.createShader(canvasRect);
92 | for (int i = 0; i < squareAmountHorizontal; i++) {
93 | for (int j = 0; j < squareAmountVertical; j++) {
94 | final rectPos = Offset(
95 | i * squareContainerSize + padding * 2,
96 | j * squareContainerSize + padding * 2,
97 | );
98 |
99 | final a = location.dx - rectPos.dx;
100 | final b = location.dy - rectPos.dy;
101 | final root = sqrt((a * a) + (b * b));
102 | final diagonalValue =
103 | sqrt((size.width * size.width) + (size.height * size.height));
104 | final scale = root / (diagonalValue / 2);
105 | final modifiedScale = location == Offset.zero ? 1 : (1 - scale);
106 | final fadingScale = modifiedScale > 0 ? modifiedScale : 0;
107 | Rect rect = Rect.fromCenter(
108 | center: rectPos,
109 | height: fadingScale * squareSize,
110 | width: fadingScale * squareSize,
111 | );
112 | canvas.drawRRect(
113 | RRect.fromRectAndRadius(rect, const Radius.circular(4)), paint);
114 | }
115 | }
116 | }
117 |
118 | @override
119 | bool shouldRepaint(covariant CustomPainter oldDelegate) {
120 | return true;
121 | }
122 | }
123 |
--------------------------------------------------------------------------------
/lib/animations/grid_magnification/grid_magnification.dart:
--------------------------------------------------------------------------------
1 | import 'dart:math';
2 |
3 | import 'package:flutter/material.dart';
4 |
5 | class GridMagnification extends StatefulWidget {
6 | const GridMagnification({Key? key}) : super(key: key);
7 |
8 | @override
9 | State createState() => _GridMagnificationState();
10 | }
11 |
12 | class _GridMagnificationState extends State {
13 | Offset location = Offset.zero;
14 |
15 | @override
16 | Widget build(BuildContext context) {
17 | Size screenSize = MediaQuery.of(context).size;
18 | int squareAmountHorizontal = screenSize.width ~/ 32.7;
19 | double squareContainerSize = screenSize.width / squareAmountHorizontal;
20 | double squarePadding = 10;
21 | double squareSize = squareContainerSize - squarePadding;
22 | int squareAmountVertical =
23 | (screenSize.height / squareContainerSize).floor() - 3;
24 | return Scaffold(
25 | backgroundColor: Colors.black,
26 | appBar: AppBar(
27 | title: const Text('Grid Magnification'),
28 | ),
29 | body: Center(
30 | child: GestureDetector(
31 | onPanDown: (details) {
32 | location = details.globalPosition;
33 | setState(() {});
34 | },
35 | onPanUpdate: (details) {
36 | location = details.globalPosition;
37 | setState(() {});
38 | },
39 | onPanEnd: (details) {
40 | location = Offset.zero;
41 | setState(() {});
42 | },
43 | child: SizedBox(
44 | width: screenSize.width,
45 | height: squareAmountVertical * squareContainerSize,
46 | child: CustomPaint(
47 | size: Size(
48 | screenSize.width, squareAmountVertical * squareContainerSize),
49 | painter: _GridPainter(
50 | squareAmountHorizontal: squareAmountHorizontal,
51 | squareAmountVertical: squareAmountVertical,
52 | squareContainerSize: squareContainerSize,
53 | padding: squarePadding,
54 | squareSize: squareSize,
55 | location: location,
56 | ),
57 | ),
58 | ),
59 | ),
60 | ),
61 | );
62 | }
63 | }
64 |
65 | class _GridPainter extends CustomPainter {
66 | final int squareAmountHorizontal;
67 | final int squareAmountVertical;
68 | final double squareContainerSize;
69 | final double padding;
70 | final double squareSize;
71 | final Offset location;
72 |
73 | _GridPainter({
74 | required this.squareAmountHorizontal,
75 | required this.squareAmountVertical,
76 | required this.squareContainerSize,
77 | required this.padding,
78 | required this.squareSize,
79 | required this.location,
80 | });
81 |
82 | @override
83 | void paint(Canvas canvas, Size size) {
84 | var gradient = const SweepGradient(
85 | colors: [Colors.cyan, Colors.pink, Colors.yellow, Colors.cyan]);
86 | Rect canvasRect = Rect.fromCenter(
87 | center: size.center(Offset.zero),
88 | width: size.width / 2,
89 | height: size.height / 2,
90 | );
91 | Paint paint = Paint()..color = Colors.white;
92 | paint.shader = gradient.createShader(canvasRect);
93 | const radius = 110;
94 | for (int i = 0; i < squareAmountHorizontal; i++) {
95 | for (int j = 0; j < squareAmountVertical; j++) {
96 | final rectPos = Offset(
97 | i * squareContainerSize + padding * 2,
98 | j * squareContainerSize + padding * 2,
99 | );
100 |
101 | final a = location.dx - rectPos.dx;
102 | final b = location.dy - rectPos.dy;
103 | final distance = sqrt(
104 | pow(location.dx - rectPos.dx, 2) + pow(location.dy - rectPos.dy, 2),
105 | );
106 | final median = (distance - radius) / radius;
107 | final root = sqrt((a * a) + (b * b));
108 | final scale = (root - radius) / radius;
109 | final modifiedScale = location == Offset.zero ? 1 : (1 - scale);
110 | final fadingScale = modifiedScale > 0 ? modifiedScale : 0;
111 | final translateX = a * median;
112 | final translateY = b * median;
113 | Rect rect = Rect.fromCenter(
114 | center: rectPos,
115 | height: fadingScale * squareSize,
116 | width: fadingScale * squareSize,
117 | );
118 | Rect transformedRect = rect.translate(translateX, translateY);
119 | canvas.drawRRect(
120 | RRect.fromRectAndRadius(
121 | location == Offset.zero ? rect : transformedRect,
122 | const Radius.circular(4),
123 | ),
124 | paint,
125 | );
126 | }
127 | }
128 | }
129 |
130 | @override
131 | bool shouldRepaint(covariant CustomPainter oldDelegate) {
132 | return true;
133 | }
134 | }
135 |
--------------------------------------------------------------------------------
/lib/animations/loaders/barrel.dart:
--------------------------------------------------------------------------------
1 | export 'clock_loader.dart';
2 |
--------------------------------------------------------------------------------
/lib/animations/loaders/clock_loader.dart:
--------------------------------------------------------------------------------
1 | import 'dart:math' as math;
2 |
3 | import 'package:flutter/material.dart';
4 |
5 | class ClockLoader extends StatefulWidget {
6 | const ClockLoader({Key? key}) : super(key: key);
7 |
8 | @override
9 | State createState() => _ClockLoaderState();
10 | }
11 |
12 | class _ClockLoaderState extends State
13 | with TickerProviderStateMixin {
14 | static const tickLength = 12;
15 | static const squareSize = 12.0;
16 | List colors = List.generate(tickLength, (index) => index);
17 | late Animation tickAnimation;
18 | late AnimationController animationController;
19 |
20 | @override
21 | void initState() {
22 | super.initState();
23 | animationController = AnimationController(
24 | vsync: this,
25 | duration: const Duration(milliseconds: 8000),
26 | )
27 | ..forward()..repeat();
28 | tickAnimation = Tween(
29 | begin: 0,
30 | end: 4 * math.pi,
31 | ).animate(
32 | CurvedAnimation(parent: animationController, curve: Curves.easeIn));
33 | animationController.addListener(() {
34 | if (animationController.isAnimating) {
35 | setState(() {});
36 | }
37 | });
38 | }
39 |
40 | @override
41 | void dispose() {
42 | animationController.dispose();
43 | super.dispose();
44 | }
45 |
46 | @override
47 | Widget build(BuildContext context) {
48 | const offsetAngle = (2 * math.pi) / tickLength;
49 | return Scaffold(
50 | appBar: AppBar(
51 | title: const Text('Clock Loader'),
52 | ),
53 | body: Center(
54 | child: Stack(
55 | children: [
56 | ...colors.map((e) {
57 | int index = colors.indexOf(e);
58 | final finalAngle = offsetAngle * (tickLength - 1 - index);
59 | double rotate = () {
60 | if (tickAnimation.value <= 2 * math.pi) {
61 | return math.min(finalAngle, tickAnimation.value);
62 | }
63 | if (tickAnimation.value - 2 * math.pi < finalAngle) {
64 | return finalAngle;
65 | }
66 |
67 | return tickAnimation.value;
68 | }();
69 | double yDefaultPosition = -index * squareSize;
70 | double translateY = () {
71 | if (rotate == finalAngle) {
72 | return -tickLength * squareSize;
73 | }
74 |
75 | if (tickAnimation.value > 2 * math.pi) {
76 | return (index - tickLength) * squareSize;
77 | }
78 |
79 | return yDefaultPosition;
80 | }();
81 | return TweenAnimationBuilder(
82 | tween: Tween(
83 | begin: yDefaultPosition,
84 | end: translateY,
85 | ),
86 | duration: const Duration(milliseconds: 500),
87 | builder: (context, translateYAnimValue, _) {
88 | return Transform.rotate(
89 | angle: rotate,
90 | child: Transform.translate(
91 | offset: Offset(0.0, translateYAnimValue),
92 | child: Container(
93 | height: squareSize,
94 | width: squareSize,
95 | color: Colors.white,
96 | ),
97 | ),
98 | );
99 | },
100 | );
101 | }).toList(),
102 | ],
103 | ),
104 | ),
105 | );
106 | }
107 | }
108 |
--------------------------------------------------------------------------------
/lib/animations/morphing_segmented_bar.dart:
--------------------------------------------------------------------------------
1 | import 'dart:math' as math;
2 |
3 | import 'package:animation_playground/buildcontext_extension.dart';
4 | import 'package:flutter/material.dart';
5 |
6 | enum PlanType { free, premiumMonthly, premiumYearly }
7 |
8 | class MorphingSegmentedControlPage extends StatefulWidget {
9 | const MorphingSegmentedControlPage({super.key});
10 |
11 | @override
12 | State createState() =>
13 | _MorphingSegmentedControlPageState();
14 | }
15 |
16 | class _MorphingSegmentedControlPageState
17 | extends State {
18 | PlanType _selectedPlan = PlanType.free;
19 |
20 | @override
21 | Widget build(BuildContext context) {
22 | return Scaffold(
23 | backgroundColor: Colors.white,
24 | appBar: AppBar(title: const Text('Morphing Segmented Control')),
25 | body: Column(
26 | mainAxisAlignment: MainAxisAlignment.center,
27 | crossAxisAlignment: CrossAxisAlignment.center,
28 | children: [
29 | Center(
30 | child: IntrinsicWidth(
31 | child: Container(
32 | decoration: BoxDecoration(
33 | color: Colors.white,
34 | borderRadius: BorderRadius.circular(30),
35 | border: Border.all(color: Colors.grey),
36 | boxShadow: [
37 | BoxShadow(
38 | color: Colors.grey.shade200,
39 | spreadRadius: 5,
40 | blurRadius: 7,
41 | offset: const Offset(0, 3),
42 | ),
43 | ],
44 | ),
45 | child: MorphingSegmentedControl(
46 | width: context.isMobile ? context.screenWidth - 20 : 420,
47 | height: 50,
48 | value: _selectedPlan,
49 | onChanged: (newValue) {
50 | setState(() {
51 | _selectedPlan = newValue;
52 | });
53 | },
54 | simpleTabValue: PlanType.free,
55 | simpleTabLabel: "Free",
56 | groupTabCollapsedLabel: "Premium",
57 | groupTabOptions: const [
58 | MorphingTabItem(
59 | value: PlanType.premiumMonthly,
60 | label: "Monthly",
61 | ),
62 | MorphingTabItem(
63 | value: PlanType.premiumYearly,
64 | label: "Annual",
65 | ),
66 | ],
67 | backgroundColor: Colors.white,
68 | selectedColor: Colors.black,
69 | nestedSelectedColor: Colors.white,
70 | selectedTextColor: Colors.white,
71 | unselectedTextColor: Colors.grey,
72 | nestedSelectedTextColor: Colors.black,
73 | nestedUnselectedTextColor: Colors.white,
74 | ),
75 | ),
76 | ),
77 | ),
78 | ],
79 | ),
80 | );
81 | }
82 | }
83 |
84 | class MorphingTabItem {
85 | final T value;
86 | final String label;
87 |
88 | const MorphingTabItem({required this.value, required this.label});
89 |
90 | @override
91 | bool operator ==(Object other) =>
92 | identical(this, other) ||
93 | other is MorphingTabItem &&
94 | runtimeType == other.runtimeType &&
95 | value == other.value;
96 |
97 | @override
98 | int get hashCode => value.hashCode;
99 | }
100 |
101 | class MorphingSegmentedControl extends StatefulWidget {
102 | final T value;
103 | final ValueChanged onChanged;
104 | final T simpleTabValue;
105 | final String simpleTabLabel;
106 | final String groupTabCollapsedLabel;
107 | final List> groupTabOptions;
108 | final double height;
109 | final double? width;
110 | final EdgeInsets padding;
111 | final EdgeInsets mainThumbMargin;
112 | final EdgeInsets nestedThumbMargin;
113 | final Color backgroundColor;
114 | final Color selectedColor;
115 | final Color nestedSelectedColor;
116 | final Color selectedTextColor;
117 | final Color unselectedTextColor;
118 | final Color nestedSelectedTextColor;
119 | final Color nestedUnselectedTextColor;
120 | final TextStyle? textStyle;
121 | final Duration mainAnimationDuration;
122 | final Duration nestedAnimationDuration;
123 | final Duration switchAnimationDuration;
124 | final Curve animationCurve;
125 | final Curve switchScaleInCurve;
126 | final Curve switchScaleOutCurve;
127 | final Curve switchFadeInCurve;
128 | final Curve switchFadeOutCurve;
129 | final Curve switchSlideOutCurve;
130 |
131 | const MorphingSegmentedControl({
132 | super.key,
133 | required this.value,
134 | required this.onChanged,
135 | required this.simpleTabValue,
136 | required this.simpleTabLabel,
137 | required this.groupTabCollapsedLabel,
138 | required this.groupTabOptions,
139 | this.height = 48,
140 | this.width = 320,
141 | this.padding = const EdgeInsets.all(0),
142 | this.mainThumbMargin = const EdgeInsets.all(2),
143 | this.nestedThumbMargin = const EdgeInsets.all(4),
144 | this.backgroundColor = Colors.black,
145 | this.selectedColor = Colors.white,
146 | this.nestedSelectedColor = Colors.black,
147 | this.selectedTextColor = Colors.black,
148 | this.unselectedTextColor = Colors.white,
149 | this.nestedSelectedTextColor = Colors.white,
150 | this.nestedUnselectedTextColor = Colors.black,
151 | this.textStyle,
152 | this.mainAnimationDuration = const Duration(milliseconds: 250),
153 | this.nestedAnimationDuration = const Duration(milliseconds: 250),
154 | this.switchAnimationDuration = const Duration(milliseconds: 250),
155 | this.animationCurve = Curves.easeInOut,
156 | this.switchScaleInCurve = Curves.easeOutCubic,
157 | this.switchScaleOutCurve = Curves.easeInCubic,
158 | this.switchFadeInCurve = Curves.easeIn,
159 | this.switchFadeOutCurve = Curves.easeOut,
160 | this.switchSlideOutCurve = Curves.easeOut,
161 | }) : assert(groupTabOptions.length >= 2,
162 | 'groupTabOptions must have at least two items for the default subtitle display');
163 |
164 | @override
165 | State> createState() =>
166 | _MorphingSegmentedControlState();
167 | }
168 |
169 | class _MorphingSegmentedControlState
170 | extends State> with TickerProviderStateMixin {
171 | late AnimationController _switchController;
172 | bool _wasGroupTabSelected = false;
173 |
174 | bool get _isCurrentlyGroupTabSelected =>
175 | widget.groupTabOptions.any((option) => option.value == widget.value);
176 |
177 | @override
178 | void initState() {
179 | super.initState();
180 | _wasGroupTabSelected = _isCurrentlyGroupTabSelected;
181 | _switchController = AnimationController(
182 | vsync: this,
183 | duration: widget.switchAnimationDuration,
184 | value: _wasGroupTabSelected ? 1.0 : 0.0,
185 | );
186 | }
187 |
188 | @override
189 | void didUpdateWidget(MorphingSegmentedControl oldWidget) {
190 | super.didUpdateWidget(oldWidget);
191 |
192 | final bool isNowGroupSelected = _isCurrentlyGroupTabSelected;
193 |
194 | if (_wasGroupTabSelected != isNowGroupSelected) {
195 | if (isNowGroupSelected) {
196 | _switchController.forward();
197 | } else {
198 | _switchController.reverse();
199 | }
200 | _wasGroupTabSelected = isNowGroupSelected;
201 | }
202 |
203 | if (widget.switchAnimationDuration != oldWidget.switchAnimationDuration) {
204 | _switchController.duration = widget.switchAnimationDuration;
205 | }
206 | }
207 |
208 | @override
209 | void dispose() {
210 | _switchController.dispose();
211 | super.dispose();
212 | }
213 |
214 | Map _calculateMainThumbMetrics(double maxWidth) {
215 | if (maxWidth <= 0) return {'left': 0.0, 'width': 0.0};
216 | double availableWidth = math.max(0, maxWidth - widget.padding.horizontal);
217 | double thumbWidth = availableWidth / 2;
218 | double thumbLeft = widget.padding.left;
219 | if (_isCurrentlyGroupTabSelected) {
220 | thumbLeft = widget.padding.left + (availableWidth / 2);
221 | }
222 | return {'left': thumbLeft, 'width': thumbWidth};
223 | }
224 |
225 | Widget _buildSimpleTabView({
226 | required TextStyle effectiveTextStyle,
227 | required Color simpleTextColor,
228 | }) {
229 | return Expanded(
230 | child: GestureDetector(
231 | behavior: HitTestBehavior.opaque,
232 | onTap: () => widget.onChanged(widget.simpleTabValue),
233 | child: Container(
234 | alignment: Alignment.center,
235 | child: Text(
236 | widget.simpleTabLabel,
237 | style: effectiveTextStyle.copyWith(color: simpleTextColor),
238 | maxLines: 1,
239 | overflow: TextOverflow.ellipsis,
240 | ),
241 | ),
242 | ),
243 | );
244 | }
245 |
246 | Widget _buildGroupTabAnimatedSwitcher({
247 | required TextStyle effectiveTextStyle,
248 | }) {
249 | return Expanded(
250 | child: AnimatedBuilder(
251 | animation: _switchController,
252 | builder: (context, _) {
253 | final double controllerValue = _switchController.value;
254 |
255 | final double collapsedOpacity = (1.0 -
256 | CurvedAnimation(
257 | parent: _switchController,
258 | curve: widget.switchFadeOutCurve,
259 | ).value)
260 | .clamp(0.0, 1.0);
261 | final double collapsedScale = 1.0 -
262 | (CurvedAnimation(
263 | parent: _switchController,
264 | curve: widget.switchScaleOutCurve)
265 | .value *
266 | 0.4);
267 | final Offset collapsedSlide =
268 | Tween(begin: Offset.zero, end: const Offset(0.0, -0.5))
269 | .transform(CurvedAnimation(
270 | parent: _switchController,
271 | curve: widget.switchSlideOutCurve)
272 | .value);
273 | final double expandedOpacity = CurvedAnimation(
274 | parent: _switchController, curve: widget.switchFadeInCurve)
275 | .value
276 | .clamp(0.0, 1.0);
277 | final double expandedScale = 0.6 +
278 | (CurvedAnimation(
279 | parent: _switchController,
280 | curve: widget.switchScaleInCurve)
281 | .value *
282 | 0.4);
283 |
284 | return Stack(
285 | alignment: Alignment.center,
286 | children: [
287 | if (controllerValue < 1.0)
288 | _buildCollapsedGroupView(
289 | effectiveTextStyle: effectiveTextStyle,
290 | opacity: collapsedOpacity,
291 | scale: collapsedScale,
292 | slideOffset: collapsedSlide,
293 | ),
294 | if (controllerValue > 0.0)
295 | _buildExpandedGroupView(
296 | effectiveTextStyle: effectiveTextStyle,
297 | opacity: expandedOpacity,
298 | scale: expandedScale,
299 | ),
300 | ],
301 | );
302 | },
303 | ),
304 | );
305 | }
306 |
307 | Widget _buildCollapsedGroupView({
308 | required TextStyle effectiveTextStyle,
309 | required double opacity,
310 | required double scale,
311 | required Offset slideOffset,
312 | }) {
313 | final Color groupCollapsedTextColor = widget.unselectedTextColor;
314 | final String subtitleText1 = widget.groupTabOptions.isNotEmpty
315 | ? widget.groupTabOptions[0].label
316 | : '';
317 | final String subtitleText2 = widget.groupTabOptions.length > 1
318 | ? widget.groupTabOptions[1].label
319 | : '';
320 | final double subtitleFontSize =
321 | math.max(10.0, (effectiveTextStyle.fontSize ?? 14.0) * 0.7);
322 | final Color subtitleColor = groupCollapsedTextColor.withValues(alpha: 0.6);
323 | final TextStyle subtitleStyle = effectiveTextStyle.copyWith(
324 | color: subtitleColor,
325 | height: 1.0,
326 | fontSize: subtitleFontSize,
327 | fontWeight: FontWeight.w400);
328 |
329 | return IgnorePointer(
330 | ignoring: opacity < 0.15,
331 | child: Opacity(
332 | opacity: opacity,
333 | child: Transform.translate(
334 | offset: slideOffset,
335 | child: Transform.scale(
336 | scale: scale,
337 | child: GestureDetector(
338 | behavior: HitTestBehavior.opaque,
339 | onTap: () {
340 | if (!_isCurrentlyGroupTabSelected &&
341 | widget.groupTabOptions.isNotEmpty) {
342 | widget.onChanged(widget.groupTabOptions.first.value);
343 | }
344 | },
345 | child: Container(
346 | alignment: Alignment.center,
347 | padding: const EdgeInsets.symmetric(horizontal: 4.0),
348 | child: Column(
349 | mainAxisAlignment: MainAxisAlignment.center,
350 | mainAxisSize: MainAxisSize.min,
351 | children: [
352 | Text(
353 | widget.groupTabCollapsedLabel,
354 | style: effectiveTextStyle.copyWith(
355 | color: groupCollapsedTextColor, height: 1.1),
356 | maxLines: 1,
357 | overflow: TextOverflow.ellipsis,
358 | textAlign: TextAlign.center,
359 | ),
360 | const SizedBox(height: 1),
361 | Row(
362 | mainAxisAlignment: MainAxisAlignment.center,
363 | mainAxisSize: MainAxisSize.min,
364 | children: [
365 | Flexible(
366 | child: Text(subtitleText1,
367 | style: subtitleStyle,
368 | maxLines: 1,
369 | overflow: TextOverflow.ellipsis)),
370 | Padding(
371 | padding: const EdgeInsets.symmetric(horizontal: 2.0),
372 | child: Text(' - ', style: subtitleStyle),
373 | ),
374 | Flexible(
375 | child: Text(subtitleText2,
376 | style: subtitleStyle,
377 | maxLines: 1,
378 | overflow: TextOverflow.ellipsis)),
379 | ],
380 | ),
381 | ],
382 | ),
383 | ),
384 | ),
385 | ),
386 | ),
387 | ),
388 | );
389 | }
390 |
391 | Widget _buildExpandedGroupView({
392 | required TextStyle effectiveTextStyle,
393 | required double opacity,
394 | required double scale,
395 | }) {
396 | return IgnorePointer(
397 | ignoring: opacity < 0.15,
398 | child: Opacity(
399 | opacity: opacity,
400 | child: Transform.scale(
401 | scale: scale,
402 | alignment: const Alignment(0.0, 0.3), // Align lower during scale
403 | child: _NestedTabBar(
404 | selectedTabValue: widget.value,
405 | options: widget.groupTabOptions,
406 | onChanged: widget.onChanged,
407 | parentHeight: widget.height - widget.padding.vertical,
408 | nestedThumbMargin: widget.nestedThumbMargin,
409 | animationDuration: widget.nestedAnimationDuration,
410 | animationCurve: widget.animationCurve,
411 | selectedColor: widget.nestedSelectedColor,
412 | selectedTextColor: widget.nestedSelectedTextColor,
413 | unselectedTextColor: widget.nestedUnselectedTextColor,
414 | textStyle: effectiveTextStyle,
415 | ),
416 | ),
417 | ),
418 | );
419 | }
420 |
421 | @override
422 | Widget build(BuildContext context) {
423 | final double mainThumbEffectiveHeight = math.max(
424 | 0,
425 | widget.height -
426 | widget.padding.vertical -
427 | widget.mainThumbMargin.vertical);
428 | final double mainThumbBorderRadius = mainThumbEffectiveHeight / 2;
429 | final TextStyle defaultTextStyle = widget.textStyle ??
430 | Theme.of(context).textTheme.bodyMedium ??
431 | const TextStyle();
432 | final TextStyle effectiveTextStyle =
433 | defaultTextStyle.copyWith(fontWeight: FontWeight.bold);
434 |
435 | final Color simpleTextColor = widget.value == widget.simpleTabValue
436 | ? widget.selectedTextColor
437 | : widget.unselectedTextColor;
438 |
439 | return Container(
440 | height: widget.height,
441 | width: widget.width,
442 | clipBehavior: Clip.antiAlias,
443 | decoration: BoxDecoration(
444 | color: widget.backgroundColor,
445 | borderRadius: BorderRadius.circular(widget.height / 2),
446 | ),
447 | child: LayoutBuilder(
448 | builder: (context, constraints) {
449 | final double maxWidth = constraints.maxWidth;
450 | if (maxWidth <= 0 || maxWidth.isInfinite) {
451 | return const SizedBox.shrink();
452 | }
453 |
454 | final mainThumbMetrics = _calculateMainThumbMetrics(maxWidth);
455 | final double mainThumbLeft = mainThumbMetrics['left']!;
456 | final double mainThumbWidth = mainThumbMetrics['width']!;
457 |
458 | return Stack(
459 | alignment: Alignment.centerLeft,
460 | children: [
461 | AnimatedPositioned(
462 | duration: widget.mainAnimationDuration,
463 | curve: widget.animationCurve,
464 | left: mainThumbLeft,
465 | top: widget.padding.top,
466 | bottom: widget.padding.bottom,
467 | width: mainThumbWidth,
468 | child: Container(
469 | margin: widget.mainThumbMargin,
470 | decoration: BoxDecoration(
471 | color: widget.selectedColor,
472 | borderRadius: BorderRadius.circular(
473 | mainThumbBorderRadius > 0 ? mainThumbBorderRadius : 0),
474 | ),
475 | ),
476 | ),
477 | Padding(
478 | padding: widget.padding,
479 | child: Row(
480 | children: [
481 | _buildSimpleTabView(
482 | effectiveTextStyle: effectiveTextStyle,
483 | simpleTextColor: simpleTextColor,
484 | ),
485 | _buildGroupTabAnimatedSwitcher(
486 | effectiveTextStyle: effectiveTextStyle,
487 | ),
488 | ],
489 | ),
490 | ),
491 | ],
492 | );
493 | },
494 | ),
495 | );
496 | }
497 | }
498 |
499 | class _NestedTabBar extends StatelessWidget {
500 | final T selectedTabValue;
501 | final List> options;
502 | final ValueChanged onChanged;
503 |
504 | final double parentHeight;
505 | final EdgeInsets nestedThumbMargin;
506 | final Duration animationDuration;
507 | final Curve animationCurve;
508 | final Color selectedColor;
509 | final Color selectedTextColor;
510 | final Color unselectedTextColor;
511 | final TextStyle? textStyle;
512 |
513 | const _NestedTabBar({
514 | super.key,
515 | required this.selectedTabValue,
516 | required this.options,
517 | required this.onChanged,
518 | required this.parentHeight,
519 | required this.nestedThumbMargin,
520 | required this.animationDuration,
521 | required this.animationCurve,
522 | required this.selectedColor,
523 | required this.selectedTextColor,
524 | required this.unselectedTextColor,
525 | this.textStyle,
526 | });
527 |
528 | Map _calculateInternalThumbMetrics(double maxWidth) {
529 | if (options.isEmpty || maxWidth <= 0) {
530 | return {'left': 0.0, 'width': 0.0};
531 | }
532 | int selectedIndex = options.indexWhere((o) => o.value == selectedTabValue);
533 | if (selectedIndex < 0) selectedIndex = 0;
534 |
535 | double totalOptions = options.length.toDouble();
536 | double thumbWidth = maxWidth / totalOptions;
537 | double thumbLeft = thumbWidth * selectedIndex;
538 |
539 | thumbLeft = math.max(0, thumbLeft);
540 | thumbWidth = math.min(thumbWidth, maxWidth - thumbLeft);
541 |
542 | return {'left': thumbLeft, 'width': thumbWidth};
543 | }
544 |
545 | @override
546 | Widget build(BuildContext context) {
547 | final double thumbEffectiveHeight =
548 | math.max(0, parentHeight - nestedThumbMargin.vertical);
549 | final double thumbBorderRadius = thumbEffectiveHeight / 2;
550 |
551 | return LayoutBuilder(builder: (context, constraints) {
552 | final double maxWidth = constraints.maxWidth;
553 | if (maxWidth <= 0 || maxWidth.isInfinite || options.isEmpty) {
554 | return const SizedBox.shrink();
555 | }
556 |
557 | final internalThumbMetrics = _calculateInternalThumbMetrics(maxWidth);
558 | final double thumbLeft = internalThumbMetrics['left']!;
559 | final double thumbWidth = internalThumbMetrics['width']!;
560 |
561 | return Stack(
562 | alignment: Alignment.centerLeft,
563 | children: [
564 | if (thumbWidth > 0)
565 | AnimatedPositioned(
566 | duration: animationDuration,
567 | curve: animationCurve,
568 | left: thumbLeft,
569 | top: 0,
570 | bottom: 0,
571 | width: thumbWidth,
572 | child: Container(
573 | margin: nestedThumbMargin,
574 | decoration: BoxDecoration(
575 | color: selectedColor,
576 | borderRadius: BorderRadius.circular(
577 | thumbBorderRadius > 0 ? thumbBorderRadius : 0,
578 | ),
579 | ),
580 | ),
581 | ),
582 | Row(
583 | children: List.generate(options.length, (index) {
584 | final item = options[index];
585 | final bool isSelected = item.value == selectedTabValue;
586 | final Color textColor =
587 | isSelected ? selectedTextColor : unselectedTextColor;
588 |
589 | return Expanded(
590 | child: GestureDetector(
591 | behavior: HitTestBehavior.opaque,
592 | onTap: () => onChanged(item.value),
593 | child: Container(
594 | alignment: Alignment.center,
595 | child: Text(
596 | item.label,
597 | style: textStyle?.copyWith(color: textColor) ??
598 | TextStyle(
599 | color: textColor,
600 | fontWeight: FontWeight.bold,
601 | ),
602 | maxLines: 1,
603 | overflow: TextOverflow.ellipsis,
604 | ),
605 | ),
606 | ),
607 | );
608 | }),
609 | ),
610 | ],
611 | );
612 | });
613 | }
614 | }
615 |
--------------------------------------------------------------------------------
/lib/animations/segmented_bar_flip.dart:
--------------------------------------------------------------------------------
1 | import 'dart:math' as math;
2 |
3 | import 'package:flutter/material.dart';
4 |
5 | const kSegmentBarHeight = 45.0;
6 | const color = Colors.black;
7 | const images = [
8 | 'https://images.unsplash.com/photo-1516280030429-27679b3dc9cf?w=500&auto=format&fit=crop&q=60&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxzZWFyY2h8Mnx8Y2F0c3xlbnwwfHwwfHx8MA%3D%3D',
9 | 'https://images.unsplash.com/photo-1536590158209-e9d615d525e4?w=500&auto=format&fit=crop&q=60&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxzZWFyY2h8NHx8Y2F0c3xlbnwwfHwwfHx8MA%3D%3D',
10 | 'https://images.unsplash.com/photo-1536589961747-e239b2abbec2?w=500&auto=format&fit=crop&q=60&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxzZWFyY2h8Nnx8Y2F0c3xlbnwwfHwwfHx8MA%3D%3D',
11 | 'https://images.unsplash.com/photo-1518791841217-8f162f1e1131?w=500&auto=format&fit=crop&q=60&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxzZWFyY2h8MTB8fGNhdHN8ZW58MHx8MHx8fDA%3D',
12 | 'https://images.unsplash.com/photo-1548366086-7f1b76106622?w=500&auto=format&fit=crop&q=60&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxzZWFyY2h8MTV8fGNhdHN8ZW58MHx8MHx8fDA%3D',
13 | ];
14 |
15 | class SegmentedBarFlip extends StatefulWidget {
16 | const SegmentedBarFlip({super.key});
17 |
18 | @override
19 | State createState() => _SegmentedBarFlipState();
20 | }
21 |
22 | class _SegmentedBarFlipState extends State {
23 | int _selectedIndex = 0;
24 |
25 | void _onTabChanged(int index) {
26 | setState(() {
27 | _selectedIndex = index;
28 | });
29 | }
30 |
31 | @override
32 | Widget build(BuildContext context) {
33 | return Theme(
34 | data: ThemeData(
35 | primarySwatch: Colors.blue,
36 | brightness: Brightness.light,
37 | ),
38 | child: Scaffold(
39 | body: Padding(
40 | padding: const EdgeInsets.symmetric(horizontal: 25),
41 | child: Column(
42 | crossAxisAlignment: CrossAxisAlignment.start,
43 | children: [
44 | const SizedBox(height: kToolbarHeight + 10),
45 | Center(
46 | child: CustomSegmentBar(
47 | onTabChanged: _onTabChanged,
48 | ),
49 | ),
50 | const SizedBox(height: 50),
51 | const Text('Recent', style: TextStyle(fontSize: 20)),
52 | const SizedBox(height: 15),
53 | Flexible(
54 | child: AnimatedSwitcher(
55 | duration: const Duration(milliseconds: 500),
56 | switchInCurve: Curves.easeInOut,
57 | switchOutCurve: Curves.easeInOut,
58 | child:
59 | _selectedIndex == 0 ? _buildGridView() : _buildListView(),
60 | ),
61 | ),
62 | ],
63 | ),
64 | ),
65 | ),
66 | );
67 | }
68 |
69 | Widget _buildGridView() {
70 | return GridView.builder(
71 | padding: EdgeInsets.zero,
72 | physics: const ClampingScrollPhysics(),
73 | gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
74 | crossAxisCount: 3,
75 | crossAxisSpacing: 10,
76 | mainAxisSpacing: 10,
77 | ),
78 | itemCount: 15,
79 | itemBuilder: (context, index) {
80 | return ClipRRect(
81 | borderRadius: BorderRadius.circular(10),
82 | child: Image.network(
83 | images[index % images.length],
84 | height: 100,
85 | width: 100,
86 | fit: BoxFit.cover,
87 | ),
88 | );
89 | },
90 | );
91 | }
92 |
93 | Widget _buildListView() {
94 | return ListView.separated(
95 | padding: EdgeInsets.zero,
96 | physics: const ClampingScrollPhysics(),
97 | itemCount: 5,
98 | itemBuilder: (context, index) {
99 | return Row(
100 | children: [
101 | ClipRRect(
102 | borderRadius: BorderRadius.circular(10),
103 | child: Image.network(
104 | images[index % images.length],
105 | height: 100,
106 | width: 100,
107 | fit: BoxFit.cover,
108 | ),
109 | ),
110 | const SizedBox(width: 10),
111 | const Column(
112 | crossAxisAlignment: CrossAxisAlignment.start,
113 | children: [
114 | SizedBox(height: 10),
115 | Text(
116 | 'AUD_000012374Y74WA000',
117 | style: TextStyle(fontSize: 15),
118 | ),
119 | SizedBox(height: 5),
120 | Text(
121 | '34KB',
122 | style: TextStyle(fontSize: 15, color: Colors.deepPurple),
123 | ),
124 | SizedBox(height: 5),
125 | Text(
126 | '31/99/33',
127 | style: TextStyle(fontSize: 15, color: Colors.grey),
128 | ),
129 | ],
130 | ),
131 | ],
132 | );
133 | },
134 | separatorBuilder: (context, index) => const SizedBox(height: 10),
135 | );
136 | }
137 | }
138 |
139 | class CustomSegmentBar extends StatefulWidget {
140 | final Function(int) onTabChanged;
141 | const CustomSegmentBar({super.key, required this.onTabChanged});
142 |
143 | @override
144 | State createState() => _CustomSegmentBarState();
145 | }
146 |
147 | class _CustomSegmentBarState extends State {
148 | int _selectedIndex = 0;
149 | bool _showInitialFill = true;
150 |
151 | void _onTap(int index) {
152 | setState(() {
153 | _selectedIndex = index;
154 | _showInitialFill = false;
155 | });
156 | widget.onTabChanged(index);
157 | }
158 |
159 | @override
160 | Widget build(BuildContext context) {
161 | return Row(
162 | mainAxisAlignment: MainAxisAlignment.center,
163 | children: [
164 | Segment(
165 | text: "Photos",
166 | isSelected: _selectedIndex == 0,
167 | onTap: () => _onTap(0),
168 | isLeftSegment: true,
169 | isInitiallyFilled: _showInitialFill && _selectedIndex == 0,
170 | ),
171 | Segment(
172 | text: "Videos",
173 | isSelected: _selectedIndex == 1,
174 | onTap: () => _onTap(1),
175 | isLeftSegment: false,
176 | isInitiallyFilled: false,
177 | ),
178 | ],
179 | );
180 | }
181 | }
182 |
183 | class Segment extends StatefulWidget {
184 | final String text;
185 | final bool isSelected;
186 | final VoidCallback onTap;
187 | final bool isLeftSegment;
188 | final bool isInitiallyFilled;
189 |
190 | const Segment({
191 | required this.text,
192 | required this.isSelected,
193 | required this.onTap,
194 | required this.isLeftSegment,
195 | required this.isInitiallyFilled,
196 | super.key,
197 | });
198 |
199 | @override
200 | State createState() => _SegmentState();
201 | }
202 |
203 | class _SegmentState extends State with SingleTickerProviderStateMixin {
204 | late AnimationController _controller;
205 | late Animation _animation;
206 |
207 | @override
208 | void initState() {
209 | super.initState();
210 | _controller = AnimationController(
211 | duration: const Duration(milliseconds: 500),
212 | vsync: this,
213 | );
214 | _animation = Tween(begin: 1, end: 0).animate(
215 | CurvedAnimation(parent: _controller, curve: Curves.easeInOut),
216 | );
217 |
218 | if (widget.isSelected) {
219 | _controller.value = 0;
220 | }
221 | }
222 |
223 | @override
224 | void didUpdateWidget(covariant Segment oldWidget) {
225 | super.didUpdateWidget(oldWidget);
226 | if (widget.isSelected != oldWidget.isSelected && widget.isSelected) {
227 | _controller.forward(from: 0);
228 | } else if (!widget.isSelected && oldWidget.isSelected) {
229 | _controller.reverse(from: 1);
230 | }
231 | }
232 |
233 | @override
234 | void dispose() {
235 | _controller.dispose();
236 | super.dispose();
237 | }
238 |
239 | @override
240 | Widget build(BuildContext context) {
241 | return GestureDetector(
242 | onTap: widget.onTap,
243 | child: Stack(
244 | children: [
245 | // Background for all segments with initial fill logic
246 | Container(
247 | width: 150,
248 | height: kSegmentBarHeight,
249 | alignment: Alignment.center,
250 | decoration: BoxDecoration(
251 | color: widget.isInitiallyFilled ? color : Colors.transparent,
252 | borderRadius: widget.isLeftSegment
253 | ? const BorderRadius.only(
254 | topLeft: Radius.circular(100),
255 | bottomLeft: Radius.circular(100),
256 | )
257 | : const BorderRadius.only(
258 | topRight: Radius.circular(100),
259 | bottomRight: Radius.circular(100),
260 | ),
261 | border: Border.all(
262 | color: color,
263 | width: 3,
264 | ),
265 | ),
266 | child: Text(
267 | widget.text,
268 | style: TextStyle(
269 | fontSize: 20,
270 | color: widget.isInitiallyFilled ? Colors.white : color,
271 | fontWeight: FontWeight.w600,
272 | ),
273 | ),
274 | ),
275 | AnimatedBuilder(
276 | animation: _animation,
277 | builder: (context, child) {
278 | final double rotationAngle = widget.isSelected
279 | ? _animation.value * math.pi / 2
280 | : (1 - _animation.value) * math.pi / 2;
281 |
282 | return Transform(
283 | alignment: widget.isLeftSegment
284 | ? Alignment.centerRight
285 | : Alignment.centerLeft,
286 | transform: Matrix4.identity()
287 | ..setEntry(3, 2, 0.001)
288 | ..rotateY(
289 | widget.isLeftSegment ? -rotationAngle : rotationAngle),
290 | child: Container(
291 | width: 150,
292 | height: kSegmentBarHeight,
293 | alignment: Alignment.center,
294 | decoration: BoxDecoration(
295 | color: widget.isSelected ? color : Colors.transparent,
296 | borderRadius: widget.isLeftSegment
297 | ? const BorderRadius.only(
298 | topLeft: Radius.circular(100),
299 | bottomLeft: Radius.circular(100),
300 | )
301 | : const BorderRadius.only(
302 | topRight: Radius.circular(100),
303 | bottomRight: Radius.circular(100),
304 | ),
305 | ),
306 | child: Text(
307 | widget.text,
308 | style: TextStyle(
309 | fontSize: 20,
310 | color:
311 | widget.isSelected ? Colors.white : Colors.transparent,
312 | fontWeight: FontWeight.w600,
313 | ),
314 | ),
315 | ),
316 | );
317 | },
318 | ),
319 | ],
320 | ),
321 | );
322 | }
323 | }
324 |
--------------------------------------------------------------------------------
/lib/animations_list.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | List animationList = [
4 | AnimationPage(
5 | title: 'Fading Grid',
6 | route: '/fading-grid',
7 | icon: Icons.grid_view_rounded,
8 | ),
9 | AnimationPage(
10 | title: 'Grid Magnification',
11 | route: '/grid-magnification',
12 | icon: Icons.grid_view_rounded,
13 | ),
14 | AnimationPage(
15 | title: '3D Card',
16 | route: '/3d-card',
17 | icon: Icons.threed_rotation,
18 | ),
19 | AnimationPage(
20 | title: 'Bouncing DVD',
21 | route: '/bouncing-dvd',
22 | icon: Icons.animation,
23 | ),
24 | AnimationPage(
25 | title: 'Clock Loader',
26 | route: '/clock-loader',
27 | icon: Icons.access_time_rounded,
28 | ),
29 | AnimationPage(
30 | title: 'Rain',
31 | route: '/rain',
32 | icon: Icons.thunderstorm_outlined,
33 | ),
34 | AnimationPage(
35 | title: 'Fractal Pyramid Shader',
36 | route: '/pyramid-shader',
37 | icon: Icons.animation,
38 | ),
39 | AnimationPage(
40 | title: 'Metaball FAB',
41 | route: '/metaball-fab',
42 | icon: Icons.animation,
43 | ),
44 | AnimationPage(
45 | title: 'Simple Particle System',
46 | route: '/simple-particle-system',
47 | icon: Icons.snowing,
48 | ),
49 | AnimationPage(
50 | title: 'The Bouncing Ball',
51 | route: '/bouncing-ball',
52 | icon: Icons.sports_baseball,
53 | ),
54 | AnimationPage(
55 | title: 'Particle System with emitters',
56 | route: '/particle-system-with-emitters',
57 | icon: Icons.snowing,
58 | ),
59 | AnimationPage(
60 | title: 'Painting with Pixels',
61 | route: '/painting-with-pixels',
62 | icon: Icons.format_paint,
63 | ),
64 | AnimationPage(
65 | title: 'Segmented bar Flip animation',
66 | route: '/segmented-bar-flip-animation',
67 | icon: Icons.tab,
68 | ),
69 | AnimationPage(
70 | title: 'MorphingSegmentedControl',
71 | route: '/morphing-segmented-control',
72 | icon: Icons.animation,
73 | ),
74 | ];
75 |
76 | class AnimationPage {
77 | final String title;
78 | final String route;
79 | final IconData icon;
80 |
81 | AnimationPage({required this.title, required this.route, required this.icon});
82 | }
83 |
--------------------------------------------------------------------------------
/lib/buildcontext_extension.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | extension BuildContextExtension on BuildContext {
4 | double get screenWidth => MediaQuery.sizeOf(this).width;
5 | double get screenHeight => MediaQuery.sizeOf(this).height;
6 |
7 | double get screenWidthFraction => screenWidth / 100;
8 |
9 | bool get isMobile => screenWidth < 600;
10 | }
11 |
--------------------------------------------------------------------------------
/lib/list_page.dart:
--------------------------------------------------------------------------------
1 | import 'package:animation_playground/animations_list.dart';
2 | import 'package:flutter/material.dart';
3 |
4 | class ListPage extends StatelessWidget {
5 | const ListPage({Key? key}) : super(key: key);
6 |
7 | @override
8 | Widget build(BuildContext context) {
9 | return Scaffold(
10 | appBar: AppBar(
11 | title: const Text('Animation Playground'),
12 | elevation: 0,
13 | actions: [
14 | IconButton(
15 | onPressed: () {
16 | showAboutDialog(
17 | context: context,
18 | children: [
19 | const Text(
20 | 'This is a project where i basically dump some animations '
21 | 'i work on from time to time. I hope it inspires and '
22 | 'help people with Flutter animations.',
23 | ),
24 | const SizedBox(height: 15),
25 | const Row(
26 | mainAxisAlignment: MainAxisAlignment.end,
27 | children: [
28 | Text(
29 | '- JideGuru 💙',
30 | style: TextStyle(fontWeight: FontWeight.bold),
31 | ),
32 | ],
33 | ),
34 | ],
35 | );
36 | },
37 | icon: const Icon(Icons.info_outline),
38 | ),
39 | ],
40 | ),
41 | body: ListView.builder(
42 | itemCount: animationList.length,
43 | itemBuilder: (BuildContext context, int index) {
44 | AnimationPage page = animationList[index];
45 | return ListTile(
46 | leading: Icon(page.icon),
47 | title: Text(page.title),
48 | onTap: () {
49 | Navigator.pushNamed(context, page.route);
50 | },
51 | );
52 | },
53 | ),
54 | );
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/lib/main.dart:
--------------------------------------------------------------------------------
1 | import 'package:animation_playground/routes.dart';
2 | import 'package:flutter/material.dart';
3 | import 'package:flutter_web_plugins/url_strategy.dart';
4 |
5 | void main() {
6 | usePathUrlStrategy();
7 | runApp(const MyApp());
8 | }
9 |
10 | class MyApp extends StatelessWidget {
11 | const MyApp({super.key});
12 |
13 | @override
14 | Widget build(BuildContext context) {
15 | return MaterialApp(
16 | title: 'Animation Playground',
17 | theme: ThemeData(
18 | primarySwatch: Colors.blue,
19 | brightness: Brightness.dark,
20 | ),
21 | initialRoute: '/',
22 | routes: routes,
23 | );
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/lib/random_extension.dart:
--------------------------------------------------------------------------------
1 | import 'dart:math';
2 |
3 | Random random = Random();
4 |
5 | extension RandomExtension on Random {
6 | double fromRange(double min, double max) =>
7 | (nextDouble() * (max - min + 1)).floor() + min;
8 | }
--------------------------------------------------------------------------------
/lib/routes.dart:
--------------------------------------------------------------------------------
1 | import 'package:animation_playground/animations/segmented_bar_flip.dart';
2 | import 'package:animation_playground/list_page.dart';
3 | import 'package:animation_playground/shaders/barrel.dart';
4 | import 'package:flutter/material.dart';
5 |
6 | import 'animations/card/barrel.dart';
7 | import 'animations/coding_train_challenges/barrel.dart';
8 | import 'animations/grid_magnification/barrel.dart';
9 | import 'animations/loaders/barrel.dart';
10 | import 'animations/morphing_segmented_bar.dart';
11 |
12 | Map routes = {
13 | '/': (context) => const ListPage(),
14 | '/fading-grid': (context) => const FadingGrid(),
15 | '/grid-magnification': (context) => const GridMagnification(),
16 | '/3d-card': (context) => const ThreeDimensionalCard(),
17 | '/bouncing-dvd': (context) => const BouncingDVD(),
18 | '/clock-loader': (context) => const ClockLoader(),
19 | '/rain': (context) => const RainAnimation(),
20 | '/pyramid-shader': (context) => const PyramidShader(),
21 | '/metaball-fab': (context) => const MetaballFAB(),
22 | '/simple-particle-system': (context) => const SimpleParticleSystem(),
23 | '/bouncing-ball': (context) => const BouncingBall(),
24 | '/particle-system-with-emitters': (context) =>
25 | const ParticleSystemWithEmitters(),
26 | '/painting-with-pixels': (context) => const PaintingWithPixels(),
27 | '/segmented-bar-flip-animation': (context) => const SegmentedBarFlip(),
28 | '/morphing-segmented-control': (context) =>
29 | const MorphingSegmentedControlPage(),
30 | };
31 |
--------------------------------------------------------------------------------
/lib/shaders/barrel.dart:
--------------------------------------------------------------------------------
1 | export 'fractal_pyramid.dart';
2 | export 'metaball_fab.dart';
3 |
--------------------------------------------------------------------------------
/lib/shaders/fractal_pyramid.dart:
--------------------------------------------------------------------------------
1 | import 'dart:ui' as ui;
2 |
3 | import 'package:flutter/material.dart';
4 | import 'package:flutter/scheduler.dart';
5 | import 'package:flutter_shaders/flutter_shaders.dart';
6 |
7 | // This shader was taken from ShaderToy
8 | // Origin of Shader: https://www.shadertoy.com/view/tsXBzS
9 | class PyramidShader extends StatefulWidget {
10 | const PyramidShader({Key? key}) : super(key: key);
11 |
12 | @override
13 | State createState() => _PyramidShaderState();
14 | }
15 |
16 | class _PyramidShaderState extends State
17 | with SingleTickerProviderStateMixin {
18 | double time = 0;
19 |
20 | late final Ticker _ticker;
21 |
22 | @override
23 | void initState() {
24 | super.initState();
25 | _ticker = createTicker((elapsed) {
26 | time += 0.015;
27 | setState(() {});
28 | });
29 | _ticker.start();
30 | }
31 |
32 | @override
33 | void dispose() {
34 | _ticker.dispose();
35 | super.dispose();
36 | }
37 |
38 | @override
39 | Widget build(BuildContext context) {
40 | final size = MediaQuery.of(context).size;
41 | return Scaffold(
42 | appBar: AppBar(
43 | title: const Text('Fractal Pyramid Shader'),
44 | ),
45 | backgroundColor: Colors.black,
46 | body: ShaderBuilder(
47 | assetKey: 'shaders/pyramid.glsl',
48 | child: SizedBox(width: size.width, height: size.height),
49 | (context, shader, child) {
50 | return AnimatedSampler(
51 | child: child!,
52 | (ui.Image image, Size size, Canvas canvas) {
53 | shader
54 | ..setFloat(0, time)
55 | ..setFloat(1, size.width)
56 | ..setFloat(2, size.height);
57 | canvas.drawPaint(Paint()..shader = shader);
58 | },
59 | );
60 | },
61 | ),
62 | );
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/lib/shaders/metaball_fab.dart:
--------------------------------------------------------------------------------
1 | import 'dart:ui' as ui;
2 |
3 | import 'package:flutter/material.dart';
4 | import 'package:flutter_shaders/flutter_shaders.dart';
5 |
6 | class MetaballFAB extends StatefulWidget {
7 | const MetaballFAB({Key? key}) : super(key: key);
8 |
9 | @override
10 | State createState() => _MetaballFABState();
11 | }
12 |
13 | class _MetaballFABState extends State
14 | with TickerProviderStateMixin {
15 | late Offset mainButtonPos;
16 | late Offset firstButtonPos;
17 | late Offset secondButtonPos;
18 | late final AnimationController _firstController;
19 | late final Animation _firstAnimation;
20 | late final AnimationController _secondController;
21 | late final Animation _secondAnimation;
22 | bool expanded = false;
23 |
24 | @override
25 | void initState() {
26 | super.initState();
27 | var screenWidth =
28 | (ui.window.physicalSize.shortestSide / ui.window.devicePixelRatio);
29 | var screenHeight =
30 | (ui.window.physicalSize.longestSide / ui.window.devicePixelRatio);
31 | mainButtonPos = Offset(screenWidth / 2, screenHeight - 100);
32 | firstButtonPos = Offset(screenWidth / 2, screenHeight - 100);
33 | secondButtonPos = Offset(screenWidth / 2, screenHeight - 100);
34 | _firstController = AnimationController(
35 | // value: _open ? 1.0 : 0.0,
36 | duration: const Duration(milliseconds: 500),
37 | vsync: this,
38 | );
39 | _firstAnimation = Tween(
40 | begin: firstButtonPos,
41 | end: Offset(firstButtonPos.dx, firstButtonPos.dy - 250),
42 | ).animate(_firstController);
43 |
44 | _secondController = AnimationController(
45 | // value: _open ? 1.0 : 0.0,
46 | duration: const Duration(milliseconds: 500),
47 | vsync: this,
48 | );
49 | _secondAnimation = Tween(
50 | begin: secondButtonPos,
51 | end: Offset(secondButtonPos.dx, secondButtonPos.dy - 140),
52 | ).animate(_secondController);
53 |
54 | _firstController.addListener(() {
55 | setState(() {});
56 | });
57 | _secondController.addListener(() {
58 | setState(() {});
59 | });
60 | }
61 |
62 | @override
63 | Widget build(BuildContext context) {
64 | return Scaffold(
65 | appBar: AppBar(
66 | title: const Text('Metaball FAB'),
67 | ),
68 | backgroundColor: Colors.black,
69 | body: ShaderBuilder(
70 | assetKey: 'shaders/metaball_shader.frag',
71 | child: Stack(
72 | children: [
73 | Positioned(
74 | top: firstButtonPos.dy,
75 | left: firstButtonPos.dx,
76 | child: Container(
77 | height: 40,
78 | width: 40,
79 | color: Colors.transparent,
80 | ),
81 | ),
82 | Positioned(
83 | top: mainButtonPos.dy -100,
84 | left: mainButtonPos.dx - 90,
85 | child: GestureDetector(
86 | onTap: () {
87 | if (expanded) {
88 | _firstController.reverse();
89 | _secondController.reverse();
90 | } else {
91 | _firstController.forward();
92 | _secondController.forward();
93 | }
94 | expanded = !expanded;
95 | },
96 | child: Container(
97 | height: 150,
98 | width: 150,
99 | color: Colors.transparent,
100 | ),
101 | ),
102 | ),
103 | ],
104 | ),
105 | (context, shader, child) {
106 | return AnimatedSampler(
107 | child: child!,
108 | (ui.Image image, Size size, Canvas canvas) {
109 | shader
110 | ..setFloat(0, mainButtonPos.dx)
111 | ..setFloat(1, mainButtonPos.dy)
112 | ..setFloat(2, 90)
113 | ..setFloat(3, _firstAnimation.value.dx)
114 | ..setFloat(4, _firstAnimation.value.dy)
115 | ..setFloat(5, 40)
116 | ..setFloat(6, 3)
117 | ..setFloat(7, 1.9)
118 | ..setFloat(8, 10.0)
119 | ..setFloat(9, _secondAnimation.value.dx)
120 | ..setFloat(10, _secondAnimation.value.dy)
121 | ..setFloat(11, 40);
122 | canvas.drawRect(
123 | Offset.zero & size,
124 | Paint()
125 | ..color = Colors.white
126 | ..shader = shader,
127 | );
128 |
129 | // canvas.drawPaint(
130 | // Paint()
131 | // ..shader = shader
132 | // ..color = Colors.black,
133 | // );
134 | // canvas.drawCircle(dragOffset - Offset(0, 50), 20, Paint()..color = Colors.white);
135 | // canvas.drawCircle(
136 | // size.center(Offset.zero), 20, Paint()..color = Colors.white);
137 | },
138 | );
139 | },
140 | ),
141 | );
142 | }
143 | }
144 |
--------------------------------------------------------------------------------
/lib/utils.dart:
--------------------------------------------------------------------------------
1 | import 'dart:math' as math;
2 | import 'dart:math';
3 |
4 | import 'package:flutter/material.dart';
5 |
6 | List colors = [
7 | Colors.green,
8 | Colors.blue,
9 | Colors.indigo,
10 | Colors.purple,
11 | Colors.pink,
12 | Colors.orange,
13 | Colors.yellow,
14 | Colors.greenAccent,
15 | Colors.green,
16 | ];
17 |
18 | const fullAngleInRadians = math.pi * 2;
19 |
20 | double normalizeAngle(double angle) => normalize(angle, fullAngleInRadians);
21 |
22 | Offset toPolar(Offset center, double radians, double radius) =>
23 | center + Offset.fromDirection(radians, radius);
24 |
25 | double normalize(double value, double max) => (value % max + max) % max;
26 |
27 | double toAngle(Offset position, Offset center) => (position - center).direction;
28 |
29 | double toRadian(double value) => (value * math.pi) / 180;
30 |
31 | /// Re-maps a number from one range to another
32 | /// See map Function in processing https://processing.org/reference/map_.html
33 | /// https://stackoverflow.com/a/5735770/10835183
34 | double rangeMap(
35 | double x, double inMin, double inMax, double outMin, double outMax) {
36 | return (x - inMin) * (outMax - outMin) / (inMax - inMin) + outMin;
37 | }
38 |
39 | Random _random = Random();
40 |
41 | double doubleInRange(num start, num end) =>
42 | _random.nextDouble() * (end - start) + start;
43 |
--------------------------------------------------------------------------------
/macos/.gitignore:
--------------------------------------------------------------------------------
1 | # Flutter-related
2 | **/Flutter/ephemeral/
3 | **/Pods/
4 |
5 | # Xcode-related
6 | **/dgph
7 | **/xcuserdata/
8 |
--------------------------------------------------------------------------------
/macos/Flutter/Flutter-Debug.xcconfig:
--------------------------------------------------------------------------------
1 | #include "ephemeral/Flutter-Generated.xcconfig"
2 |
--------------------------------------------------------------------------------
/macos/Flutter/Flutter-Release.xcconfig:
--------------------------------------------------------------------------------
1 | #include "ephemeral/Flutter-Generated.xcconfig"
2 |
--------------------------------------------------------------------------------
/macos/Flutter/GeneratedPluginRegistrant.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Generated file. Do not edit.
3 | //
4 |
5 | import FlutterMacOS
6 | import Foundation
7 |
8 |
9 | func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
10 | }
11 |
--------------------------------------------------------------------------------
/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 |
69 |
71 |
77 |
78 |
79 |
80 |
82 |
83 |
86 |
87 |
88 |
--------------------------------------------------------------------------------
/macos/Runner.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/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/JideGuru/animation_playground/b53a541c25039b11aadbabb5c173964242e980da/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png
--------------------------------------------------------------------------------
/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JideGuru/animation_playground/b53a541c25039b11aadbabb5c173964242e980da/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png
--------------------------------------------------------------------------------
/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JideGuru/animation_playground/b53a541c25039b11aadbabb5c173964242e980da/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png
--------------------------------------------------------------------------------
/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JideGuru/animation_playground/b53a541c25039b11aadbabb5c173964242e980da/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png
--------------------------------------------------------------------------------
/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JideGuru/animation_playground/b53a541c25039b11aadbabb5c173964242e980da/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png
--------------------------------------------------------------------------------
/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JideGuru/animation_playground/b53a541c25039b11aadbabb5c173964242e980da/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png
--------------------------------------------------------------------------------
/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JideGuru/animation_playground/b53a541c25039b11aadbabb5c173964242e980da/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 = animation_playground
9 |
10 | // The application's bundle identifier
11 | PRODUCT_BUNDLE_IDENTIFIER = com.jideguru.animationPlayground
12 |
13 | // The copyright displayed in application information
14 | PRODUCT_COPYRIGHT = Copyright © 2023 com.jideguru. 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.server
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/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 |
32 |
33 |
--------------------------------------------------------------------------------
/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.lock:
--------------------------------------------------------------------------------
1 | # Generated by pub
2 | # See https://dart.dev/tools/pub/glossary#lockfile
3 | packages:
4 | archive:
5 | dependency: transitive
6 | description:
7 | name: archive
8 | sha256: "7dcbd0f87fe5f61cb28da39a1a8b70dbc106e2fe0516f7836eb7bb2948481a12"
9 | url: "https://pub.dev"
10 | source: hosted
11 | version: "4.0.5"
12 | async:
13 | dependency: transitive
14 | description:
15 | name: async
16 | sha256: d2872f9c19731c2e5f10444b14686eb7cc85c76274bd6c16e1816bff9a3bab63
17 | url: "https://pub.dev"
18 | source: hosted
19 | version: "2.12.0"
20 | boolean_selector:
21 | dependency: transitive
22 | description:
23 | name: boolean_selector
24 | sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea"
25 | url: "https://pub.dev"
26 | source: hosted
27 | version: "2.1.2"
28 | characters:
29 | dependency: transitive
30 | description:
31 | name: characters
32 | sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803
33 | url: "https://pub.dev"
34 | source: hosted
35 | version: "1.4.0"
36 | clock:
37 | dependency: transitive
38 | description:
39 | name: clock
40 | sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b
41 | url: "https://pub.dev"
42 | source: hosted
43 | version: "1.1.2"
44 | collection:
45 | dependency: transitive
46 | description:
47 | name: collection
48 | sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76"
49 | url: "https://pub.dev"
50 | source: hosted
51 | version: "1.19.1"
52 | crypto:
53 | dependency: transitive
54 | description:
55 | name: crypto
56 | sha256: "1e445881f28f22d6140f181e07737b22f1e099a5e1ff94b0af2f9e4a463f4855"
57 | url: "https://pub.dev"
58 | source: hosted
59 | version: "3.0.6"
60 | cupertino_icons:
61 | dependency: "direct main"
62 | description:
63 | name: cupertino_icons
64 | sha256: ba631d1c7f7bef6b729a622b7b752645a2d076dba9976925b8f25725a30e1ee6
65 | url: "https://pub.dev"
66 | source: hosted
67 | version: "1.0.8"
68 | fake_async:
69 | dependency: transitive
70 | description:
71 | name: fake_async
72 | sha256: "6a95e56b2449df2273fd8c45a662d6947ce1ebb7aafe80e550a3f68297f3cacc"
73 | url: "https://pub.dev"
74 | source: hosted
75 | version: "1.3.2"
76 | ffi:
77 | dependency: transitive
78 | description:
79 | name: ffi
80 | sha256: "289279317b4b16eb2bb7e271abccd4bf84ec9bdcbe999e278a94b804f5630418"
81 | url: "https://pub.dev"
82 | source: hosted
83 | version: "2.1.4"
84 | flutter:
85 | dependency: "direct main"
86 | description: flutter
87 | source: sdk
88 | version: "0.0.0"
89 | flutter_lints:
90 | dependency: "direct dev"
91 | description:
92 | name: flutter_lints
93 | sha256: a25a15ebbdfc33ab1cd26c63a6ee519df92338a9c10f122adda92938253bef04
94 | url: "https://pub.dev"
95 | source: hosted
96 | version: "2.0.3"
97 | flutter_shaders:
98 | dependency: "direct main"
99 | description:
100 | name: flutter_shaders
101 | sha256: "1cf98f699701b520ed029c144f22c478c1f37f5784a4789b61d4fdbe95350a56"
102 | url: "https://pub.dev"
103 | source: hosted
104 | version: "0.0.6"
105 | flutter_test:
106 | dependency: "direct dev"
107 | description: flutter
108 | source: sdk
109 | version: "0.0.0"
110 | flutter_web_plugins:
111 | dependency: "direct main"
112 | description: flutter
113 | source: sdk
114 | version: "0.0.0"
115 | image:
116 | dependency: "direct main"
117 | description:
118 | name: image
119 | sha256: "4e973fcf4caae1a4be2fa0a13157aa38a8f9cb049db6529aa00b4d71abc4d928"
120 | url: "https://pub.dev"
121 | source: hosted
122 | version: "4.5.4"
123 | leak_tracker:
124 | dependency: transitive
125 | description:
126 | name: leak_tracker
127 | sha256: c35baad643ba394b40aac41080300150a4f08fd0fd6a10378f8f7c6bc161acec
128 | url: "https://pub.dev"
129 | source: hosted
130 | version: "10.0.8"
131 | leak_tracker_flutter_testing:
132 | dependency: transitive
133 | description:
134 | name: leak_tracker_flutter_testing
135 | sha256: f8b613e7e6a13ec79cfdc0e97638fddb3ab848452eff057653abd3edba760573
136 | url: "https://pub.dev"
137 | source: hosted
138 | version: "3.0.9"
139 | leak_tracker_testing:
140 | dependency: transitive
141 | description:
142 | name: leak_tracker_testing
143 | sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3"
144 | url: "https://pub.dev"
145 | source: hosted
146 | version: "3.0.1"
147 | lints:
148 | dependency: transitive
149 | description:
150 | name: lints
151 | sha256: "0a217c6c989d21039f1498c3ed9f3ed71b354e69873f13a8dfc3c9fe76f1b452"
152 | url: "https://pub.dev"
153 | source: hosted
154 | version: "2.1.1"
155 | matcher:
156 | dependency: transitive
157 | description:
158 | name: matcher
159 | sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2
160 | url: "https://pub.dev"
161 | source: hosted
162 | version: "0.12.17"
163 | material_color_utilities:
164 | dependency: transitive
165 | description:
166 | name: material_color_utilities
167 | sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec
168 | url: "https://pub.dev"
169 | source: hosted
170 | version: "0.11.1"
171 | meta:
172 | dependency: transitive
173 | description:
174 | name: meta
175 | sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c
176 | url: "https://pub.dev"
177 | source: hosted
178 | version: "1.16.0"
179 | path:
180 | dependency: transitive
181 | description:
182 | name: path
183 | sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5"
184 | url: "https://pub.dev"
185 | source: hosted
186 | version: "1.9.1"
187 | petitparser:
188 | dependency: transitive
189 | description:
190 | name: petitparser
191 | sha256: "07c8f0b1913bcde1ff0d26e57ace2f3012ccbf2b204e070290dad3bb22797646"
192 | url: "https://pub.dev"
193 | source: hosted
194 | version: "6.1.0"
195 | posix:
196 | dependency: transitive
197 | description:
198 | name: posix
199 | sha256: a0117dc2167805aa9125b82eee515cc891819bac2f538c83646d355b16f58b9a
200 | url: "https://pub.dev"
201 | source: hosted
202 | version: "6.0.1"
203 | sky_engine:
204 | dependency: transitive
205 | description: flutter
206 | source: sdk
207 | version: "0.0.0"
208 | source_span:
209 | dependency: transitive
210 | description:
211 | name: source_span
212 | sha256: "254ee5351d6cb365c859e20ee823c3bb479bf4a293c22d17a9f1bf144ce86f7c"
213 | url: "https://pub.dev"
214 | source: hosted
215 | version: "1.10.1"
216 | stack_trace:
217 | dependency: transitive
218 | description:
219 | name: stack_trace
220 | sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1"
221 | url: "https://pub.dev"
222 | source: hosted
223 | version: "1.12.1"
224 | stream_channel:
225 | dependency: transitive
226 | description:
227 | name: stream_channel
228 | sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d"
229 | url: "https://pub.dev"
230 | source: hosted
231 | version: "2.1.4"
232 | string_scanner:
233 | dependency: transitive
234 | description:
235 | name: string_scanner
236 | sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43"
237 | url: "https://pub.dev"
238 | source: hosted
239 | version: "1.4.1"
240 | term_glyph:
241 | dependency: transitive
242 | description:
243 | name: term_glyph
244 | sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e"
245 | url: "https://pub.dev"
246 | source: hosted
247 | version: "1.2.2"
248 | test_api:
249 | dependency: transitive
250 | description:
251 | name: test_api
252 | sha256: fb31f383e2ee25fbbfe06b40fe21e1e458d14080e3c67e7ba0acfde4df4e0bbd
253 | url: "https://pub.dev"
254 | source: hosted
255 | version: "0.7.4"
256 | typed_data:
257 | dependency: transitive
258 | description:
259 | name: typed_data
260 | sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006
261 | url: "https://pub.dev"
262 | source: hosted
263 | version: "1.4.0"
264 | vector_math:
265 | dependency: transitive
266 | description:
267 | name: vector_math
268 | sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803"
269 | url: "https://pub.dev"
270 | source: hosted
271 | version: "2.1.4"
272 | vm_service:
273 | dependency: transitive
274 | description:
275 | name: vm_service
276 | sha256: "0968250880a6c5fe7edc067ed0a13d4bae1577fe2771dcf3010d52c4a9d3ca14"
277 | url: "https://pub.dev"
278 | source: hosted
279 | version: "14.3.1"
280 | xml:
281 | dependency: transitive
282 | description:
283 | name: xml
284 | sha256: b015a8ad1c488f66851d762d3090a21c600e479dc75e68328c52774040cf9226
285 | url: "https://pub.dev"
286 | source: hosted
287 | version: "6.5.0"
288 | sdks:
289 | dart: ">=3.7.0 <4.0.0"
290 | flutter: ">=3.18.0-18.0.pre.54"
291 |
--------------------------------------------------------------------------------
/pubspec.yaml:
--------------------------------------------------------------------------------
1 | name: animation_playground
2 | description: A new Flutter project.
3 |
4 | publish_to: 'none' # Remove this line if you wish to publish to pub.dev
5 |
6 | version: 1.0.0+1
7 |
8 | environment:
9 | sdk: '>=2.18.2 <3.0.0'
10 |
11 | dependencies:
12 | flutter:
13 | sdk: flutter
14 | flutter_web_plugins:
15 | sdk: flutter
16 | cupertino_icons: ^1.0.2
17 | flutter_shaders: ^0.0.6
18 | image: ^4.0.15
19 |
20 | dev_dependencies:
21 | flutter_test:
22 | sdk: flutter
23 | flutter_lints: ^2.0.0
24 |
25 | flutter:
26 | uses-material-design: true
27 |
28 | # To add assets to your application, add an assets section, like this:
29 | assets:
30 | - assets/images/
31 | # - images/a_dot_ham.jpeg
32 |
33 | shaders:
34 | - shaders/metaball_shader.frag
35 | - shaders/pyramid.glsl
36 |
37 | # An image asset can refer to one or more resolution-specific "variants", see
38 | # https://flutter.dev/assets-and-images/#resolution-aware
39 |
40 | # For details regarding adding assets from package dependencies, see
41 | # https://flutter.dev/assets-and-images/#from-packages
42 |
43 | # To add custom fonts to your application, add a fonts section here,
44 | # in this "flutter" section. Each entry in this list should have a
45 | # "family" key with the font family name, and a "fonts" key with a
46 | # list giving the asset and other descriptors for the font. For
47 | # example:
48 | # fonts:
49 | # - family: Schyler
50 | # fonts:
51 | # - asset: fonts/Schyler-Regular.ttf
52 | # - asset: fonts/Schyler-Italic.ttf
53 | # style: italic
54 | # - family: Trajan Pro
55 | # fonts:
56 | # - asset: fonts/TrajanPro.ttf
57 | # - asset: fonts/TrajanPro_Bold.ttf
58 | # weight: 700
59 | #
60 | # For details regarding fonts from package dependencies,
61 | # see https://flutter.dev/custom-fonts/#from-packages
62 |
--------------------------------------------------------------------------------
/shaders/metaball_shader.frag:
--------------------------------------------------------------------------------
1 | /// ref: https://github.com/T99Rots/flutter_metaballs/blob/main/lib/metaballs_shader.glsl
2 |
3 | #version 320 es
4 |
5 | precision highp float;
6 |
7 | out vec4 fragColor;
8 |
9 | uniform vec3 metaball1;
10 | uniform vec3 metaball2;
11 | uniform float metaballs;
12 | uniform float minimumGlowSum;
13 | uniform float glowIntensity;
14 | uniform vec3 metaball3;
15 |
16 | float addSum(vec3 metaball, vec2 coords) {
17 | float dx = metaball.x - coords.x;
18 | float dy = metaball.y - coords.y;
19 | float radius = metaball.z;
20 | return ((radius * radius) / (dx * dx + dy * dy));
21 | }
22 |
23 | vec4 noise(vec4 v){
24 | // ensure reasonable range
25 | v = fract(v) + fract(v*1e4) + fract(v*1e-4);
26 | // seed
27 | v += vec4(0.12345, 0.6789, 0.314159, 0.271828);
28 | // more iterations => more random
29 | v = fract(v*dot(v, v)*123.456);
30 | v = fract(v*dot(v, v)*123.456);
31 | return v;
32 | }
33 |
34 | float getSum(vec2 coords) {
35 | float sum = 0.0;
36 | if (metaballs < 1.0) return sum;
37 | sum += addSum(metaball1, coords);
38 | if (metaballs < 2.0) return sum;
39 | sum += addSum(metaball2, coords);
40 | if (metaballs < 3.0) return sum;
41 | sum += addSum(metaball3, coords);
42 | return sum;
43 | }
44 |
45 | void main() {
46 | vec2 coords = gl_FragCoord.xy;
47 | float time = 0.5;
48 | // float minimumGlowSum = 1.5;
49 | // float glowIntensity = 5.0;
50 | float sum = getSum(coords);
51 |
52 | // if (sum >= 1.0) {
53 | // fragColor = vec4(1,1,1,1);
54 | // } else if (sum > minimumGlowSum) {
55 | float n = ((sum - minimumGlowSum) / (1.0 - minimumGlowSum)) * glowIntensity;
56 |
57 | fragColor = vec4(n) + ((noise(vec4(coords, time, 0.0)) - 0.5) / 255.0);
58 | // } else {
59 | // fragColor = vec4(0, 0, 0, 0);
60 | // }
61 | }
--------------------------------------------------------------------------------
/shaders/pyramid.glsl:
--------------------------------------------------------------------------------
1 | // This shader was taken from ShaderToy
2 | // Origin of Shader: https://www.shadertoy.com/view/tsXBzS
3 | #version 320 es
4 |
5 | precision highp float;
6 | uniform float iTime;
7 | uniform vec2 iResolution;
8 |
9 | out vec4 fragColor;
10 |
11 | vec3 palette(float d){
12 | return mix(vec3(0.2,0.7,0.9),vec3(1.,0.,1.),d);
13 | }
14 |
15 | vec2 rotate(vec2 p,float a){
16 | float c = cos(a);
17 | float s = sin(a);
18 | return p*mat2(c,s,-s,c);
19 | }
20 |
21 | float map(vec3 p){
22 | for( int i = 0; i<8; ++i){
23 | float t = iTime*0.2;
24 | p.xz =rotate(p.xz,t);
25 | p.xy =rotate(p.xy,t*1.89);
26 | p.xz = abs(p.xz);
27 | p.xz-=.5;
28 | }
29 | return dot(sign(p),p)/5.;
30 | }
31 |
32 | vec4 rm (vec3 ro, vec3 rd){
33 | float t = 0.;
34 | vec3 col = vec3(0.);
35 | float d;
36 | for(float i =0.; i<64.; i++){
37 | vec3 p = ro + rd*t;
38 | d = map(p)*.5;
39 | if(d<0.02){
40 | break;
41 | }
42 | if(d>100.){
43 | break;
44 | }
45 | //col+=vec3(0.6,0.8,0.8)/(400.*(d));
46 | col+=palette(length(p)*.1)/(400.*(d));
47 | t+=d;
48 | }
49 | return vec4(col,1./(d*100.));
50 | }
51 | vec4 mainImage( in vec2 fragCoord )
52 | {
53 | vec2 uv = (fragCoord-(iResolution.xy/2.))/iResolution.x;
54 | vec3 ro = vec3(0.,0.,-50.);
55 | ro.xz = rotate(ro.xz,iTime);
56 | vec3 cf = normalize(-ro);
57 | vec3 cs = normalize(cross(cf,vec3(0.,1.,0.)));
58 | vec3 cu = normalize(cross(cf,cs));
59 |
60 | vec3 uuv = ro+cf*3. + uv.x*cs + uv.y*cu;
61 |
62 | vec3 rd = normalize(uuv-ro);
63 |
64 | vec4 col = rm(ro,rd);
65 |
66 |
67 | return col;
68 | }
69 |
70 | void main() {
71 | vec2 pos = gl_FragCoord.xy;
72 | // vec2 uv = pos / vec2(width, height);
73 | fragColor = mainImage(pos);
74 | }
--------------------------------------------------------------------------------
/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 in the flutter_test package. 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:animation_playground/main.dart';
12 |
13 | void main() {
14 | testWidgets('Counter increments smoke test', (WidgetTester tester) async {
15 | // Build our app and trigger a frame.
16 | await tester.pumpWidget(const MyApp());
17 |
18 | // Verify that our counter starts at 0.
19 | expect(find.text('0'), findsOneWidget);
20 | expect(find.text('1'), findsNothing);
21 |
22 | // Tap the '+' icon and trigger a frame.
23 | await tester.tap(find.byIcon(Icons.add));
24 | await tester.pump();
25 |
26 | // Verify that our counter has incremented.
27 | expect(find.text('0'), findsNothing);
28 | expect(find.text('1'), findsOneWidget);
29 | });
30 | }
31 |
--------------------------------------------------------------------------------
/web/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JideGuru/animation_playground/b53a541c25039b11aadbabb5c173964242e980da/web/favicon.png
--------------------------------------------------------------------------------
/web/icons/Icon-192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JideGuru/animation_playground/b53a541c25039b11aadbabb5c173964242e980da/web/icons/Icon-192.png
--------------------------------------------------------------------------------
/web/icons/Icon-512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JideGuru/animation_playground/b53a541c25039b11aadbabb5c173964242e980da/web/icons/Icon-512.png
--------------------------------------------------------------------------------
/web/icons/Icon-maskable-192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JideGuru/animation_playground/b53a541c25039b11aadbabb5c173964242e980da/web/icons/Icon-maskable-192.png
--------------------------------------------------------------------------------
/web/icons/Icon-maskable-512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JideGuru/animation_playground/b53a541c25039b11aadbabb5c173964242e980da/web/icons/Icon-maskable-512.png
--------------------------------------------------------------------------------
/web/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 | animation_playground
33 |
34 |
35 |
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/web/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "animation_playground",
3 | "short_name": "animation_playground",
4 | "start_url": ".",
5 | "display": "standalone",
6 | "background_color": "#0175C2",
7 | "theme_color": "#0175C2",
8 | "description": "A new Flutter project.",
9 | "orientation": "portrait-primary",
10 | "prefer_related_applications": false,
11 | "icons": [
12 | {
13 | "src": "icons/Icon-192.png",
14 | "sizes": "192x192",
15 | "type": "image/png"
16 | },
17 | {
18 | "src": "icons/Icon-512.png",
19 | "sizes": "512x512",
20 | "type": "image/png"
21 | },
22 | {
23 | "src": "icons/Icon-maskable-192.png",
24 | "sizes": "192x192",
25 | "type": "image/png",
26 | "purpose": "maskable"
27 | },
28 | {
29 | "src": "icons/Icon-maskable-512.png",
30 | "sizes": "512x512",
31 | "type": "image/png",
32 | "purpose": "maskable"
33 | }
34 | ]
35 | }
36 |
--------------------------------------------------------------------------------