From 6cd3415720ef2bf0b360d7bde7519e65faeb0d29 Mon Sep 17 00:00:00 2001 From: Plague Fox Date: Tue, 19 Dec 2023 17:53:44 +0400 Subject: [PATCH] Add google_fonts dependency and register PathProviderPlugin --- .../feature/shop/widget/favorite_button.dart | 206 ++++++++++++++---- .../Flutter/GeneratedPluginRegistrant.swift | 2 + example/pubspec.lock | 40 ++++ example/pubspec.yaml | 2 + 4 files changed, 202 insertions(+), 48 deletions(-) diff --git a/example/lib/src/feature/shop/widget/favorite_button.dart b/example/lib/src/feature/shop/widget/favorite_button.dart index 79d2054..90bb500 100644 --- a/example/lib/src/feature/shop/widget/favorite_button.dart +++ b/example/lib/src/feature/shop/widget/favorite_button.dart @@ -8,63 +8,173 @@ import 'package:flutter/services.dart'; /// {@endtemplate} class FavoriteButton extends StatelessWidget { /// {@macro favorite_button} - const FavoriteButton({required this.productId, super.key}); + const FavoriteButton({ + required this.productId, + super.key, + }); final ProductID productId; @override Widget build(BuildContext context) { final status = ShopScope.isFavorite(context, productId, listen: true); - return FloatingActionButton( - onPressed: () { - if (status) { - ShopScope.removeFavorite(context, productId); - HapticFeedback.lightImpact().ignore(); - } else { - ShopScope.addFavorite(context, productId); - HapticFeedback.mediumImpact().ignore(); - } - }, - backgroundColor: status - ? Theme.of(context).buttonTheme.colorScheme?.background - : Theme.of(context).primaryColor, - shape: status - ? RoundedRectangleBorder( - borderRadius: BorderRadius.circular(18), - side: BorderSide( - color: Theme.of(context).buttonTheme.colorScheme?.primary ?? - Colors.transparent, - ), - ) - : RoundedRectangleBorder( - borderRadius: BorderRadius.circular(12), - ), - child: AnimatedSwitcher( - duration: const Duration(milliseconds: 350), - transitionBuilder: (child, animation) => ScaleTransition( - scale: CurvedAnimation( - parent: animation, - curve: Curves.bounceInOut, - ), - child: FadeTransition( - opacity: Tween(begin: 0.5, end: 1).animate(animation), - child: child, - ), - ), - child: status - ? const Icon( - Icons.favorite, - key: ValueKey('favorite'), - color: Colors.red, - size: 36, + return RepaintBoundary( + child: FloatingActionButton( + onPressed: () { + if (status) { + ShopScope.removeFavorite(context, productId); + HapticFeedback.lightImpact().ignore(); + } else { + ShopScope.addFavorite(context, productId); + HapticFeedback.mediumImpact().ignore(); + } + }, + backgroundColor: status + ? Theme.of(context).buttonTheme.colorScheme?.background + : Theme.of(context).primaryColor, + shape: status + ? RoundedRectangleBorder( + borderRadius: BorderRadius.circular(18), + side: BorderSide( + color: Theme.of(context).buttonTheme.colorScheme?.primary ?? + Colors.transparent, + ), ) - : const Icon( - Icons.favorite_border, - key: ValueKey('favorite_border'), - color: Colors.grey, - size: 24, + : RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), ), + child: _FavoriteHeartBeatIcon( + favorite: status, + ), ), ); } } + +class _FavoriteHeartBeatIcon extends StatefulWidget { + const _FavoriteHeartBeatIcon({ + this.favorite = true, + this.duration = const Duration(milliseconds: 650), // ignore: unused_element + super.key, // ignore: unused_element + }); + + /// Is the icon currently filled in? + final bool favorite; + + /// The duration of the animation. + final Duration duration; + + @override + State<_FavoriteHeartBeatIcon> createState() => _FavoriteHeartBeatIconState(); +} + +/// State for widget _FavoriteHeartBeatIcon. +class _FavoriteHeartBeatIconState extends State<_FavoriteHeartBeatIcon> + with SingleTickerProviderStateMixin { + late final AnimationController _controller; + late final Animation _heartbeat1, _heartbeat2; + + @override + void initState() { + super.initState(); + _controller = + AnimationController(vsync: this, duration: widget.duration, value: 0); + _heartbeat1 = CurvedAnimation( + parent: _controller, + curve: const Interval(0, .75, curve: Curves.easeInOut)); + _heartbeat2 = CurvedAnimation( + parent: _controller, + curve: const Interval(.5, 1, curve: Curves.easeInOut)); + if (!widget.favorite) { + _controller.repeat(); + } + } + + @override + void didUpdateWidget(covariant _FavoriteHeartBeatIcon oldWidget) { + super.didUpdateWidget(oldWidget); + if (widget.duration != _controller.duration) { + _controller.duration = widget.duration; + } + if (widget.favorite != oldWidget.favorite) { + if (widget.favorite) { + _controller.stop(); + } else { + _controller.repeat(); + } + } + } + + @override + void dispose() { + _controller.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) => Stack( + alignment: Alignment.center, + children: [ + if (!widget.favorite) + Positioned.fill( + child: FadeTransition( + opacity: ReverseAnimation(_heartbeat1), + child: ScaleTransition( + scale: + Tween(begin: 1, end: 1.75).animate(_heartbeat1), + child: Icon( + Icons.favorite_border, + color: Colors.redAccent.withAlpha(127), + size: 32, + ), + ), + ), + ), + if (!widget.favorite) + Positioned.fill( + child: FadeTransition( + opacity: Tween(begin: 0, end: .75) + .animate(ReverseAnimation(_heartbeat2)), + child: ScaleTransition( + scale: + Tween(begin: 0.8, end: 1.5).animate(_heartbeat2), + child: Icon( + Icons.favorite_border, + color: Colors.red.withAlpha(200), + size: 28, + ), + ), + ), + ), + Positioned.fill( + key: const ValueKey('_FavoriteHeartBeatIconState#icon'), + child: AnimatedSwitcher( + duration: const Duration(milliseconds: 350), + transitionBuilder: (child, animation) => ScaleTransition( + scale: CurvedAnimation( + parent: animation, + curve: Curves.bounceInOut, + ), + child: FadeTransition( + opacity: Tween(begin: 0.5, end: 1).animate(animation), + child: child, + ), + ), + child: widget.favorite + ? const Icon( + Icons.favorite, + key: ValueKey('favorite'), + color: Colors.red, + size: 36, + ) + : Icon( + Icons.favorite_border, + key: const ValueKey('favorite_border'), + color: Colors.grey.withAlpha(200), + size: 24, + ), + ), + ), + ], + ); +} diff --git a/example/macos/Flutter/GeneratedPluginRegistrant.swift b/example/macos/Flutter/GeneratedPluginRegistrant.swift index 724bb2a..b8e2b22 100644 --- a/example/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/example/macos/Flutter/GeneratedPluginRegistrant.swift @@ -5,8 +5,10 @@ import FlutterMacOS import Foundation +import path_provider_foundation import shared_preferences_foundation func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { + PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) } diff --git a/example/pubspec.lock b/example/pubspec.lock index ce1dc26..8b2bd22 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -343,6 +343,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.2" + google_fonts: + dependency: "direct main" + description: + name: google_fonts + sha256: f0b8d115a13ecf827013ec9fc883390ccc0e87a96ed5347a3114cac177ef18e8 + url: "https://pub.dev" + source: hosted + version: "6.1.0" graphs: dependency: transitive description: @@ -359,6 +367,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.15.4" + http: + dependency: transitive + description: + name: http + sha256: d4872660c46d929f6b8a9ef4e7a7eff7e49bbf0c4ec3f385ee32df5119175139 + url: "https://pub.dev" + source: hosted + version: "1.1.2" http_multi_server: dependency: transitive description: @@ -499,6 +515,30 @@ packages: url: "https://pub.dev" source: hosted version: "1.8.3" + path_provider: + dependency: transitive + description: + name: path_provider + sha256: a1aa8aaa2542a6bc57e381f132af822420216c80d4781f7aa085ca3229208aaa + url: "https://pub.dev" + source: hosted + version: "2.1.1" + path_provider_android: + dependency: transitive + description: + name: path_provider_android + sha256: e595b98692943b4881b219f0a9e3945118d3c16bd7e2813f98ec6e532d905f72 + url: "https://pub.dev" + source: hosted + version: "2.2.1" + path_provider_foundation: + dependency: transitive + description: + name: path_provider_foundation + sha256: "19314d595120f82aca0ba62787d58dde2cc6b5df7d2f0daf72489e38d1b57f2d" + url: "https://pub.dev" + source: hosted + version: "2.3.1" path_provider_linux: dependency: transitive description: diff --git a/example/pubspec.yaml b/example/pubspec.yaml index b79e77b..e9ac606 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -68,6 +68,8 @@ dependencies: # UI and Widgets cupertino_icons: ^1.0.5 photo_view: ^0.14.0 + google_fonts: ^6.1.0 + #font_awesome_flutter: ^10.6.0 dev_dependencies: # Unit & Widget tests for Flutter