├── .gitignore ├── .metadata ├── CHANGELOG.md ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── analysis_options.yaml ├── doc ├── example-looney-tunes.png ├── example-pulse-icon.png ├── example-splash.png ├── example-tunnel.png ├── flutter-demo.gif ├── pulsator-icon.gif ├── pulsator-looney-tunes.gif ├── pulsator-splash.gif └── pulsator-tunnel.gif ├── example ├── .gitignore ├── .metadata ├── analysis_options.yaml ├── android │ ├── .gitignore │ ├── app │ │ ├── build.gradle │ │ └── src │ │ │ ├── debug │ │ │ └── AndroidManifest.xml │ │ │ ├── main │ │ │ ├── AndroidManifest.xml │ │ │ ├── kotlin │ │ │ │ └── com │ │ │ │ │ └── example │ │ │ │ │ └── example │ │ │ │ │ └── MainActivity.kt │ │ │ └── res │ │ │ │ ├── drawable-v21 │ │ │ │ └── launch_background.xml │ │ │ │ ├── drawable │ │ │ │ └── launch_background.xml │ │ │ │ ├── mipmap-hdpi │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-mdpi │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-xhdpi │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-xxhdpi │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-xxxhdpi │ │ │ │ └── ic_launcher.png │ │ │ │ ├── values-night │ │ │ │ └── styles.xml │ │ │ │ └── values │ │ │ │ └── styles.xml │ │ │ └── profile │ │ │ └── AndroidManifest.xml │ ├── build.gradle │ ├── gradle.properties │ ├── gradle │ │ └── wrapper │ │ │ └── gradle-wrapper.properties │ └── settings.gradle ├── assets │ └── android_phone.png ├── 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 │ └── main.dart ├── pubspec.lock └── pubspec.yaml ├── lib ├── pulsator.dart └── src │ ├── pulsator.dart │ ├── pulse_icon.dart │ └── styles.dart └── pubspec.yaml /.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .buildlog/ 9 | .history 10 | .svn/ 11 | migrate_working_dir/ 12 | 13 | # IntelliJ related 14 | *.iml 15 | *.ipr 16 | *.iws 17 | .idea/ 18 | 19 | # The .vscode folder contains launch configuration and tasks you configure in 20 | # VS Code which you may wish to be included in version control, so this line 21 | # is commented out by default. 22 | #.vscode/ 23 | 24 | # Flutter/Dart/Pub related 25 | # Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock. 26 | /pubspec.lock 27 | **/doc/api/ 28 | .dart_tool/ 29 | build/ 30 | -------------------------------------------------------------------------------- /.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: "db7ef5bf9f59442b0e200a90587e8fa5e0c6336a" 8 | channel: "stable" 9 | 10 | project_type: package 11 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 1.0.0+2 2 | 3 | * Updated pubspec.yaml file 4 | 5 | ## 1.0.0+1 6 | 7 | * Updated supported platforms 8 | 9 | ## 1.0.0 10 | 11 | * Initial release 12 | 13 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to make participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, religion, or sexual identity and orientation. 6 | 7 | ## Our Standards 8 | 9 | Examples of behavior that contributes to creating a positive environment include: 10 | 11 | - Using welcoming and inclusive language 12 | - Being respectful of differing viewpoints and experiences 13 | - Gracefully accepting constructive criticism 14 | - Focusing on what is best for the community 15 | - Showing empathy towards other community members 16 | 17 | Examples of unacceptable behavior by participants include: 18 | 19 | - The use of sexualized language or imagery and unwelcome sexual attention or advances 20 | - Trolling, insulting/derogatory comments, and personal or political attacks 21 | - Public or private harassment 22 | - Publishing others' private information, such as a physical or electronic address, without explicit permission 23 | - Other conduct which could reasonably be considered inappropriate in a professional setting 24 | 25 | ## Our Responsibilities 26 | 27 | Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. 28 | 29 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, issues, and other contributions that are not aligned with this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. 30 | 31 | ## Scope 32 | 33 | This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project email address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. 34 | 35 | ## Enforcement 36 | 37 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team. All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. 38 | 39 | Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. 40 | 41 | ## Attribution 42 | 43 | This Code of Conduct is adapted from the [Contributor Covenant](https://www.contributor-covenant.org), version 2.0, available at [https://www.contributor-covenant.org/version/2/0/code_of_conduct.html](https://www.contributor-covenant.org/version/2/0/code_of_conduct.html). 44 | 45 | For answers to common questions about this code of conduct, see [FAQ](https://www.contributor-covenant.org/faq). 46 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to Pulsator 2 | 3 | Thank you for considering contributing to this open-source project! We welcome your contributions to make this library even better. Whether you want to report a bug, suggest an enhancement, or submit code changes, this guide will help you get started. 4 | 5 | Please note that this project follows a Code of Conduct (see [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md)). By participating, you are expected to uphold this code. 6 | 7 | ## Ways to Contribute 8 | 9 | You can contribute to this project in several ways: 10 | 11 | 1. Reporting Issues: 12 | - If you encounter a bug or have a feature request, please open an issue on the GitHub repository. Make sure to provide a clear and detailed description of the problem or feature request. 13 | 14 | 2. Code Contributions: 15 | - Fork the repository and make your changes in a feature branch. 16 | - Ensure your code follows the project's coding standards. 17 | - Write tests to cover your changes. 18 | - Submit a pull request with a clear description of your changes. 19 | 20 | 3. Documentation: 21 | - Help improve the project's documentation by correcting typos, enhancing explanations, or adding missing details. 22 | 23 | 4. Review Pull Requests: 24 | - Review open pull requests, provide feedback, and help ensure code quality. 25 | 26 | ## Getting Started 27 | 28 | 1. **Fork** the project repository to your GitHub account. 29 | 30 | 2. **Clone** your fork to your local development environment: 31 | 32 | ```bash 33 | git clone https://github.com/booncol/pulsator.git 34 | ``` 35 | 3. **Create a branch** for your contribution: 36 | 37 | ```bash 38 | git checkout -b feature/my-feature 39 | ``` 40 | 4. **Make your changes** and commit them: 41 | 42 | ```bash 43 | git add . 44 | git commit -m "Add new feature" 45 | ``` 46 | 5. **Push** your changes to your GitHub repository: 47 | 48 | ```bash 49 | git push origin feature/my-feature 50 | ``` 51 | 6. Open a **pull request** on the main repository for review. 52 | 53 | ## Code of Conduct 54 | 55 | This project has adopted a Code of Conduct that we expect project participants to adhere to. Please see [CODE_OF_CONDUCT.md](https://github.com/booncol/pulsator/blob/main/CODE_OF_CONDUCT.md) for details. 56 | 57 | ## License 58 | 59 | By contributing to this project, you agree that your contributions will be licensed under the MIT License. See the [LICENSE](https://github.com/booncol/pulsator/blob/main/LICENSE) for details. 60 | 61 | ## Contact 62 | 63 | If you have questions or need assistance, feel free to contact me. 64 | 65 | Happy coding! 66 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Lukasz Majda 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Pulsator for Flutter 2 | 3 | [![Version](https://img.shields.io/pub/v/pulsator.svg)](https://pub.dev/packages/pulsator) 4 | ![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg?style=flat) 5 | 6 | The Pulsator Flutter package brings a captivating pulsating animation to your Flutter applications. 7 | 8 | ![PulsatorPreview](https://raw.githubusercontent.com/booncol/pulsator/main/doc/flutter-demo.gif) 9 | 10 | ## Installation 11 | 12 | To integrate the Pulsator package into your Flutter project, add the following dependency to your `pubspec.yaml` file: 13 | 14 | ```yaml 15 | dependencies: 16 | pulsator: ^1.0.0 17 | ``` 18 | 19 | After making the modification, run the following command in your terminal: 20 | 21 | ```bash 22 | flutter pub get 23 | ``` 24 | 25 | ## Introduction 26 | 27 | The Pulsator package introduces two primary widgets: `Pulsator` and `PulseIcon`. 28 | 29 | ### `Pulsator` Widget 30 | 31 | The `Pulsator` widget allows you to create pulsating animations with customizable styles. You can control the number of pulses, animation duration, repetition, and more. This widget is perfect for adding dynamic visual effects to specific areas of your app. 32 | 33 | ```dart 34 | Pulsator( 35 | style: PulseStyle(color: Colors.blue), 36 | count: 5, 37 | duration: Duration(seconds: 4), 38 | repeat: 0, 39 | startFromScratch: false, 40 | autoStart: true, 41 | fit: PulseFit.contain, 42 | child: YourContentWidget(), 43 | ) 44 | ``` 45 | 46 | ### `PulseIcon` Widget 47 | 48 | The `PulseIcon` widget simplifies the process of displaying an icon with a pulsing effect. It allows you to customize the pulse and icon properties effortlessly. 49 | 50 | ```dart 51 | PulseIcon( 52 | icon: Icons.favorite, 53 | pulseColor: Colors.red, 54 | iconColor: Colors.white, 55 | iconSize: 44, 56 | innerSize: 54, 57 | pulseSize: 116, 58 | pulseCount: 4, 59 | pulseDuration: Duration(seconds: 4), 60 | ) 61 | ``` 62 | 63 | ## Features 64 | 65 | - **Customizable Styles**: Tailor the pulse animation to your preferences with adjustable color, size, and gradient configurations. 66 | - **Dynamic Pulse Effects**: Create dynamic and visually appealing pulsating animations that draw attention to specific elements in your UI. 67 | - **Icon Integration**: Easily incorporate pulsating effects into your icons using the `PulseIcon` widget for a more engaging user experience. 68 | - **Flexible Configuration**: Fine-tune the pulse behavior by adjusting parameters such as count, duration, repetition, and more. 69 | 70 | ## Usage 71 | 72 | Explore the various properties and customization options provided by the `Pulsator` and `PulseIcon` widgets to seamlessly integrate pulsating animations into your Flutter application. Experiment with different configurations to achieve the desired visual impact and enhance the overall user experience. 73 | 74 | ## Juicy examples 75 | 76 | | Code | Preview | 77 | |-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------| 78 | | ![PulseIconExampleCode](https://raw.githubusercontent.com/booncol/pulsator/main/doc/example-pulse-icon.png) | ![PulseIconExamplePreview](https://raw.githubusercontent.com/booncol/pulsator/main/doc/pulsator-icon.gif) | 79 | | ![SplashExampleCode](https://raw.githubusercontent.com/booncol/pulsator/main/doc/example-splash.png) | ![SplashExamplePreview](https://raw.githubusercontent.com/booncol/pulsator/main/doc/pulsator-splash.gif) | 80 | | ![TunnelExampleCode](https://raw.githubusercontent.com/booncol/pulsator/main/doc/example-tunnel.png) | ![TunnelExamplePreview](https://raw.githubusercontent.com/booncol/pulsator/main/doc/pulsator-tunnel.gif) | 81 | | ![LooneyExampleCode](https://raw.githubusercontent.com/booncol/pulsator/main/doc/example-looney-tunes.png) | ![LooneyExamplePreview](https://raw.githubusercontent.com/booncol/pulsator/main/doc/pulsator-looney-tunes.gif) | 82 | 83 | ## License 84 | This project is licensed under the MIT License - see the [LICENSE](https://github.com/booncol/pulsator/blob/main/LICENSE) file for details. 85 | 86 | ## Contributing 87 | Please read [CONTRIBUTING.md](https://github.com/booncol/pulsator/blob/main/CONTRIBUTING.md) for details on my code of conduct, and the process for submitting pull requests to me. 88 | 89 | ## The docs, please! 90 | 91 | ### `Pulsator` Widget properties 92 | 93 | | Property | Type | Description | 94 | |--------------------|------------|-------------------------------------------------------------------------------------------------| 95 | | `style` | PulseStyle | Pulse style configuration. Required. | 96 | | `count` | int | Number of pulses visible at a time. Default is `3`. | 97 | | `duration` | Duration | Duration of a single pulse animation. Default is `2` seconds. | 98 | | `repeat` | int | Number of times pulses will repeat. If 0, pulses will repeat forever. Default is `0`. | 99 | | `startFromScratch` | bool | Whether the animation should start from the beginning. Default is `true`. | 100 | | `autoStart` | bool | Whether the animation should start automatically when the widget is created. Default is `true`. | 101 | | `fit` | PulseFit | How the pulse should be scaled to fit the widget size. Default is `PulseFit.contain`. | 102 | | `child` | Widget? | The child of the widget that is rendered on top of the pulses. Default is `null`. | 103 | 104 | #### `Events` 105 | 106 | | Event | Description | 107 | |----------|---------------------------------------------------| 108 | | `onCreated` | Invoked when the animation controller is created. | 109 | | `onCompleted` | Invoked when the animation is completed. | 110 | 111 | 112 | ### `PulseIcon` Widget properties 113 | 114 | | Property | Type | Description | 115 | |-----------------|----------|-------------------------------------------------------------------| 116 | | `icon` | IconData | The icon to display. Required. | 117 | | `pulseColor` | Color | The color of the pulse. Required. | 118 | | `iconColor` | Color | The color of the icon. Default is `white`. | 119 | | `iconSize` | double | The size of the icon. Default is `24`. | 120 | | `pulseSize` | double | The size of the pulse. Default is `64`. | 121 | | `innerColor` | Color? | The color of the inner, non-pulsing circle. Default is `null`. | 122 | | `innerSize` | double? | The size of the inner, non-pulsing circle. Default is `null`. | 123 | | `pulseCount` | int | The number of pulses to display. Default is `3`. | 124 | | `pulseDuration` | Duration | The duration of a single pulse animation. Default is `4` seconds. | 125 | 126 | ### `PulseStyle` properties 127 | 128 | | Property | Type | Description | 129 | |-----------------|---------------------|--------------------------------------------------------------------------------------------| 130 | | `color` | Color | Main pulse color. Default is `Colors.red`. | 131 | | `borderColor` | Color? | Pulse border color. If `null`, no border will be rendered. Default is `null`. | 132 | | `borderWidth` | double? | Pulse border width. If `null`, no border will be rendered. Default is `null`. | 133 | | `gradientStyle` | PulseGradientStyle? | If set, the pulse will be rendered as a gradient. Default is `null`. | 134 | | `pulseCurve` | Curve | Pulse scale animation curve. Default is `Curves.linear`. | 135 | | `opacityCurve` | Curve | Pulse opacity animation curve. Default is `Curves.linear`. | 136 | | `fadeOpacity` | bool | Whether the opacity should be animated from 1.0 to 0.0. Default is `true`. | 137 | | `startSize` | double | The size of the pulse when it begins, as a fraction of the pulse radius. Default is `0.0`. | 138 | 139 | ### `PulseGradientStyle` properties 140 | 141 | | Property | Type | Description | 142 | |-----------------|--------|----------------------------------------------------------------------------------------------------------------------------------------| 143 | | `radius` | double | The radius of the gradient, as a fraction pulse radius. Default is `0.5`. | 144 | | `start` | double | The start point of the gradient, as a fraction of the pulse radius. Default is `0.0`. | 145 | | `end` | double | The end point of the gradient, as a fraction of the pulse radius. Default is `1.0`. | 146 | | `startColor` | Color? | The start color of the gradient. If null, the pulse color will be used with the opacity set to `0.0`. Default is `null`. | 147 | | `reverseColors` | bool | Whether the gradient colors should be reversed. If `true`, the gradient will start from `end` and end at `start`. Default is `false`. | 148 | 149 | ### `PulseFit` enum 150 | 151 | | Value | Description | 152 | |-----------|---------------------------------------------------| 153 | | `contain` | The pulse will be scaled to fit the widget size. | 154 | | `cover` | The pulse will be scaled to fill the widget size. | 155 | -------------------------------------------------------------------------------- /analysis_options.yaml: -------------------------------------------------------------------------------- 1 | include: package:flutter_lints/flutter.yaml 2 | 3 | # Additional information about this file can be found at 4 | # https://dart.dev/guides/language/analysis-options 5 | -------------------------------------------------------------------------------- /doc/example-looney-tunes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/booncol/pulsator/30f31fa9c5c7bb5f8c22a6df0fd857ede7b1cadc/doc/example-looney-tunes.png -------------------------------------------------------------------------------- /doc/example-pulse-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/booncol/pulsator/30f31fa9c5c7bb5f8c22a6df0fd857ede7b1cadc/doc/example-pulse-icon.png -------------------------------------------------------------------------------- /doc/example-splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/booncol/pulsator/30f31fa9c5c7bb5f8c22a6df0fd857ede7b1cadc/doc/example-splash.png -------------------------------------------------------------------------------- /doc/example-tunnel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/booncol/pulsator/30f31fa9c5c7bb5f8c22a6df0fd857ede7b1cadc/doc/example-tunnel.png -------------------------------------------------------------------------------- /doc/flutter-demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/booncol/pulsator/30f31fa9c5c7bb5f8c22a6df0fd857ede7b1cadc/doc/flutter-demo.gif -------------------------------------------------------------------------------- /doc/pulsator-icon.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/booncol/pulsator/30f31fa9c5c7bb5f8c22a6df0fd857ede7b1cadc/doc/pulsator-icon.gif -------------------------------------------------------------------------------- /doc/pulsator-looney-tunes.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/booncol/pulsator/30f31fa9c5c7bb5f8c22a6df0fd857ede7b1cadc/doc/pulsator-looney-tunes.gif -------------------------------------------------------------------------------- /doc/pulsator-splash.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/booncol/pulsator/30f31fa9c5c7bb5f8c22a6df0fd857ede7b1cadc/doc/pulsator-splash.gif -------------------------------------------------------------------------------- /doc/pulsator-tunnel.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/booncol/pulsator/30f31fa9c5c7bb5f8c22a6df0fd857ede7b1cadc/doc/pulsator-tunnel.gif -------------------------------------------------------------------------------- /example/.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .buildlog/ 9 | .history 10 | .svn/ 11 | migrate_working_dir/ 12 | 13 | # IntelliJ related 14 | *.iml 15 | *.ipr 16 | *.iws 17 | .idea/ 18 | 19 | # The .vscode folder contains launch configuration and tasks you configure in 20 | # VS Code which you may wish to be included in version control, so this line 21 | # is commented out by default. 22 | #.vscode/ 23 | 24 | # Flutter/Dart/Pub related 25 | **/doc/api/ 26 | **/ios/Flutter/.last_build_id 27 | .dart_tool/ 28 | .flutter-plugins 29 | .flutter-plugins-dependencies 30 | .packages 31 | .pub-cache/ 32 | .pub/ 33 | /build/ 34 | 35 | # Symbolication related 36 | app.*.symbols 37 | 38 | # Obfuscation related 39 | app.*.map.json 40 | 41 | # Android Studio will place build artifacts here 42 | /android/app/debug 43 | /android/app/profile 44 | /android/app/release 45 | -------------------------------------------------------------------------------- /example/.metadata: -------------------------------------------------------------------------------- 1 | # This file tracks properties of this Flutter project. 2 | # Used by Flutter tool to assess capabilities and perform upgrades etc. 3 | # 4 | # This file should be version controlled. 5 | 6 | version: 7 | revision: b06b8b2710955028a6b562f5aa6fe62941d6febf 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: b06b8b2710955028a6b562f5aa6fe62941d6febf 17 | base_revision: b06b8b2710955028a6b562f5aa6fe62941d6febf 18 | - platform: android 19 | create_revision: b06b8b2710955028a6b562f5aa6fe62941d6febf 20 | base_revision: b06b8b2710955028a6b562f5aa6fe62941d6febf 21 | - platform: ios 22 | create_revision: b06b8b2710955028a6b562f5aa6fe62941d6febf 23 | base_revision: b06b8b2710955028a6b562f5aa6fe62941d6febf 24 | 25 | # User provided section 26 | 27 | # List of Local paths (relative to this file) that should be 28 | # ignored by the migrate tool. 29 | # 30 | # Files that are not part of the templates will be ignored by default. 31 | unmanaged_files: 32 | - 'lib/main.dart' 33 | - 'ios/Runner.xcodeproj/project.pbxproj' 34 | -------------------------------------------------------------------------------- /example/analysis_options.yaml: -------------------------------------------------------------------------------- 1 | # This file configures the analyzer, which statically analyzes Dart code to 2 | # check for errors, warnings, and lints. 3 | # 4 | # The issues identified by the analyzer are surfaced in the UI of Dart-enabled 5 | # IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be 6 | # invoked from the command line by running `flutter analyze`. 7 | 8 | # The following line activates a set of recommended lints for Flutter apps, 9 | # packages, and plugins designed to encourage good coding practices. 10 | include: package:flutter_lints/flutter.yaml 11 | 12 | linter: 13 | # The lint rules applied to this project can be customized in the 14 | # section below to disable rules from the `package:flutter_lints/flutter.yaml` 15 | # included above or to enable additional rules. A list of all available lints 16 | # and their documentation is published at 17 | # https://dart-lang.github.io/linter/lints/index.html. 18 | # 19 | # Instead of disabling a lint rule for the entire project in the 20 | # section below, it can also be suppressed for a single line of code 21 | # or a specific dart file by using the `// ignore: name_of_lint` and 22 | # `// ignore_for_file: name_of_lint` syntax on the line or in the file 23 | # producing the lint. 24 | rules: 25 | # avoid_print: false # Uncomment to disable the `avoid_print` rule 26 | # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule 27 | 28 | # Additional information about this file can be found at 29 | # https://dart.dev/guides/language/analysis-options 30 | -------------------------------------------------------------------------------- /example/android/.gitignore: -------------------------------------------------------------------------------- 1 | gradle-wrapper.jar 2 | /.gradle 3 | /captures/ 4 | /gradlew 5 | /gradlew.bat 6 | /local.properties 7 | GeneratedPluginRegistrant.java 8 | 9 | # Remember to never publicly share your keystore. 10 | # See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app 11 | key.properties 12 | **/*.keystore 13 | **/*.jks 14 | -------------------------------------------------------------------------------- /example/android/app/build.gradle: -------------------------------------------------------------------------------- 1 | def localProperties = new Properties() 2 | def localPropertiesFile = rootProject.file('local.properties') 3 | if (localPropertiesFile.exists()) { 4 | localPropertiesFile.withReader('UTF-8') { reader -> 5 | localProperties.load(reader) 6 | } 7 | } 8 | 9 | def flutterRoot = localProperties.getProperty('flutter.sdk') 10 | if (flutterRoot == null) { 11 | throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") 12 | } 13 | 14 | def flutterVersionCode = localProperties.getProperty('flutter.versionCode') 15 | if (flutterVersionCode == null) { 16 | flutterVersionCode = '1' 17 | } 18 | 19 | def flutterVersionName = localProperties.getProperty('flutter.versionName') 20 | if (flutterVersionName == null) { 21 | flutterVersionName = '1.0' 22 | } 23 | 24 | apply plugin: 'com.android.application' 25 | apply plugin: 'kotlin-android' 26 | apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" 27 | 28 | android { 29 | compileSdkVersion 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.example.example" 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-gradle-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 | -------------------------------------------------------------------------------- /example/android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 7 | 15 | 19 | 23 | 24 | 25 | 26 | 27 | 28 | 30 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /example/android/app/src/main/kotlin/com/example/example/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.example.example 2 | 3 | import io.flutter.embedding.android.FlutterActivity 4 | 5 | class MainActivity: FlutterActivity() { 6 | } 7 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/drawable-v21/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/drawable/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/booncol/pulsator/30f31fa9c5c7bb5f8c22a6df0fd857ede7b1cadc/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/booncol/pulsator/30f31fa9c5c7bb5f8c22a6df0fd857ede7b1cadc/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/booncol/pulsator/30f31fa9c5c7bb5f8c22a6df0fd857ede7b1cadc/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/booncol/pulsator/30f31fa9c5c7bb5f8c22a6df0fd857ede7b1cadc/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/booncol/pulsator/30f31fa9c5c7bb5f8c22a6df0fd857ede7b1cadc/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/values-night/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /example/android/app/src/profile/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/android/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | ext.kotlin_version = '1.7.10' 3 | repositories { 4 | google() 5 | mavenCentral() 6 | } 7 | 8 | dependencies { 9 | classpath 'com.android.tools.build:gradle:7.2.0' 10 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 11 | } 12 | } 13 | 14 | allprojects { 15 | repositories { 16 | google() 17 | mavenCentral() 18 | } 19 | } 20 | 21 | rootProject.buildDir = '../build' 22 | subprojects { 23 | project.buildDir = "${rootProject.buildDir}/${project.name}" 24 | } 25 | subprojects { 26 | project.evaluationDependsOn(':app') 27 | } 28 | 29 | task clean(type: Delete) { 30 | delete rootProject.buildDir 31 | } 32 | -------------------------------------------------------------------------------- /example/android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx1536M 2 | android.useAndroidX=true 3 | android.enableJetifier=true 4 | -------------------------------------------------------------------------------- /example/android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | 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.5-all.zip 6 | -------------------------------------------------------------------------------- /example/android/settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | 3 | def localPropertiesFile = new File(rootProject.projectDir, "local.properties") 4 | def properties = new Properties() 5 | 6 | assert localPropertiesFile.exists() 7 | localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) } 8 | 9 | def flutterSdkPath = properties.getProperty("flutter.sdk") 10 | assert flutterSdkPath != null, "flutter.sdk not set in local.properties" 11 | apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle" 12 | -------------------------------------------------------------------------------- /example/assets/android_phone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/booncol/pulsator/30f31fa9c5c7bb5f8c22a6df0fd857ede7b1cadc/example/assets/android_phone.png -------------------------------------------------------------------------------- /example/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 | -------------------------------------------------------------------------------- /example/ios/Flutter/AppFrameworkInfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | App 9 | CFBundleIdentifier 10 | io.flutter.flutter.app 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | App 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1.0 23 | MinimumOSVersion 24 | 11.0 25 | 26 | 27 | -------------------------------------------------------------------------------- /example/ios/Flutter/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Generated.xcconfig" 2 | -------------------------------------------------------------------------------- /example/ios/Flutter/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Generated.xcconfig" 2 | -------------------------------------------------------------------------------- /example/ios/Runner.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 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 = 1300; 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 | ); 180 | name = "Thin Binary"; 181 | outputPaths = ( 182 | ); 183 | runOnlyForDeploymentPostprocessing = 0; 184 | shellPath = /bin/sh; 185 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; 186 | }; 187 | 9740EEB61CF901F6004384FC /* Run Script */ = { 188 | isa = PBXShellScriptBuildPhase; 189 | alwaysOutOfDate = 1; 190 | buildActionMask = 2147483647; 191 | files = ( 192 | ); 193 | inputPaths = ( 194 | ); 195 | name = "Run Script"; 196 | outputPaths = ( 197 | ); 198 | runOnlyForDeploymentPostprocessing = 0; 199 | shellPath = /bin/sh; 200 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; 201 | }; 202 | /* End PBXShellScriptBuildPhase section */ 203 | 204 | /* Begin PBXSourcesBuildPhase section */ 205 | 97C146EA1CF9000F007C117D /* Sources */ = { 206 | isa = PBXSourcesBuildPhase; 207 | buildActionMask = 2147483647; 208 | files = ( 209 | 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, 210 | 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, 211 | ); 212 | runOnlyForDeploymentPostprocessing = 0; 213 | }; 214 | /* End PBXSourcesBuildPhase section */ 215 | 216 | /* Begin PBXVariantGroup section */ 217 | 97C146FA1CF9000F007C117D /* Main.storyboard */ = { 218 | isa = PBXVariantGroup; 219 | children = ( 220 | 97C146FB1CF9000F007C117D /* Base */, 221 | ); 222 | name = Main.storyboard; 223 | sourceTree = ""; 224 | }; 225 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { 226 | isa = PBXVariantGroup; 227 | children = ( 228 | 97C147001CF9000F007C117D /* Base */, 229 | ); 230 | name = LaunchScreen.storyboard; 231 | sourceTree = ""; 232 | }; 233 | /* End PBXVariantGroup section */ 234 | 235 | /* Begin XCBuildConfiguration section */ 236 | 249021D3217E4FDB00AE95B9 /* Profile */ = { 237 | isa = XCBuildConfiguration; 238 | buildSettings = { 239 | ALWAYS_SEARCH_USER_PATHS = NO; 240 | CLANG_ANALYZER_NONNULL = YES; 241 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 242 | CLANG_CXX_LIBRARY = "libc++"; 243 | CLANG_ENABLE_MODULES = YES; 244 | CLANG_ENABLE_OBJC_ARC = YES; 245 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 246 | CLANG_WARN_BOOL_CONVERSION = YES; 247 | CLANG_WARN_COMMA = YES; 248 | CLANG_WARN_CONSTANT_CONVERSION = YES; 249 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 250 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 251 | CLANG_WARN_EMPTY_BODY = YES; 252 | CLANG_WARN_ENUM_CONVERSION = YES; 253 | CLANG_WARN_INFINITE_RECURSION = YES; 254 | CLANG_WARN_INT_CONVERSION = YES; 255 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 256 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 257 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 258 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 259 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 260 | CLANG_WARN_STRICT_PROTOTYPES = YES; 261 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 262 | CLANG_WARN_UNREACHABLE_CODE = YES; 263 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 264 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 265 | COPY_PHASE_STRIP = NO; 266 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 267 | ENABLE_NS_ASSERTIONS = NO; 268 | ENABLE_STRICT_OBJC_MSGSEND = YES; 269 | GCC_C_LANGUAGE_STANDARD = gnu99; 270 | GCC_NO_COMMON_BLOCKS = YES; 271 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 272 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 273 | GCC_WARN_UNDECLARED_SELECTOR = YES; 274 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 275 | GCC_WARN_UNUSED_FUNCTION = YES; 276 | GCC_WARN_UNUSED_VARIABLE = YES; 277 | IPHONEOS_DEPLOYMENT_TARGET = 11.0; 278 | MTL_ENABLE_DEBUG_INFO = NO; 279 | SDKROOT = iphoneos; 280 | SUPPORTED_PLATFORMS = iphoneos; 281 | TARGETED_DEVICE_FAMILY = "1,2"; 282 | VALIDATE_PRODUCT = YES; 283 | }; 284 | name = Profile; 285 | }; 286 | 249021D4217E4FDB00AE95B9 /* Profile */ = { 287 | isa = XCBuildConfiguration; 288 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; 289 | buildSettings = { 290 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 291 | CLANG_ENABLE_MODULES = YES; 292 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; 293 | ENABLE_BITCODE = NO; 294 | INFOPLIST_FILE = Runner/Info.plist; 295 | LD_RUNPATH_SEARCH_PATHS = ( 296 | "$(inherited)", 297 | "@executable_path/Frameworks", 298 | ); 299 | PRODUCT_BUNDLE_IDENTIFIER = com.example.example; 300 | PRODUCT_NAME = "$(TARGET_NAME)"; 301 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; 302 | SWIFT_VERSION = 5.0; 303 | VERSIONING_SYSTEM = "apple-generic"; 304 | }; 305 | name = Profile; 306 | }; 307 | 97C147031CF9000F007C117D /* Debug */ = { 308 | isa = XCBuildConfiguration; 309 | buildSettings = { 310 | ALWAYS_SEARCH_USER_PATHS = NO; 311 | CLANG_ANALYZER_NONNULL = YES; 312 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 313 | CLANG_CXX_LIBRARY = "libc++"; 314 | CLANG_ENABLE_MODULES = YES; 315 | CLANG_ENABLE_OBJC_ARC = YES; 316 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 317 | CLANG_WARN_BOOL_CONVERSION = YES; 318 | CLANG_WARN_COMMA = YES; 319 | CLANG_WARN_CONSTANT_CONVERSION = YES; 320 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 321 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 322 | CLANG_WARN_EMPTY_BODY = YES; 323 | CLANG_WARN_ENUM_CONVERSION = YES; 324 | CLANG_WARN_INFINITE_RECURSION = YES; 325 | CLANG_WARN_INT_CONVERSION = YES; 326 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 327 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 328 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 329 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 330 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 331 | CLANG_WARN_STRICT_PROTOTYPES = YES; 332 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 333 | CLANG_WARN_UNREACHABLE_CODE = YES; 334 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 335 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 336 | COPY_PHASE_STRIP = NO; 337 | DEBUG_INFORMATION_FORMAT = dwarf; 338 | ENABLE_STRICT_OBJC_MSGSEND = YES; 339 | ENABLE_TESTABILITY = YES; 340 | GCC_C_LANGUAGE_STANDARD = gnu99; 341 | GCC_DYNAMIC_NO_PIC = NO; 342 | GCC_NO_COMMON_BLOCKS = YES; 343 | GCC_OPTIMIZATION_LEVEL = 0; 344 | GCC_PREPROCESSOR_DEFINITIONS = ( 345 | "DEBUG=1", 346 | "$(inherited)", 347 | ); 348 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 349 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 350 | GCC_WARN_UNDECLARED_SELECTOR = YES; 351 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 352 | GCC_WARN_UNUSED_FUNCTION = YES; 353 | GCC_WARN_UNUSED_VARIABLE = YES; 354 | IPHONEOS_DEPLOYMENT_TARGET = 11.0; 355 | MTL_ENABLE_DEBUG_INFO = YES; 356 | ONLY_ACTIVE_ARCH = YES; 357 | SDKROOT = iphoneos; 358 | TARGETED_DEVICE_FAMILY = "1,2"; 359 | }; 360 | name = Debug; 361 | }; 362 | 97C147041CF9000F007C117D /* Release */ = { 363 | isa = XCBuildConfiguration; 364 | buildSettings = { 365 | ALWAYS_SEARCH_USER_PATHS = NO; 366 | CLANG_ANALYZER_NONNULL = YES; 367 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 368 | CLANG_CXX_LIBRARY = "libc++"; 369 | CLANG_ENABLE_MODULES = YES; 370 | CLANG_ENABLE_OBJC_ARC = YES; 371 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 372 | CLANG_WARN_BOOL_CONVERSION = YES; 373 | CLANG_WARN_COMMA = YES; 374 | CLANG_WARN_CONSTANT_CONVERSION = YES; 375 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 376 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 377 | CLANG_WARN_EMPTY_BODY = YES; 378 | CLANG_WARN_ENUM_CONVERSION = YES; 379 | CLANG_WARN_INFINITE_RECURSION = YES; 380 | CLANG_WARN_INT_CONVERSION = YES; 381 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 382 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 383 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 384 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 385 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 386 | CLANG_WARN_STRICT_PROTOTYPES = YES; 387 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 388 | CLANG_WARN_UNREACHABLE_CODE = YES; 389 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 390 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 391 | COPY_PHASE_STRIP = NO; 392 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 393 | ENABLE_NS_ASSERTIONS = NO; 394 | ENABLE_STRICT_OBJC_MSGSEND = YES; 395 | GCC_C_LANGUAGE_STANDARD = gnu99; 396 | GCC_NO_COMMON_BLOCKS = YES; 397 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 398 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 399 | GCC_WARN_UNDECLARED_SELECTOR = YES; 400 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 401 | GCC_WARN_UNUSED_FUNCTION = YES; 402 | GCC_WARN_UNUSED_VARIABLE = YES; 403 | IPHONEOS_DEPLOYMENT_TARGET = 11.0; 404 | MTL_ENABLE_DEBUG_INFO = NO; 405 | SDKROOT = iphoneos; 406 | SUPPORTED_PLATFORMS = iphoneos; 407 | SWIFT_COMPILATION_MODE = wholemodule; 408 | SWIFT_OPTIMIZATION_LEVEL = "-O"; 409 | TARGETED_DEVICE_FAMILY = "1,2"; 410 | VALIDATE_PRODUCT = YES; 411 | }; 412 | name = Release; 413 | }; 414 | 97C147061CF9000F007C117D /* Debug */ = { 415 | isa = XCBuildConfiguration; 416 | baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; 417 | buildSettings = { 418 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 419 | CLANG_ENABLE_MODULES = YES; 420 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; 421 | ENABLE_BITCODE = NO; 422 | INFOPLIST_FILE = Runner/Info.plist; 423 | LD_RUNPATH_SEARCH_PATHS = ( 424 | "$(inherited)", 425 | "@executable_path/Frameworks", 426 | ); 427 | PRODUCT_BUNDLE_IDENTIFIER = com.example.example; 428 | PRODUCT_NAME = "$(TARGET_NAME)"; 429 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; 430 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 431 | SWIFT_VERSION = 5.0; 432 | VERSIONING_SYSTEM = "apple-generic"; 433 | }; 434 | name = Debug; 435 | }; 436 | 97C147071CF9000F007C117D /* Release */ = { 437 | isa = XCBuildConfiguration; 438 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; 439 | buildSettings = { 440 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 441 | CLANG_ENABLE_MODULES = YES; 442 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; 443 | ENABLE_BITCODE = NO; 444 | INFOPLIST_FILE = Runner/Info.plist; 445 | LD_RUNPATH_SEARCH_PATHS = ( 446 | "$(inherited)", 447 | "@executable_path/Frameworks", 448 | ); 449 | PRODUCT_BUNDLE_IDENTIFIER = com.example.example; 450 | PRODUCT_NAME = "$(TARGET_NAME)"; 451 | SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; 452 | SWIFT_VERSION = 5.0; 453 | VERSIONING_SYSTEM = "apple-generic"; 454 | }; 455 | name = Release; 456 | }; 457 | /* End XCBuildConfiguration section */ 458 | 459 | /* Begin XCConfigurationList section */ 460 | 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { 461 | isa = XCConfigurationList; 462 | buildConfigurations = ( 463 | 97C147031CF9000F007C117D /* Debug */, 464 | 97C147041CF9000F007C117D /* Release */, 465 | 249021D3217E4FDB00AE95B9 /* Profile */, 466 | ); 467 | defaultConfigurationIsVisible = 0; 468 | defaultConfigurationName = Release; 469 | }; 470 | 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { 471 | isa = XCConfigurationList; 472 | buildConfigurations = ( 473 | 97C147061CF9000F007C117D /* Debug */, 474 | 97C147071CF9000F007C117D /* Release */, 475 | 249021D4217E4FDB00AE95B9 /* Profile */, 476 | ); 477 | defaultConfigurationIsVisible = 0; 478 | defaultConfigurationName = Release; 479 | }; 480 | /* End XCConfigurationList section */ 481 | }; 482 | rootObject = 97C146E61CF9000F007C117D /* Project object */; 483 | } 484 | -------------------------------------------------------------------------------- /example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 37 | 38 | 39 | 40 | 41 | 42 | 52 | 54 | 60 | 61 | 62 | 63 | 69 | 71 | 77 | 78 | 79 | 80 | 82 | 83 | 86 | 87 | 88 | -------------------------------------------------------------------------------- /example/ios/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/ios/Runner/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | import Flutter 3 | 4 | @UIApplicationMain 5 | @objc class AppDelegate: FlutterAppDelegate { 6 | override func application( 7 | _ application: UIApplication, 8 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? 9 | ) -> Bool { 10 | GeneratedPluginRegistrant.register(with: self) 11 | return super.application(application, didFinishLaunchingWithOptions: launchOptions) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "20x20", 5 | "idiom" : "iphone", 6 | "filename" : "Icon-App-20x20@2x.png", 7 | "scale" : "2x" 8 | }, 9 | { 10 | "size" : "20x20", 11 | "idiom" : "iphone", 12 | "filename" : "Icon-App-20x20@3x.png", 13 | "scale" : "3x" 14 | }, 15 | { 16 | "size" : "29x29", 17 | "idiom" : "iphone", 18 | "filename" : "Icon-App-29x29@1x.png", 19 | "scale" : "1x" 20 | }, 21 | { 22 | "size" : "29x29", 23 | "idiom" : "iphone", 24 | "filename" : "Icon-App-29x29@2x.png", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "size" : "29x29", 29 | "idiom" : "iphone", 30 | "filename" : "Icon-App-29x29@3x.png", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "size" : "40x40", 35 | "idiom" : "iphone", 36 | "filename" : "Icon-App-40x40@2x.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "40x40", 41 | "idiom" : "iphone", 42 | "filename" : "Icon-App-40x40@3x.png", 43 | "scale" : "3x" 44 | }, 45 | { 46 | "size" : "60x60", 47 | "idiom" : "iphone", 48 | "filename" : "Icon-App-60x60@2x.png", 49 | "scale" : "2x" 50 | }, 51 | { 52 | "size" : "60x60", 53 | "idiom" : "iphone", 54 | "filename" : "Icon-App-60x60@3x.png", 55 | "scale" : "3x" 56 | }, 57 | { 58 | "size" : "20x20", 59 | "idiom" : "ipad", 60 | "filename" : "Icon-App-20x20@1x.png", 61 | "scale" : "1x" 62 | }, 63 | { 64 | "size" : "20x20", 65 | "idiom" : "ipad", 66 | "filename" : "Icon-App-20x20@2x.png", 67 | "scale" : "2x" 68 | }, 69 | { 70 | "size" : "29x29", 71 | "idiom" : "ipad", 72 | "filename" : "Icon-App-29x29@1x.png", 73 | "scale" : "1x" 74 | }, 75 | { 76 | "size" : "29x29", 77 | "idiom" : "ipad", 78 | "filename" : "Icon-App-29x29@2x.png", 79 | "scale" : "2x" 80 | }, 81 | { 82 | "size" : "40x40", 83 | "idiom" : "ipad", 84 | "filename" : "Icon-App-40x40@1x.png", 85 | "scale" : "1x" 86 | }, 87 | { 88 | "size" : "40x40", 89 | "idiom" : "ipad", 90 | "filename" : "Icon-App-40x40@2x.png", 91 | "scale" : "2x" 92 | }, 93 | { 94 | "size" : "76x76", 95 | "idiom" : "ipad", 96 | "filename" : "Icon-App-76x76@1x.png", 97 | "scale" : "1x" 98 | }, 99 | { 100 | "size" : "76x76", 101 | "idiom" : "ipad", 102 | "filename" : "Icon-App-76x76@2x.png", 103 | "scale" : "2x" 104 | }, 105 | { 106 | "size" : "83.5x83.5", 107 | "idiom" : "ipad", 108 | "filename" : "Icon-App-83.5x83.5@2x.png", 109 | "scale" : "2x" 110 | }, 111 | { 112 | "size" : "1024x1024", 113 | "idiom" : "ios-marketing", 114 | "filename" : "Icon-App-1024x1024@1x.png", 115 | "scale" : "1x" 116 | } 117 | ], 118 | "info" : { 119 | "version" : 1, 120 | "author" : "xcode" 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/booncol/pulsator/30f31fa9c5c7bb5f8c22a6df0fd857ede7b1cadc/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/booncol/pulsator/30f31fa9c5c7bb5f8c22a6df0fd857ede7b1cadc/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/booncol/pulsator/30f31fa9c5c7bb5f8c22a6df0fd857ede7b1cadc/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/booncol/pulsator/30f31fa9c5c7bb5f8c22a6df0fd857ede7b1cadc/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/booncol/pulsator/30f31fa9c5c7bb5f8c22a6df0fd857ede7b1cadc/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/booncol/pulsator/30f31fa9c5c7bb5f8c22a6df0fd857ede7b1cadc/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/booncol/pulsator/30f31fa9c5c7bb5f8c22a6df0fd857ede7b1cadc/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/booncol/pulsator/30f31fa9c5c7bb5f8c22a6df0fd857ede7b1cadc/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/booncol/pulsator/30f31fa9c5c7bb5f8c22a6df0fd857ede7b1cadc/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/booncol/pulsator/30f31fa9c5c7bb5f8c22a6df0fd857ede7b1cadc/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/booncol/pulsator/30f31fa9c5c7bb5f8c22a6df0fd857ede7b1cadc/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/booncol/pulsator/30f31fa9c5c7bb5f8c22a6df0fd857ede7b1cadc/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/booncol/pulsator/30f31fa9c5c7bb5f8c22a6df0fd857ede7b1cadc/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/booncol/pulsator/30f31fa9c5c7bb5f8c22a6df0fd857ede7b1cadc/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/booncol/pulsator/30f31fa9c5c7bb5f8c22a6df0fd857ede7b1cadc/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "LaunchImage.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "LaunchImage@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "LaunchImage@3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/booncol/pulsator/30f31fa9c5c7bb5f8c22a6df0fd857ede7b1cadc/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/booncol/pulsator/30f31fa9c5c7bb5f8c22a6df0fd857ede7b1cadc/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/booncol/pulsator/30f31fa9c5c7bb5f8c22a6df0fd857ede7b1cadc/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md: -------------------------------------------------------------------------------- 1 | # Launch Screen Assets 2 | 3 | You can customize the launch screen with your own desired assets by replacing the image files in this directory. 4 | 5 | You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. -------------------------------------------------------------------------------- /example/ios/Runner/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /example/ios/Runner/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /example/ios/Runner/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleDisplayName 8 | Example 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | example 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 | -------------------------------------------------------------------------------- /example/ios/Runner/Runner-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | #import "GeneratedPluginRegistrant.h" 2 | -------------------------------------------------------------------------------- /example/lib/main.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:pulsator/pulsator.dart'; 3 | 4 | void main() { 5 | runApp(const MyApp()); 6 | } 7 | 8 | class MyApp extends StatelessWidget { 9 | const MyApp({super.key}); 10 | 11 | @override 12 | Widget build(BuildContext context) { 13 | return MaterialApp( 14 | title: 'Pulsator example', 15 | theme: ThemeData(primarySwatch: Colors.blue), 16 | home: const MyHomePage(), 17 | ); 18 | } 19 | } 20 | 21 | class MyHomePage extends StatefulWidget { 22 | const MyHomePage({super.key}); 23 | 24 | @override 25 | State createState() => _MyHomePageState(); 26 | } 27 | 28 | class _MyHomePageState extends State { 29 | int _count = 4; 30 | int _duration = 3; 31 | int _repeatCount = 0; 32 | 33 | void _handleCountChanged(double value) => 34 | setState(() => _count = value.toInt()); 35 | 36 | void _handleDurationChanged(double value) => 37 | setState(() => _duration = value.toInt()); 38 | 39 | void _handleRepeatCountChanged(double value) => 40 | setState(() => _repeatCount = value.toInt()); 41 | 42 | @override 43 | Widget build(BuildContext context) { 44 | return Scaffold( 45 | appBar: AppBar(title: const Text('Pulsator')), 46 | body: SafeArea( 47 | bottom: true, 48 | child: Column( 49 | children: [ 50 | Expanded( 51 | child: Stack( 52 | children: [ 53 | Pulsator( 54 | style: const PulseStyle(color: Colors.red), 55 | count: _count, 56 | duration: Duration(seconds: _duration), 57 | repeat: _repeatCount, 58 | ), 59 | Center( 60 | child: Image.asset( 61 | 'assets/android_phone.png', 62 | width: 128, 63 | height: 128, 64 | ), 65 | ), 66 | ], 67 | ), 68 | ), 69 | Padding( 70 | padding: const EdgeInsets.all(24), 71 | child: _Controls( 72 | count: _count, 73 | duration: _duration, 74 | repeatCount: _repeatCount, 75 | onCountChanged: _handleCountChanged, 76 | onDurationChanged: _handleDurationChanged, 77 | onRepeatCountChanged: _handleRepeatCountChanged, 78 | ), 79 | ), 80 | ], 81 | ), 82 | ), 83 | ); 84 | } 85 | } 86 | 87 | class _Controls extends StatelessWidget { 88 | const _Controls({ 89 | required this.count, 90 | required this.duration, 91 | required this.repeatCount, 92 | required this.onCountChanged, 93 | required this.onDurationChanged, 94 | required this.onRepeatCountChanged, 95 | }); 96 | 97 | final int count; 98 | final int duration; 99 | final int repeatCount; 100 | final ValueChanged onCountChanged; 101 | final ValueChanged onDurationChanged; 102 | final ValueChanged onRepeatCountChanged; 103 | 104 | @override 105 | Widget build(BuildContext context) { 106 | return Table( 107 | defaultVerticalAlignment: TableCellVerticalAlignment.middle, 108 | columnWidths: const { 109 | 0: FixedColumnWidth(70), 110 | 1: FlexColumnWidth(), 111 | 2: FixedColumnWidth(30), 112 | }, 113 | children: [ 114 | TableRow( 115 | children: [ 116 | const Text('Count', textAlign: TextAlign.right), 117 | Slider( 118 | value: count.toDouble(), 119 | min: 1, 120 | max: 9, 121 | onChanged: onCountChanged, 122 | ), 123 | Text(count.toString()), 124 | ], 125 | ), 126 | TableRow( 127 | children: [ 128 | const Text('Duration', textAlign: TextAlign.right), 129 | Slider( 130 | value: duration.toDouble(), 131 | min: 1, 132 | max: 6, 133 | onChanged: onDurationChanged, 134 | ), 135 | Text(duration.toString()), 136 | ], 137 | ), 138 | TableRow( 139 | children: [ 140 | const Text('Repeats', textAlign: TextAlign.right), 141 | Slider( 142 | value: repeatCount.toDouble(), 143 | min: 0, 144 | max: 10, 145 | onChanged: onRepeatCountChanged, 146 | ), 147 | Text(repeatCount.toString()), 148 | ], 149 | ), 150 | ], 151 | ); 152 | } 153 | } 154 | -------------------------------------------------------------------------------- /example/pubspec.lock: -------------------------------------------------------------------------------- 1 | # Generated by pub 2 | # See https://dart.dev/tools/pub/glossary#lockfile 3 | packages: 4 | async: 5 | dependency: transitive 6 | description: 7 | name: async 8 | sha256: bfe67ef28df125b7dddcea62755991f807aa39a2492a23e1550161692950bbe0 9 | url: "https://pub.dev" 10 | source: hosted 11 | version: "2.10.0" 12 | boolean_selector: 13 | dependency: transitive 14 | description: 15 | name: boolean_selector 16 | sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" 17 | url: "https://pub.dev" 18 | source: hosted 19 | version: "2.1.1" 20 | characters: 21 | dependency: transitive 22 | description: 23 | name: characters 24 | sha256: e6a326c8af69605aec75ed6c187d06b349707a27fbff8222ca9cc2cff167975c 25 | url: "https://pub.dev" 26 | source: hosted 27 | version: "1.2.1" 28 | clock: 29 | dependency: transitive 30 | description: 31 | name: clock 32 | sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf 33 | url: "https://pub.dev" 34 | source: hosted 35 | version: "1.1.1" 36 | collection: 37 | dependency: transitive 38 | description: 39 | name: collection 40 | sha256: cfc915e6923fe5ce6e153b0723c753045de46de1b4d63771530504004a45fae0 41 | url: "https://pub.dev" 42 | source: hosted 43 | version: "1.17.0" 44 | cupertino_icons: 45 | dependency: "direct main" 46 | description: 47 | name: cupertino_icons 48 | sha256: d57953e10f9f8327ce64a508a355f0b1ec902193f66288e8cb5070e7c47eeb2d 49 | url: "https://pub.dev" 50 | source: hosted 51 | version: "1.0.6" 52 | fake_async: 53 | dependency: transitive 54 | description: 55 | name: fake_async 56 | sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78" 57 | url: "https://pub.dev" 58 | source: hosted 59 | version: "1.3.1" 60 | flutter: 61 | dependency: "direct main" 62 | description: flutter 63 | source: sdk 64 | version: "0.0.0" 65 | flutter_lints: 66 | dependency: "direct dev" 67 | description: 68 | name: flutter_lints 69 | sha256: a25a15ebbdfc33ab1cd26c63a6ee519df92338a9c10f122adda92938253bef04 70 | url: "https://pub.dev" 71 | source: hosted 72 | version: "2.0.3" 73 | flutter_test: 74 | dependency: "direct dev" 75 | description: flutter 76 | source: sdk 77 | version: "0.0.0" 78 | js: 79 | dependency: transitive 80 | description: 81 | name: js 82 | sha256: "5528c2f391ededb7775ec1daa69e65a2d61276f7552de2b5f7b8d34ee9fd4ab7" 83 | url: "https://pub.dev" 84 | source: hosted 85 | version: "0.6.5" 86 | lints: 87 | dependency: transitive 88 | description: 89 | name: lints 90 | sha256: "5e4a9cd06d447758280a8ac2405101e0e2094d2a1dbdd3756aec3fe7775ba593" 91 | url: "https://pub.dev" 92 | source: hosted 93 | version: "2.0.1" 94 | matcher: 95 | dependency: transitive 96 | description: 97 | name: matcher 98 | sha256: "16db949ceee371e9b99d22f88fa3a73c4e59fd0afed0bd25fc336eb76c198b72" 99 | url: "https://pub.dev" 100 | source: hosted 101 | version: "0.12.13" 102 | material_color_utilities: 103 | dependency: transitive 104 | description: 105 | name: material_color_utilities 106 | sha256: d92141dc6fe1dad30722f9aa826c7fbc896d021d792f80678280601aff8cf724 107 | url: "https://pub.dev" 108 | source: hosted 109 | version: "0.2.0" 110 | meta: 111 | dependency: transitive 112 | description: 113 | name: meta 114 | sha256: "6c268b42ed578a53088d834796959e4a1814b5e9e164f147f580a386e5decf42" 115 | url: "https://pub.dev" 116 | source: hosted 117 | version: "1.8.0" 118 | path: 119 | dependency: transitive 120 | description: 121 | name: path 122 | sha256: db9d4f58c908a4ba5953fcee2ae317c94889433e5024c27ce74a37f94267945b 123 | url: "https://pub.dev" 124 | source: hosted 125 | version: "1.8.2" 126 | pulsator: 127 | dependency: "direct main" 128 | description: 129 | path: ".." 130 | relative: true 131 | source: path 132 | version: "0.0.1" 133 | sky_engine: 134 | dependency: transitive 135 | description: flutter 136 | source: sdk 137 | version: "0.0.99" 138 | source_span: 139 | dependency: transitive 140 | description: 141 | name: source_span 142 | sha256: dd904f795d4b4f3b870833847c461801f6750a9fa8e61ea5ac53f9422b31f250 143 | url: "https://pub.dev" 144 | source: hosted 145 | version: "1.9.1" 146 | stack_trace: 147 | dependency: transitive 148 | description: 149 | name: stack_trace 150 | sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5 151 | url: "https://pub.dev" 152 | source: hosted 153 | version: "1.11.0" 154 | stream_channel: 155 | dependency: transitive 156 | description: 157 | name: stream_channel 158 | sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8" 159 | url: "https://pub.dev" 160 | source: hosted 161 | version: "2.1.1" 162 | string_scanner: 163 | dependency: transitive 164 | description: 165 | name: string_scanner 166 | sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" 167 | url: "https://pub.dev" 168 | source: hosted 169 | version: "1.2.0" 170 | term_glyph: 171 | dependency: transitive 172 | description: 173 | name: term_glyph 174 | sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 175 | url: "https://pub.dev" 176 | source: hosted 177 | version: "1.2.1" 178 | test_api: 179 | dependency: transitive 180 | description: 181 | name: test_api 182 | sha256: ad540f65f92caa91bf21dfc8ffb8c589d6e4dc0c2267818b4cc2792857706206 183 | url: "https://pub.dev" 184 | source: hosted 185 | version: "0.4.16" 186 | vector_math: 187 | dependency: transitive 188 | description: 189 | name: vector_math 190 | sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" 191 | url: "https://pub.dev" 192 | source: hosted 193 | version: "2.1.4" 194 | sdks: 195 | dart: ">=2.19.0 <4.0.0" 196 | -------------------------------------------------------------------------------- /example/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: example 2 | description: A new Flutter project. 3 | publish_to: 'none' # Remove this line if you wish to publish to pub.dev 4 | version: 1.0.0+1 5 | 6 | environment: 7 | sdk: '>=2.19.0 <3.0.0' 8 | 9 | dependencies: 10 | flutter: 11 | sdk: flutter 12 | 13 | cupertino_icons: ^1.0.2 14 | pulsator: 15 | path: ../ 16 | 17 | dev_dependencies: 18 | flutter_test: 19 | sdk: flutter 20 | 21 | flutter_lints: ^2.0.0 22 | 23 | flutter: 24 | uses-material-design: true 25 | assets: 26 | - assets/ -------------------------------------------------------------------------------- /lib/pulsator.dart: -------------------------------------------------------------------------------- 1 | library pulsator; 2 | 3 | export 'src/pulsator.dart'; 4 | export 'src/styles.dart'; 5 | export 'src/pulse_icon.dart'; 6 | -------------------------------------------------------------------------------- /lib/src/pulsator.dart: -------------------------------------------------------------------------------- 1 | /// Copyright 2023 Lukasz Majda (lukasz.majda@gmail.com) 2 | /// 3 | /// 4 | 5 | import 'package:flutter/material.dart'; 6 | import 'package:pulsator/src/styles.dart'; 7 | 8 | const _kOverdrawFactor = 1.4142135624; 9 | 10 | typedef OnCreatedListener = void Function(AnimationController controller); 11 | 12 | /// Pulsator widget that renders pulsating circles. 13 | /// 14 | /// The widget can be configured to render a given number of pulsating circles 15 | /// with a given [style]. 16 | /// 17 | /// The [count] property controls the number of circles rendered at a time. 18 | /// 19 | /// The [duration] property controls the duration of a single pulse animation. 20 | /// 21 | /// The [repeat] property controls the number of times the animation will 22 | /// repeat. If 0, the animation will repeat forever. 23 | /// 24 | /// The [startFromScratch] property controls if the animation should start from 25 | /// the beginning. 26 | /// 27 | /// The [autoStart] property controls if the animation should start 28 | /// automatically when the widget is created. 29 | /// 30 | /// The [fit] property controls how the pulse should be scaled to fit the 31 | /// widget size. The [onCreated] callback is invoked when the animation 32 | /// controller is created. 33 | /// 34 | /// The [onCompleted] callback is invoked when the animation is completed. 35 | /// 36 | /// The [child] property is the child of the widget that is rendered on top of 37 | /// the pulses. 38 | class Pulsator extends StatefulWidget { 39 | /// Make a new [Pulsator] instance. 40 | const Pulsator({ 41 | required this.style, 42 | this.count = 3, 43 | this.duration = const Duration(seconds: 2), 44 | this.repeat = 0, 45 | this.startFromScratch = true, 46 | this.autoStart = true, 47 | this.fit = PulseFit.contain, 48 | this.onCreated, 49 | this.onCompleted, 50 | this.child, 51 | super.key, 52 | }) : assert(count > 0), 53 | assert(repeat >= 0); 54 | 55 | /// Pulse style configuration. 56 | final PulseStyle style; 57 | 58 | /// Number of pulses visible at a time. Default is 3. 59 | final int count; 60 | 61 | /// Duration of a single pulse animation. Default is 2 seconds. 62 | final Duration duration; 63 | 64 | /// Number of times pulses will repeat. If 0, pulses will repeat forever. 65 | /// Default is 0. 66 | final int repeat; 67 | 68 | /// Whether the animation should start from the beginning. Default is true. 69 | final bool startFromScratch; 70 | 71 | /// Whether the animation should start automatically when the widget is created. 72 | /// Default is true. 73 | final bool autoStart; 74 | 75 | /// How the pulse should be scaled to fit the widget size. 76 | /// Default is [PulseFit.contain]. 77 | final PulseFit fit; 78 | 79 | /// Invoked when the animation controller is created. 80 | final OnCreatedListener? onCreated; 81 | 82 | /// Invoked when the animation is completed. 83 | final VoidCallback? onCompleted; 84 | 85 | /// The child of the widget that is rendered on top of the pulses. 86 | final Widget? child; 87 | 88 | @override 89 | State createState() => _PulsatorViewState(); 90 | } 91 | 92 | class _PulsatorViewState extends State 93 | with SingleTickerProviderStateMixin { 94 | AnimationController? _controller; 95 | late Animation _animation; 96 | final int _counter = 0; 97 | double _scaleFactor = 1.0; 98 | late double? _minProgress; 99 | 100 | @override 101 | void initState() { 102 | super.initState(); 103 | _buildAnimation(); 104 | } 105 | 106 | @override 107 | void dispose() { 108 | _controller?.dispose(); 109 | super.dispose(); 110 | } 111 | 112 | @override 113 | void didUpdateWidget(covariant Pulsator oldWidget) { 114 | // Recalculate the scale factor. 115 | if (widget.fit == PulseFit.cover) { 116 | _scaleFactor = (widget.count > 1 117 | ? 1.0 / 118 | widget.style.pulseCurve.transform( 119 | (widget.count - 1) / widget.count, 120 | ) 121 | : 1.0) * 122 | _kOverdrawFactor; 123 | } else { 124 | _scaleFactor = 1.0; 125 | } 126 | 127 | // Rebuild the animation if necessary. 128 | if (widget.repeat != oldWidget.repeat || 129 | widget.duration != oldWidget.duration || 130 | widget.startFromScratch != oldWidget.startFromScratch || 131 | widget.autoStart != oldWidget.autoStart || 132 | widget.count != oldWidget.count) { 133 | _buildAnimation(); 134 | } 135 | 136 | super.didUpdateWidget(oldWidget); 137 | } 138 | 139 | /// Build animation controller and animation based on widget configuration. 140 | void _buildAnimation() { 141 | // Calculate animation end value based on repeat count and pulse count. 142 | late final double animEnd; 143 | if (widget.repeat > 0) { 144 | animEnd = widget.repeat + 1.0 - 1.0 / widget.count; 145 | } else { 146 | animEnd = 1.0; 147 | } 148 | 149 | // Create animation controller and animation if not already created. 150 | // Otherwise, update only the animation duration. 151 | final firstBuild = _controller == null; 152 | final duration = (widget.duration.inMilliseconds * animEnd).toInt(); 153 | if (_controller == null) { 154 | _controller = AnimationController( 155 | duration: Duration(milliseconds: duration), 156 | vsync: this, 157 | )..addStatusListener(_handleAnimationStatus); 158 | } else { 159 | _controller!.duration = Duration(milliseconds: duration); 160 | } 161 | 162 | _animation = Tween(begin: 0.0, end: animEnd).animate(_controller!); 163 | _minProgress = widget.startFromScratch ? 0.0 : null; 164 | 165 | // Start animation if autoStart is true. 166 | if (widget.autoStart) { 167 | _controller!.reset(); 168 | _controller!.forward(); 169 | } 170 | 171 | // Invoke onCreated callback if it is a first build. 172 | if (firstBuild && widget.onCreated != null) { 173 | widget.onCreated!.call(_controller!); 174 | } 175 | } 176 | 177 | /// Handle animation status changes to reset the animation if necessary. 178 | void _handleAnimationStatus(AnimationStatus status) { 179 | if (status != AnimationStatus.completed) { 180 | return; 181 | } 182 | 183 | if (widget.repeat > 0) { 184 | // Animation is completed so invoke the callback. 185 | widget.onCompleted?.call(); 186 | return; 187 | } 188 | 189 | // It's another animation cycle, so don't clamp the progress. 190 | _minProgress = null; 191 | 192 | _controller!.reset(); 193 | _controller!.forward(); 194 | } 195 | 196 | @override 197 | Widget build(BuildContext context) { 198 | final pulse = AnimatedBuilder( 199 | animation: _animation, 200 | builder: (context, child) { 201 | final pulses = [ 202 | for (var i = 0; i < widget.count; i++) 203 | _PulseCircle( 204 | style: widget.style, 205 | scale: _animation.value, 206 | offset: i / widget.count, 207 | progress: _counter + _animation.value, 208 | minProgress: _minProgress, 209 | maxProgress: widget.repeat > 0 ? widget.repeat.toDouble() : null, 210 | scaleFactor: _scaleFactor, 211 | ), 212 | ]; 213 | // Pulses should be rendered in order from the biggest to the smallest. 214 | pulses.sort(_compareZIndex); 215 | 216 | return Stack( 217 | alignment: Alignment.center, 218 | fit: StackFit.expand, 219 | children: pulses.map((e) => e).toList(growable: false), 220 | ); 221 | }, 222 | ); 223 | 224 | // If there is no child, just return the pulse. 225 | if (widget.child == null) { 226 | return pulse; 227 | } 228 | 229 | return Stack( 230 | alignment: Alignment.center, 231 | children: [ 232 | pulse, 233 | widget.child!, 234 | ], 235 | ); 236 | } 237 | 238 | /// Compare two pulses by their z-index. 239 | static int _compareZIndex(_PulseCircle a, _PulseCircle b) { 240 | final ta = (a.progress - a.offset) % 1.0; 241 | final tb = (b.progress - b.offset) % 1.0; 242 | return tb.compareTo(ta); 243 | } 244 | } 245 | 246 | class _PulseCircle extends StatelessWidget { 247 | const _PulseCircle({ 248 | required this.style, 249 | required this.scale, 250 | required this.offset, 251 | required this.progress, 252 | this.minProgress, 253 | this.maxProgress, 254 | this.scaleFactor = 1.0, 255 | }) : assert(scale >= 0.0), 256 | assert(offset >= 0.0), 257 | assert(progress >= 0.0), 258 | assert(scaleFactor > 0.0); 259 | 260 | /// Pulse style configuration. 261 | final PulseStyle style; 262 | 263 | /// Current animation scale value. 264 | final double scale; 265 | 266 | /// Offset of the pulse in the animation cycle. 267 | final double offset; 268 | 269 | /// Current animation progress value. 270 | final double progress; 271 | 272 | /// Minimum animation progress value to render the pulse. 273 | final double? minProgress; 274 | 275 | /// Maximum animation progress value to render the pulse. 276 | final double? maxProgress; 277 | 278 | /// Scale factor to apply to the pulse. Used when the pulse is rendered 279 | /// to fill the entire widget. 280 | final double scaleFactor; 281 | 282 | @override 283 | Widget build(BuildContext context) { 284 | // Calculate the current pulse progress, taking into account the offset. 285 | final progress = this.progress - offset; 286 | 287 | // If minProgress or maxProgress are set, check if the pulse should be 288 | // rendered. 289 | if ((minProgress != null && progress < minProgress!) || 290 | (maxProgress != null && progress > maxProgress!)) { 291 | return const SizedBox.shrink(); 292 | } 293 | 294 | // Make sure the progress is between 0.0 and 1.0. 295 | final t = progress % 1.0; 296 | final opacity = 297 | style.fadeOpacity ? 1.0 - style.opacityCurve.transform(t) : 1.0; 298 | final scale = style.startSize + 299 | style.pulseCurve.transform(t) * scaleFactor * (1.0 - style.startSize); 300 | 301 | return Transform.scale( 302 | scale: scale, 303 | child: Container( 304 | decoration: BoxDecoration( 305 | shape: BoxShape.circle, 306 | color: style.gradientStyle == null 307 | ? style.color.withOpacity(opacity) 308 | : null, 309 | gradient: style.gradientStyle != null 310 | ? RadialGradient( 311 | radius: style.gradientStyle!.radius, 312 | stops: [style.gradientStyle!.start, style.gradientStyle!.end], 313 | colors: style.gradientStyle!.reverseColors 314 | ? [ 315 | style.color.withOpacity(opacity), 316 | style.gradientStyle!.startColor != null 317 | ? style.gradientStyle!.startColor! 318 | .withOpacity(opacity) 319 | : style.color.withOpacity(0), 320 | ] 321 | : [ 322 | style.gradientStyle!.startColor != null 323 | ? style.gradientStyle!.startColor! 324 | .withOpacity(opacity) 325 | : style.color.withOpacity(0), 326 | style.color.withOpacity(opacity), 327 | ]) 328 | : null, 329 | border: style.borderWidth != null && style.borderColor != null 330 | ? Border.all( 331 | color: style.borderColor!.withOpacity(opacity), 332 | width: style.borderWidth!, 333 | ) 334 | : null, 335 | ), 336 | ), 337 | ); 338 | } 339 | } 340 | -------------------------------------------------------------------------------- /lib/src/pulse_icon.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:pulsator/src/pulsator.dart'; 3 | import 'package:pulsator/src/styles.dart'; 4 | 5 | /// A widget that displays an icon with a pulsing effect. 6 | /// 7 | /// The icon is displayed in the center of the widget. The pulsing effect is 8 | /// displayed as a circle around the icon. 9 | /// 10 | /// [icon] is the icon to display. Required. 11 | /// 12 | /// [iconColor] is the color of the icon. Default is white. 13 | /// 14 | /// [iconSize] is the size of the icon. Default is 24. 15 | /// 16 | /// [innerColor] is the color of the inner, non-pulsing circle. Default is the 17 | /// pulse color. 18 | /// 19 | /// [innerSize] is the size of the inner, non-pulsing circle. Default is the 20 | /// icon size. 21 | /// 22 | /// [pulseColor] is the color of the pulse. 23 | /// 24 | /// [pulseSize] is the size of the pulse. Default is 64. 25 | /// 26 | /// [pulseCount] is the number of pulses to display. Default is 3. 27 | /// 28 | /// [pulseDuration] is the duration of a single pulse animation. Default is 4 29 | /// seconds. 30 | /// 31 | /// Example: 32 | /// ```dart 33 | /// PulseIcon( 34 | /// icon: Icons.favorite, 35 | /// pulseColor: Colors.red, 36 | /// pulseCount: 5, 37 | /// pulseDuration: Duration(seconds: 2), 38 | /// iconColor: Colors.white, 39 | /// iconSize: 44, 40 | /// innerSize: 54, 41 | /// pulseSize: 116, 42 | /// ) 43 | /// ``` 44 | class PulseIcon extends StatelessWidget { 45 | const PulseIcon({ 46 | required this.icon, 47 | required this.pulseColor, 48 | this.iconColor = Colors.white, 49 | this.iconSize = 24, 50 | this.pulseSize = 64, 51 | this.innerColor, 52 | this.innerSize, 53 | this.pulseCount = 3, 54 | this.pulseDuration = const Duration(seconds: 4), 55 | super.key, 56 | }) : assert(pulseCount > 0), 57 | assert(pulseSize > 0.0), 58 | assert(iconSize > 0.0); 59 | 60 | /// The icon to display. 61 | final IconData icon; 62 | 63 | /// The color of the icon. Default is white. 64 | final Color iconColor; 65 | 66 | /// The size of the icon. Default is 24. 67 | final double iconSize; 68 | 69 | /// The color of the inner, non-pulsing circle. Default is the pulse color. 70 | final Color? innerColor; 71 | 72 | /// The size of the inner, non-pulsing circle. Default is the icon size. 73 | final double? innerSize; 74 | 75 | /// The color of the pulse. 76 | final Color pulseColor; 77 | 78 | /// The size of the pulse. Default is 64. 79 | final double pulseSize; 80 | 81 | /// The number of pulses to display. Default is 3. 82 | final int pulseCount; 83 | 84 | /// The duration of a single pulse animation. Default is 4 seconds. 85 | final Duration pulseDuration; 86 | 87 | @override 88 | Widget build(BuildContext context) { 89 | final innerSize = this.innerSize ?? iconSize; 90 | return SizedBox( 91 | width: pulseSize, 92 | height: pulseSize, 93 | child: Pulsator( 94 | count: pulseCount, 95 | duration: pulseDuration, 96 | startFromScratch: false, 97 | style: PulseStyle( 98 | color: pulseColor, 99 | startSize: innerSize / pulseSize, 100 | // scaleCurve: Curves.easeOut, 101 | ), 102 | child: Stack( 103 | alignment: Alignment.center, 104 | children: [ 105 | if (innerSize > 0.0) 106 | Container( 107 | width: innerSize, 108 | height: innerSize, 109 | decoration: BoxDecoration( 110 | color: innerColor ?? pulseColor, 111 | shape: BoxShape.circle, 112 | ), 113 | ), 114 | Icon(icon, color: iconColor, size: iconSize), 115 | ], 116 | ), 117 | ), 118 | ); 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /lib/src/styles.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | /// How the pulse should be scaled to fit the widget size. 4 | enum PulseFit { 5 | /// The pulse will be scaled to fit the widget size. 6 | contain, 7 | 8 | /// The pulse will be scaled to fill the widget size. 9 | cover, 10 | } 11 | 12 | /// The style of the pulse gradient. 13 | /// 14 | /// [radius] is the radius of the gradient, as a fraction pulse radius. 15 | /// 16 | /// [start] is the start point of the gradient, as a fraction of the pulse 17 | /// radius. 18 | /// 19 | /// [end] is the end point of the gradient, as a fraction of the pulse radius. 20 | /// 21 | /// [startColor] is the start color of the gradient. If null, the pulse color 22 | /// will be used with the opacity set to 0.0. 23 | /// 24 | /// [reverseColors] is if the gradient colors should be reversed. If true, the 25 | /// gradient will start from [end] and end at [start]. 26 | class PulseGradientStyle { 27 | /// Make a new [PulseGradientStyle] instance. 28 | const PulseGradientStyle({ 29 | this.radius = 0.5, 30 | this.start = 0.0, 31 | this.end = 1.0, 32 | this.startColor, 33 | this.reverseColors = false, 34 | }) : assert(radius >= 0.0 && radius <= 1.0), 35 | assert(start >= 0.0 && start <= 1.0), 36 | assert(end >= 0.0 && end <= 1.0); 37 | 38 | /// The radius of the gradient, as a fraction pulse radius. Default is 0.5. 39 | final double radius; 40 | 41 | /// The start point of the gradient, as a fraction of the pulse radius. 42 | /// Default is 0.0. 43 | final double start; 44 | 45 | /// The end point of the gradient, as a fraction of the pulse radius. Default 46 | /// is 1.0. 47 | final double end; 48 | 49 | /// The start color of the gradient. If null, the pulse color will be used 50 | /// with the opacity set to 0.0. 51 | final Color? startColor; 52 | 53 | /// Whether the gradient colors should be reversed. If true, the gradient will 54 | /// start from [end] and end at [start]. Default is false. 55 | final bool reverseColors; 56 | } 57 | 58 | /// The style of the pulse. 59 | /// 60 | /// [color] is the main color of the pulse. 61 | /// 62 | /// [borderColor] is the border color of the pulse. 63 | /// 64 | /// [borderWidth] is the border width of the pulse. If 0, no border will be 65 | /// rendered. 66 | /// 67 | /// [gradientStyle] is the gradient style of the pulse. If null, no gradient 68 | /// will be rendered. 69 | /// 70 | /// [pulseCurve] is the pulse scale animation curve (default is linear). 71 | /// 72 | /// [opacityCurve] is the pulse opacity animation curve (default is linear). 73 | /// 74 | /// [fadeOpacity] is if the opacity should be animated from 1.0 to 0.0. Default 75 | /// 76 | /// [startSize] is the size of the pulse when it begins, as a fraction of the 77 | /// pulse radius. Default is 0.0. 78 | class PulseStyle { 79 | /// Make a new [PulseStyle] instance. 80 | const PulseStyle({ 81 | this.color = Colors.red, 82 | this.borderColor, 83 | this.borderWidth, 84 | this.gradientStyle, 85 | this.pulseCurve = Curves.linear, 86 | this.opacityCurve = Curves.linear, 87 | this.fadeOpacity = true, 88 | this.startSize = 0.0, 89 | }) : assert(startSize >= 0.0 && startSize <= 1.0); 90 | 91 | /// Main pulse color. 92 | final Color color; 93 | 94 | /// Pulse border color. If `null`, no border will be rendered. 95 | final Color? borderColor; 96 | 97 | /// Pulse border width. If `null`, no border will be rendered. 98 | final double? borderWidth; 99 | 100 | /// If set, the pulse will be rendered as a gradient. 101 | final PulseGradientStyle? gradientStyle; 102 | 103 | /// Pulse scale animation curve (default is linear). 104 | final Curve pulseCurve; 105 | 106 | /// Pulse opacity animation curve (default is linear). 107 | final Curve opacityCurve; 108 | 109 | /// Whether the opacity should be animated from 1.0 to 0.0. Default is true. 110 | final bool fadeOpacity; 111 | 112 | /// The size of the pulse when it begins, as a fraction of the pulse radius. 113 | /// Default is 0.0. 114 | final double startSize; 115 | } 116 | -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: pulsator 2 | description: "Pulse animation for Flutter." 3 | version: 1.0.0+2 4 | homepage: https://github.com/booncol/pulsator 5 | repository: https://github.com/booncol/pulsator 6 | issue_tracker: https://github.com/booncol/pulsator/issues 7 | 8 | environment: 9 | sdk: ">=2.19.0 <3.0.0" 10 | flutter: ">=3.0.0" 11 | 12 | dependencies: 13 | flutter: 14 | sdk: flutter 15 | 16 | dev_dependencies: 17 | flutter_test: 18 | sdk: flutter 19 | flutter_lints: ^2.0.0 20 | 21 | flutter: 22 | uses-material-design: true 23 | --------------------------------------------------------------------------------