├── .gitignore ├── CHANGELOG.md ├── LICENSE ├── README.md ├── images ├── clap.png └── sparkles.png ├── lib └── medium_clap_flutter.dart ├── medium_clap_flutter.iml ├── pubspec.lock └── pubspec.yaml /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .dart_tool/ 3 | 4 | .packages 5 | .pub/ 6 | 7 | build/ 8 | ios/.generated/ 9 | ios/Flutter/Generated.xcconfig 10 | ios/Runner/GeneratedPluginRegistrant.* 11 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## [0.0.1] - TODO: Add release date. 2 | 3 | * TODO: Describe initial release. 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2018 Pawan Kumar 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 👏 MediumClapFlutter 2 | 3 | [![Say Thanks!](https://img.shields.io/badge/Say%20Thanks-!-1EAEDB.svg)](https://saythanks.io/to/iampawan) [![Twitter](https://img.shields.io/twitter/url/https/github.com/iampawan/MediumClapFlutter.svg?style=social)](https://twitter.com/intent/tweet?text=Wow:&url=https%3A%2F%2Fgithub.com%2Fiampawan%2FMediumClapFlutter) 4 | 5 | A Custom Floating Action Button (FAB) library like clapping effect on Medium. 6 | 7 | The source code is **100% Dart**, and everything resides in the [/lib](https://github.com/iampawan/MediumClapFlutter/tree/master/lib) folder. 8 | 9 | 10 | ### Show some :heart: and star the repo to support the project 11 | 12 | [![GitHub stars](https://img.shields.io/github/stars/iampawan/MediumClapFlutter.svg?style=social&label=Star)](https://github.com/iampawan/MediumClapFlutter) [![GitHub forks](https://img.shields.io/github/forks/iampawan/MediumClapFlutter.svg?style=social&label=Fork)](https://github.com/iampawan/MediumClapFlutter/fork) [![GitHub watchers](https://img.shields.io/github/watchers/iampawan/MediumClapFlutter.svg?style=social&label=Watch)](https://github.com/iampawan/MediumClapFlutter) [![GitHub followers](https://img.shields.io/github/followers/iampawan.svg?style=social&label=Follow)](https://github.com/iampawan/MediumClapFluttert) 13 | [![Twitter Follow](https://img.shields.io/twitter/follow/imthepk.svg?style=social)](https://twitter.com/imthepk) 14 | 15 | [![Open Source Love](https://badges.frapsoft.com/os/v1/open-source.svg?v=102)](https://opensource.org/licenses/Apache-2.0) 16 | [![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](https://github.com/iampawan/MediumClapFlutter/blob/master/LICENSE) 17 | 18 | ## YouTube Channel 19 | 20 | [MTechViral](https://www.youtube.com/c/MTechViral) 21 | 22 | ## Facebook Group 23 | 24 | [Let's Flutter](https://www.facebook.com/groups/425920117856409/) 25 | 26 | 27 | 28 | ## 💻 Installation 29 | In the `dependencies:` section of your `pubspec.yaml`, add the following line: 30 | 31 | ```yaml 32 | medium_clap_flutter: 33 | ``` 34 | 35 | ## ❔ Usage 36 | 37 | ### ClapFAB for Icon 38 | 39 | ```dart 40 | import 'package:medium_clap_flutter/medium_clap_flutter.dart'; 41 | 42 | class MyWidget extends StatelessWidget { 43 | Widget build(BuildContext context) { 44 | return Center( 45 | //Use this child anywhere in your app 46 | child: ClapFAB.icon( 47 | defaultIcon: FontAwesomeIcons.heart, 48 | filledIcon: FontAwesomeIcons.solidHeart, 49 | countCircleColor: Colors.green, 50 | defaultIconColor: Colors.green, 51 | hasShadow: true, 52 | sparkleColor: Colors.green, 53 | shadowColor: Colors.green, 54 | filledIconColor: Colors.green, 55 | ), 56 | ); 57 | } 58 | } 59 | 60 | ``` 61 | 62 | ### ClapFAB for Image 63 | 64 | ```dart 65 | import 'package:medium_clap_flutter/medium_clap_flutter.dart'; 66 | 67 | class MyWidget extends StatelessWidget { 68 | Widget build(BuildContext context) { 69 | return Center( 70 | //Use this child anywhere in your app 71 | child: ClapFAB.image( 72 | defaultImage: "images/clap.png", 73 | filledImage: "images/clap.png", 74 | countCircleColor: Colors.red, 75 | hasShadow: true, 76 | sparkleColor: Colors.red, 77 | shadowColor: Colors.red, 78 | defaultImageColor: Colors.red, 79 | filledImageColor: Colors.red, 80 | ), 81 | ); 82 | } 83 | } 84 | 85 | ``` 86 | ## 🎨 Customization and Attributes 87 | 88 | All customizable attributes for ClapFab 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 |
Attribute NameDefault ValueDescription
defaultIcon/defaultImageIcons.favorite_border/"images/clap.png"The default icon/image of the ClapFab button
filledIcon/filledImageIcons.favorite/"images.clap.png"The filled icon/image after clapping of the ClapFab button
defaultIconColor/defaultImageColorColors.blueThe color of default icon/image of the ClapFab button
filledIconColor/defaultImageColorColors.blueThe filled color of icon/image after clapping of the ClapFab button
hasShadowtrueWhether to have shadow or not around ClapFab button
countCircleColorColors.blueThe color of count's circle background
countTextColorColors.whiteThe color of count's circle text
sparkleColorColors.blueThe color of sparkels around the count
shadowColorColors.blueThe color of the shadow
floatingOutlineColorColors.whiteThe outline color/ border color of the ClabFab button
floatingBgColorColors.whiteThe Background color of the ClabFab button
initCounter0Initial counter value
maxCounterNOT_LIMIT_INCREMENT (-1)Maximum counter value
161 | 162 | ## Clap Count 163 | Use one of this properties `clapFabCallback` or `clapUpCallback` to get the clap count 164 | ```dart 165 | ClapFAB.image( 166 | clapFabCallback: (int counter)=>print(counter), 167 | ); 168 | 169 | ``` 170 | OR 171 | ```dart 172 | ClapFAB.icon( 173 | clapFabCallback: (int counter)=>print(counter), 174 | ); 175 | ``` 176 | OR 177 | ```dart 178 | ClapFAB.icon( 179 | clapUpCallback: (int counter)=>print(counter), 180 | ); 181 | ``` 182 | 183 | ## 📃 Inspired from 184 | * Medium Clap By Kartik Sharma [https://github.com/Kartik1607/FlutterUI/tree/master/MediumClapAnimation/medium_clap](https://github.com/Kartik1607/FlutterUI/tree/master/MediumClapAnimation/medium_clap) 185 | * MediumClap-Android By Wajahat Karim [https://github.com/wajahatkarim3/MediumClap-Android](https://github.com/wajahatkarim3/MediumClap-Android) 186 | 187 | ## 💰 Donations 188 | 189 | This project needs you! If you would like to support this project's further development, the creator of this project or the continuous maintenance of this project, feel free to donate. Your donation is highly appreciated (and I love food, coffee and beer). Thank you! 190 | 191 | **PayPal** 192 | 193 | * **[Donate $5](https://www.paypal.me/imthepk/5)**: Thank's for creating this project, here's a tea (or some juice) for you! 194 | * **[Donate $10](https://www.paypal.me/imthepk/10)**: Wow, I am stunned. Let me take you to the movies! 195 | * **[Donate $15](https://www.paypal.me/imthepk/15)**: I really appreciate your work, let's grab some lunch! 196 | * **[Donate $25](https://www.paypal.me/imthepk/25)**: That's some awesome stuff you did right there, dinner is on me! 197 | * **[Donate $50](https://www.paypal.me/imthepk/50)**: I really really want to support this project, great job! 198 | * **[Donate $100](https://www.paypal.me/imthepk/100)**: You are the man! This project saved me hours (if not days) of struggle and hard work, simply awesome! 199 | * **[Donate $2799](https://www.paypal.me/imthepk/2799)**: Go buddy, buy Macbook Pro for yourself! 200 | 201 | Of course, you can also choose what you want to donate, all donations are awesome! 202 | 203 | ## 👨 Developed By 204 | 205 | ``` 206 | Pawan Kumar 207 | ``` 208 | GDE (Google Developer Expert) for Flutter. Passionate #Flutter, #Android Developer. #Entrepreneur #YouTuber 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | # 👍 How to Contribute 217 | 1. Fork it 218 | 2. Create your feature branch (git checkout -b my-new-feature) 219 | 3. Commit your changes (git commit -am 'Add some feature') 220 | 4. Push to the branch (git push origin my-new-feature) 221 | 5. Create new Pull Request 222 | 223 | # 📃 License 224 | 225 | Copyright (c) 2018 Pawan Kumar 226 | 227 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 228 | 229 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 230 | 231 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 232 | 233 | ## Getting Started 234 | 235 | For help getting started with Flutter, view our online [documentation](https://flutter.io/). 236 | 237 | For help on editing package code, view the [documentation](https://flutter.io/developing-packages/). 238 | -------------------------------------------------------------------------------- /images/clap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iampawan/MediumClapFlutter/bec03143286b112eac2ad806e001e5e40a051186/images/clap.png -------------------------------------------------------------------------------- /images/sparkles.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iampawan/MediumClapFlutter/bec03143286b112eac2ad806e001e5e40a051186/images/sparkles.png -------------------------------------------------------------------------------- /lib/medium_clap_flutter.dart: -------------------------------------------------------------------------------- 1 | library medium_clap_flutter; 2 | 3 | import 'dart:async'; 4 | import 'dart:math'; 5 | 6 | import 'package:flutter/material.dart'; 7 | 8 | /// A Custom Floating Action Button (FAB) library like clapping effect on Medium. 9 | class ClapFAB extends StatefulWidget { 10 | static const int NOT_LIMIT_INCREMENT = -1; 11 | 12 | /// The color of count's circle background 13 | final countCircleColor; 14 | 15 | /// The color of count's circle text 16 | final countTextColor; 17 | 18 | /// Whether to have shadow or not around ClapFab button 19 | final hasShadow; 20 | 21 | /// The color of the shadow 22 | final shadowColor; 23 | 24 | /// The outline color/ border color of the ClabFab button 25 | final floatingOutlineColor; 26 | 27 | /// The Background color of the ClabFab button 28 | final floatingBgColor; 29 | 30 | /// The color of sparkels around the count 31 | final sparkleColor; 32 | 33 | /// The default icon of the ClapFab button 34 | final defaultIcon; 35 | 36 | /// The color of default icon of the ClapFab button 37 | final defaultIconColor; 38 | 39 | /// The filled icon after clapping of the ClapFab button 40 | final filledIcon; 41 | 42 | /// The filled icon color after clapping of the ClapFab button 43 | final filledIconColor; 44 | 45 | /// On Tap Down callback 46 | final clapFabCallback; 47 | 48 | /// On Tap Up callback 49 | final clapUpCallback; 50 | 51 | /// The default image of the ClapFab button 52 | final defaultImage; 53 | 54 | /// The color of default image of the ClapFab button 55 | final defaultImageColor; 56 | 57 | /// The filled image after clapping of the ClapFab button 58 | final filledImage; 59 | 60 | /// The color of filled image of the ClapFab button 61 | final filledImageColor; 62 | 63 | /// Starting counter value (default 0) 64 | final initCounter; 65 | 66 | /// Maximum counter value (default SHOULD_NOT_INCREMENT, which will not limit increment) 67 | final maxCounter; 68 | 69 | const ClapFAB.icon( 70 | {this.countCircleColor = Colors.blue, 71 | this.countTextColor = Colors.white, 72 | this.hasShadow = false, 73 | this.shadowColor = Colors.blue, 74 | this.floatingOutlineColor = Colors.white, 75 | this.floatingBgColor = Colors.white, 76 | this.defaultIcon = Icons.favorite_border, 77 | this.defaultIconColor = Colors.blue, 78 | this.sparkleColor = Colors.blue, 79 | this.filledIcon = Icons.favorite, 80 | this.filledIconColor = Colors.blue, 81 | this.initCounter = 0, 82 | this.maxCounter = NOT_LIMIT_INCREMENT, 83 | this.clapFabCallback, 84 | this.clapUpCallback}) 85 | : defaultImage = null, 86 | defaultImageColor = null, 87 | filledImage = null, 88 | filledImageColor = null; 89 | 90 | const ClapFAB.image( 91 | {this.countCircleColor = Colors.blue, 92 | this.countTextColor = Colors.white, 93 | this.hasShadow = false, 94 | this.shadowColor = Colors.blue, 95 | this.floatingOutlineColor = Colors.white, 96 | this.floatingBgColor = Colors.white, 97 | this.sparkleColor = Colors.blue, 98 | this.defaultImage = "images/clap.png", 99 | this.defaultImageColor = Colors.blue, 100 | this.filledImageColor = Colors.blue, 101 | this.filledImage = "images/clap.png", 102 | this.initCounter = 0, 103 | this.maxCounter = NOT_LIMIT_INCREMENT, 104 | this.clapFabCallback, 105 | this.clapUpCallback}) 106 | : defaultIcon = null, 107 | defaultIconColor = null, 108 | filledIcon = null, 109 | filledIconColor = null; 110 | 111 | @override 112 | _ClapFABState createState() => _ClapFABState(); 113 | } 114 | 115 | enum ScoreWidgetStatus { HIDDEN, BECOMING_VISIBLE, VISIBLE, BECOMING_INVISIBLE } 116 | 117 | class _ClapFABState extends State with TickerProviderStateMixin { 118 | int counter = 0; 119 | double _sparklesAngle = 0.0; 120 | ScoreWidgetStatus _scoreWidgetStatus = ScoreWidgetStatus.HIDDEN; 121 | final duration = Duration(milliseconds: 400); 122 | final oneSecond = Duration(seconds: 1); 123 | Random random; 124 | Timer holdTimer, scoreOutETA; 125 | AnimationController scoreInAnimationController, 126 | scoreOutAnimationController, 127 | scoreSizeAnimationController, 128 | sparklesAnimationController; 129 | Animation scoreOutPositionAnimation, sparklesAnimation; 130 | 131 | initState() { 132 | super.initState(); 133 | random = Random(); 134 | counter = widget.initCounter; 135 | scoreInAnimationController = 136 | AnimationController(duration: Duration(milliseconds: 150), vsync: this); 137 | scoreInAnimationController.addListener(() { 138 | setState(() {}); // Calls render function 139 | }); 140 | 141 | scoreOutAnimationController = 142 | AnimationController(vsync: this, duration: duration); 143 | scoreOutPositionAnimation = Tween(begin: 100.0, end: 150.0).animate( 144 | CurvedAnimation( 145 | parent: scoreOutAnimationController, curve: Curves.easeOut)); 146 | scoreOutPositionAnimation.addListener(() { 147 | setState(() {}); 148 | }); 149 | scoreOutAnimationController.addStatusListener((status) { 150 | if (status == AnimationStatus.completed) { 151 | _scoreWidgetStatus = ScoreWidgetStatus.HIDDEN; 152 | } 153 | }); 154 | 155 | scoreSizeAnimationController = 156 | AnimationController(vsync: this, duration: Duration(milliseconds: 150)); 157 | scoreSizeAnimationController.addStatusListener((status) { 158 | if (status == AnimationStatus.completed) { 159 | scoreSizeAnimationController.reverse(); 160 | } 161 | }); 162 | scoreSizeAnimationController.addListener(() { 163 | setState(() {}); 164 | }); 165 | 166 | sparklesAnimationController = 167 | AnimationController(vsync: this, duration: duration); 168 | sparklesAnimation = CurvedAnimation( 169 | parent: sparklesAnimationController, curve: Curves.easeIn); 170 | sparklesAnimation.addListener(() { 171 | setState(() {}); 172 | }); 173 | } 174 | 175 | dispose() { 176 | scoreInAnimationController.dispose(); 177 | scoreOutAnimationController.dispose(); 178 | super.dispose(); 179 | } 180 | 181 | void increment(Timer t) { 182 | scoreSizeAnimationController.forward(from: 0.0); 183 | sparklesAnimationController.forward(from: 0.0); 184 | 185 | if (_shouldIncrement()) { 186 | setState(() { 187 | counter++; 188 | _sparklesAngle = random.nextDouble() * (2 * pi); 189 | }); 190 | } 191 | } 192 | 193 | bool _shouldIncrement() => widget.maxCounter == ClapFAB.NOT_LIMIT_INCREMENT 194 | ? true 195 | : counter < widget.maxCounter; 196 | 197 | void onTapDown(TapDownDetails tap) { 198 | // User pressed the button. This can be a tap or a hold. 199 | if (scoreOutETA != null) { 200 | scoreOutETA.cancel(); // We do not want the score to vanish! 201 | } 202 | if (_scoreWidgetStatus == ScoreWidgetStatus.BECOMING_INVISIBLE) { 203 | // We tapped down while the widget was flying up. Need to cancel that animation. 204 | scoreOutAnimationController.stop(canceled: true); 205 | _scoreWidgetStatus = ScoreWidgetStatus.VISIBLE; 206 | } else if (_scoreWidgetStatus == ScoreWidgetStatus.HIDDEN) { 207 | _scoreWidgetStatus = ScoreWidgetStatus.BECOMING_VISIBLE; 208 | scoreInAnimationController.forward(from: 0.0); 209 | } 210 | increment(null); // Take care of tap 211 | holdTimer = Timer.periodic(duration, increment); // Takes care of hold 212 | if (widget.clapFabCallback != null) widget.clapFabCallback(counter); 213 | } 214 | 215 | void onTapUp(TapUpDetails tap) { 216 | // User removed his finger from button. 217 | scoreOutETA = Timer(oneSecond, () { 218 | scoreOutAnimationController.forward(from: 0.0); 219 | _scoreWidgetStatus = ScoreWidgetStatus.BECOMING_INVISIBLE; 220 | }); 221 | if (widget.clapUpCallback != null) widget.clapUpCallback(counter); 222 | holdTimer.cancel(); 223 | } 224 | 225 | Widget getClapButton() { 226 | // Using custom gesture detector because we want to keep increasing the claps 227 | // when user holds the button. 228 | 229 | var extraSize = 0.0; 230 | if (_scoreWidgetStatus == ScoreWidgetStatus.VISIBLE || 231 | _scoreWidgetStatus == ScoreWidgetStatus.BECOMING_VISIBLE) { 232 | extraSize = scoreSizeAnimationController.value * 3; 233 | } 234 | return GestureDetector( 235 | onTapUp: onTapUp, 236 | onTapDown: onTapDown, 237 | child: Container( 238 | height: 60.0 + extraSize, 239 | width: 60.0 + extraSize, 240 | padding: EdgeInsets.all(10.0), 241 | decoration: BoxDecoration( 242 | border: 243 | Border.all(color: widget.floatingOutlineColor, width: 1.0), 244 | borderRadius: BorderRadius.circular(50.0), 245 | color: widget.floatingBgColor, 246 | boxShadow: [ 247 | widget.hasShadow 248 | ? BoxShadow(color: widget.shadowColor, blurRadius: 8.0) 249 | : BoxShadow() 250 | ]), 251 | child: widget.defaultImage == null 252 | ? Icon( 253 | counter > 0 ? widget.filledIcon : widget.defaultIcon, 254 | color: counter > 0 255 | ? widget.filledIconColor 256 | : widget.defaultIconColor, 257 | size: 30.0, 258 | ) 259 | : ImageIcon( 260 | new AssetImage( 261 | counter > 0 ? widget.filledImage : widget.defaultImage), 262 | color: counter > 0 263 | ? widget.filledImageColor 264 | : widget.defaultImageColor, 265 | size: 30.0), 266 | )); 267 | } 268 | 269 | Widget getScoreButton() { 270 | var scorePosition = 0.0; 271 | var scoreOpacity = 0.0; 272 | var extraSize = 0.0; 273 | switch (_scoreWidgetStatus) { 274 | case ScoreWidgetStatus.HIDDEN: 275 | break; 276 | case ScoreWidgetStatus.BECOMING_VISIBLE: 277 | case ScoreWidgetStatus.VISIBLE: 278 | scorePosition = scoreInAnimationController.value * 100; 279 | scoreOpacity = scoreInAnimationController.value; 280 | extraSize = scoreSizeAnimationController.value * 3; 281 | break; 282 | case ScoreWidgetStatus.BECOMING_INVISIBLE: 283 | scorePosition = scoreOutPositionAnimation.value; 284 | scoreOpacity = 1.0 - scoreOutAnimationController.value; 285 | } 286 | 287 | var stackChildren = []; 288 | 289 | var firstAngle = _sparklesAngle; 290 | var sparkleRadius = (sparklesAnimationController.value * 50); 291 | var sparklesOpacity = (1 - sparklesAnimation.value); 292 | 293 | for (int i = 0; i < 5; ++i) { 294 | var currentAngle = (firstAngle + ((2 * pi) / 5) * (i)); 295 | var sparklesWidget = Positioned( 296 | child: Transform.rotate( 297 | angle: currentAngle - pi / 2, 298 | child: Opacity( 299 | opacity: sparklesOpacity, 300 | child: Image.asset( 301 | "images/sparkles.png", 302 | color: widget.sparkleColor, 303 | width: 14.0, 304 | height: 14.0, 305 | ))), 306 | left: (sparkleRadius * cos(currentAngle)) + 20, 307 | top: (sparkleRadius * sin(currentAngle)) + 20, 308 | ); 309 | stackChildren.add(sparklesWidget); 310 | } 311 | 312 | stackChildren.add(Opacity( 313 | opacity: scoreOpacity, 314 | child: Container( 315 | height: 50.0 + extraSize, 316 | width: 50.0 + extraSize, 317 | decoration: ShapeDecoration( 318 | shape: CircleBorder(side: BorderSide.none), 319 | color: widget.countCircleColor, 320 | ), 321 | child: Center( 322 | child: Text( 323 | "+" + counter.toString(), 324 | style: TextStyle( 325 | color: widget.countTextColor, 326 | fontWeight: FontWeight.bold, 327 | fontSize: 15.0), 328 | ))))); 329 | 330 | var _currentWidget = Positioned( 331 | child: Stack( 332 | alignment: FractionalOffset.center, 333 | overflow: Overflow.visible, 334 | children: stackChildren, 335 | ), 336 | bottom: scorePosition); 337 | return _currentWidget; 338 | } 339 | 340 | @override 341 | Widget build(BuildContext context) { 342 | return Padding( 343 | padding: const EdgeInsets.only(right: 20.0), 344 | child: Stack( 345 | alignment: FractionalOffset.center, 346 | overflow: Overflow.visible, 347 | children: [ 348 | getScoreButton(), 349 | getClapButton(), 350 | ], 351 | ), 352 | ); 353 | } 354 | } 355 | -------------------------------------------------------------------------------- /medium_clap_flutter.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /pubspec.lock: -------------------------------------------------------------------------------- 1 | # Generated by pub 2 | # See https://www.dartlang.org/tools/pub/glossary#lockfile 3 | packages: 4 | analyzer: 5 | dependency: transitive 6 | description: 7 | name: analyzer 8 | url: "https://pub.dartlang.org" 9 | source: hosted 10 | version: "0.31.2-alpha.2" 11 | args: 12 | dependency: transitive 13 | description: 14 | name: args 15 | url: "https://pub.dartlang.org" 16 | source: hosted 17 | version: "1.4.3" 18 | async: 19 | dependency: transitive 20 | description: 21 | name: async 22 | url: "https://pub.dartlang.org" 23 | source: hosted 24 | version: "2.0.7" 25 | boolean_selector: 26 | dependency: transitive 27 | description: 28 | name: boolean_selector 29 | url: "https://pub.dartlang.org" 30 | source: hosted 31 | version: "1.0.3" 32 | charcode: 33 | dependency: transitive 34 | description: 35 | name: charcode 36 | url: "https://pub.dartlang.org" 37 | source: hosted 38 | version: "1.1.1" 39 | collection: 40 | dependency: transitive 41 | description: 42 | name: collection 43 | url: "https://pub.dartlang.org" 44 | source: hosted 45 | version: "1.14.6" 46 | convert: 47 | dependency: transitive 48 | description: 49 | name: convert 50 | url: "https://pub.dartlang.org" 51 | source: hosted 52 | version: "2.0.1" 53 | crypto: 54 | dependency: transitive 55 | description: 56 | name: crypto 57 | url: "https://pub.dartlang.org" 58 | source: hosted 59 | version: "2.0.5" 60 | csslib: 61 | dependency: transitive 62 | description: 63 | name: csslib 64 | url: "https://pub.dartlang.org" 65 | source: hosted 66 | version: "0.14.4" 67 | flutter: 68 | dependency: "direct main" 69 | description: flutter 70 | source: sdk 71 | version: "0.0.0" 72 | flutter_test: 73 | dependency: "direct dev" 74 | description: flutter 75 | source: sdk 76 | version: "0.0.0" 77 | front_end: 78 | dependency: transitive 79 | description: 80 | name: front_end 81 | url: "https://pub.dartlang.org" 82 | source: hosted 83 | version: "0.1.0-alpha.12" 84 | glob: 85 | dependency: transitive 86 | description: 87 | name: glob 88 | url: "https://pub.dartlang.org" 89 | source: hosted 90 | version: "1.1.5" 91 | html: 92 | dependency: transitive 93 | description: 94 | name: html 95 | url: "https://pub.dartlang.org" 96 | source: hosted 97 | version: "0.13.3+1" 98 | http: 99 | dependency: transitive 100 | description: 101 | name: http 102 | url: "https://pub.dartlang.org" 103 | source: hosted 104 | version: "0.11.3+16" 105 | http_multi_server: 106 | dependency: transitive 107 | description: 108 | name: http_multi_server 109 | url: "https://pub.dartlang.org" 110 | source: hosted 111 | version: "2.0.5" 112 | http_parser: 113 | dependency: transitive 114 | description: 115 | name: http_parser 116 | url: "https://pub.dartlang.org" 117 | source: hosted 118 | version: "3.1.2" 119 | io: 120 | dependency: transitive 121 | description: 122 | name: io 123 | url: "https://pub.dartlang.org" 124 | source: hosted 125 | version: "0.3.2+1" 126 | js: 127 | dependency: transitive 128 | description: 129 | name: js 130 | url: "https://pub.dartlang.org" 131 | source: hosted 132 | version: "0.6.1" 133 | json_rpc_2: 134 | dependency: transitive 135 | description: 136 | name: json_rpc_2 137 | url: "https://pub.dartlang.org" 138 | source: hosted 139 | version: "2.0.8" 140 | kernel: 141 | dependency: transitive 142 | description: 143 | name: kernel 144 | url: "https://pub.dartlang.org" 145 | source: hosted 146 | version: "0.3.0-alpha.12" 147 | logging: 148 | dependency: transitive 149 | description: 150 | name: logging 151 | url: "https://pub.dartlang.org" 152 | source: hosted 153 | version: "0.11.3+1" 154 | matcher: 155 | dependency: transitive 156 | description: 157 | name: matcher 158 | url: "https://pub.dartlang.org" 159 | source: hosted 160 | version: "0.12.2" 161 | meta: 162 | dependency: transitive 163 | description: 164 | name: meta 165 | url: "https://pub.dartlang.org" 166 | source: hosted 167 | version: "1.1.5" 168 | mime: 169 | dependency: transitive 170 | description: 171 | name: mime 172 | url: "https://pub.dartlang.org" 173 | source: hosted 174 | version: "0.9.6+1" 175 | multi_server_socket: 176 | dependency: transitive 177 | description: 178 | name: multi_server_socket 179 | url: "https://pub.dartlang.org" 180 | source: hosted 181 | version: "1.0.1" 182 | node_preamble: 183 | dependency: transitive 184 | description: 185 | name: node_preamble 186 | url: "https://pub.dartlang.org" 187 | source: hosted 188 | version: "1.4.2" 189 | package_config: 190 | dependency: transitive 191 | description: 192 | name: package_config 193 | url: "https://pub.dartlang.org" 194 | source: hosted 195 | version: "1.0.3" 196 | package_resolver: 197 | dependency: transitive 198 | description: 199 | name: package_resolver 200 | url: "https://pub.dartlang.org" 201 | source: hosted 202 | version: "1.0.3" 203 | path: 204 | dependency: transitive 205 | description: 206 | name: path 207 | url: "https://pub.dartlang.org" 208 | source: hosted 209 | version: "1.6.1" 210 | plugin: 211 | dependency: transitive 212 | description: 213 | name: plugin 214 | url: "https://pub.dartlang.org" 215 | source: hosted 216 | version: "0.2.0+2" 217 | pool: 218 | dependency: transitive 219 | description: 220 | name: pool 221 | url: "https://pub.dartlang.org" 222 | source: hosted 223 | version: "1.3.5" 224 | pub_semver: 225 | dependency: transitive 226 | description: 227 | name: pub_semver 228 | url: "https://pub.dartlang.org" 229 | source: hosted 230 | version: "1.4.1" 231 | quiver: 232 | dependency: transitive 233 | description: 234 | name: quiver 235 | url: "https://pub.dartlang.org" 236 | source: hosted 237 | version: "0.29.0+1" 238 | shelf: 239 | dependency: transitive 240 | description: 241 | name: shelf 242 | url: "https://pub.dartlang.org" 243 | source: hosted 244 | version: "0.7.3+1" 245 | shelf_packages_handler: 246 | dependency: transitive 247 | description: 248 | name: shelf_packages_handler 249 | url: "https://pub.dartlang.org" 250 | source: hosted 251 | version: "1.0.3" 252 | shelf_static: 253 | dependency: transitive 254 | description: 255 | name: shelf_static 256 | url: "https://pub.dartlang.org" 257 | source: hosted 258 | version: "0.2.7+1" 259 | shelf_web_socket: 260 | dependency: transitive 261 | description: 262 | name: shelf_web_socket 263 | url: "https://pub.dartlang.org" 264 | source: hosted 265 | version: "0.2.2+2" 266 | sky_engine: 267 | dependency: transitive 268 | description: flutter 269 | source: sdk 270 | version: "0.0.99" 271 | source_map_stack_trace: 272 | dependency: transitive 273 | description: 274 | name: source_map_stack_trace 275 | url: "https://pub.dartlang.org" 276 | source: hosted 277 | version: "1.1.4" 278 | source_maps: 279 | dependency: transitive 280 | description: 281 | name: source_maps 282 | url: "https://pub.dartlang.org" 283 | source: hosted 284 | version: "0.10.5" 285 | source_span: 286 | dependency: transitive 287 | description: 288 | name: source_span 289 | url: "https://pub.dartlang.org" 290 | source: hosted 291 | version: "1.4.0" 292 | stack_trace: 293 | dependency: transitive 294 | description: 295 | name: stack_trace 296 | url: "https://pub.dartlang.org" 297 | source: hosted 298 | version: "1.9.2" 299 | stream_channel: 300 | dependency: transitive 301 | description: 302 | name: stream_channel 303 | url: "https://pub.dartlang.org" 304 | source: hosted 305 | version: "1.6.7+1" 306 | string_scanner: 307 | dependency: transitive 308 | description: 309 | name: string_scanner 310 | url: "https://pub.dartlang.org" 311 | source: hosted 312 | version: "1.0.2" 313 | term_glyph: 314 | dependency: transitive 315 | description: 316 | name: term_glyph 317 | url: "https://pub.dartlang.org" 318 | source: hosted 319 | version: "1.0.0" 320 | test: 321 | dependency: transitive 322 | description: 323 | name: test 324 | url: "https://pub.dartlang.org" 325 | source: hosted 326 | version: "0.12.41" 327 | typed_data: 328 | dependency: transitive 329 | description: 330 | name: typed_data 331 | url: "https://pub.dartlang.org" 332 | source: hosted 333 | version: "1.1.5" 334 | utf: 335 | dependency: transitive 336 | description: 337 | name: utf 338 | url: "https://pub.dartlang.org" 339 | source: hosted 340 | version: "0.9.0+4" 341 | vector_math: 342 | dependency: transitive 343 | description: 344 | name: vector_math 345 | url: "https://pub.dartlang.org" 346 | source: hosted 347 | version: "2.0.6" 348 | vm_service_client: 349 | dependency: transitive 350 | description: 351 | name: vm_service_client 352 | url: "https://pub.dartlang.org" 353 | source: hosted 354 | version: "0.2.4+3" 355 | watcher: 356 | dependency: transitive 357 | description: 358 | name: watcher 359 | url: "https://pub.dartlang.org" 360 | source: hosted 361 | version: "0.9.7+8" 362 | web_socket_channel: 363 | dependency: transitive 364 | description: 365 | name: web_socket_channel 366 | url: "https://pub.dartlang.org" 367 | source: hosted 368 | version: "1.0.8" 369 | yaml: 370 | dependency: transitive 371 | description: 372 | name: yaml 373 | url: "https://pub.dartlang.org" 374 | source: hosted 375 | version: "2.1.14" 376 | sdks: 377 | dart: ">=2.0.0-dev.62.0 <=2.0.0-dev.63.0.flutter-4c9689c1d2" 378 | -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: medium_clap_flutter 2 | description: The Medium's Clapping Effect developed in Flutter. 3 | version: 0.1.0 4 | author: Pawan Kumar 5 | homepage: https://github.com/iampawan/MediumClapFlutter 6 | 7 | environment: 8 | sdk: ">=2.0.0-dev.28.0 <3.0.0" 9 | 10 | dependencies: 11 | flutter: 12 | sdk: flutter 13 | 14 | dev_dependencies: 15 | flutter_test: 16 | sdk: flutter 17 | 18 | # For information on the generic Dart part of this file, see the 19 | # following page: https://www.dartlang.org/tools/pub/pubspec 20 | 21 | # The following section is specific to Flutter. 22 | flutter: 23 | 24 | # To add assets to your package, add an assets section, like this: 25 | assets: 26 | - images/sparkles.png 27 | - images/clap.png 28 | # 29 | # For details regarding assets in packages, see 30 | # https://flutter.io/assets-and-images/#from-packages 31 | # 32 | # An image asset can refer to one or more resolution-specific "variants", see 33 | # https://flutter.io/assets-and-images/#resolution-aware. 34 | 35 | # To add custom fonts to your package, add a fonts section here, 36 | # in this "flutter" section. Each entry in this list should have a 37 | # "family" key with the font family name, and a "fonts" key with a 38 | # list giving the asset and other descriptors for the font. For 39 | # example: 40 | # fonts: 41 | # - family: Schyler 42 | # fonts: 43 | # - asset: fonts/Schyler-Regular.ttf 44 | # - asset: fonts/Schyler-Italic.ttf 45 | # style: italic 46 | # - family: Trajan Pro 47 | # fonts: 48 | # - asset: fonts/TrajanPro.ttf 49 | # - asset: fonts/TrajanPro_Bold.ttf 50 | # weight: 700 51 | # 52 | # For details regarding fonts in packages, see 53 | # https://flutter.io/custom-fonts/#from-packages 54 | --------------------------------------------------------------------------------