diff --git a/example/lib/alarm_app.dart b/example/lib/alarm_app.dart index 80e3322..7f29f6f 100644 --- a/example/lib/alarm_app.dart +++ b/example/lib/alarm_app.dart @@ -17,18 +17,28 @@ class _AlarmAppState extends State { @override Widget build(BuildContext context) { return badges.Badge( - badgeStyle: badges.BadgeStyle(padding: EdgeInsets.all(7)), + badgeStyle: badges.BadgeStyle( + padding: EdgeInsets.zero, + borderSide: BorderSide(color: Colors.white, width: 2), + shape: badges.BadgeShape.triangle, + badgeGradient: badges.BadgeGradient.linear( + colors: [ + Colors.red, + Colors.orange, + ], + begin: Alignment.topLeft, + end: Alignment.bottomRight, + ), + ), badgeAnimation: badges.BadgeAnimation.fade( animationDuration: Duration(seconds: 1), loopAnimation: _isLooped, ), - // onTap: () { - // setState(() => _isLooped = !_isLooped); - // }, ignorePointer: false, - // toAnimate: false, - badgeContent: - Text(counter.toString(), style: TextStyle(color: Colors.white)), + badgeContent: Text( + '!', + style: TextStyle(color: Colors.white), + ), position: badges.BadgePosition.topEnd(top: -12), child: GestureDetector( onTap: () { diff --git a/lib/src/badge.dart b/lib/src/badge.dart index 7a13e8b..ae69536 100644 --- a/lib/src/badge.dart +++ b/lib/src/badge.dart @@ -3,6 +3,7 @@ import 'package:badges/src/badge_border_gradient.dart'; import 'package:badges/src/utils/calculation_utils.dart'; import 'package:badges/src/utils/drawing_utils.dart'; import 'package:flutter/material.dart'; +import 'package:flutter/scheduler.dart'; class Badge extends StatefulWidget { const Badge({ @@ -62,10 +63,15 @@ class BadgeState extends State with TickerProviderStateMixin { late AnimationController _appearanceController; late Animation _animation; bool enableLoopAnimation = false; + double? textSize; + final GlobalKey _key = GlobalKey(); + double? _widgetSize; @override void initState() { super.initState(); + SchedulerBinding.instance + .addPostFrameCallback((_) => scaleWidgetSize(_key, badge: widget)); enableLoopAnimation = widget.badgeAnimation.animationDuration.inMilliseconds > 0; _animationController = AnimationController( @@ -97,6 +103,30 @@ class BadgeState extends State with TickerProviderStateMixin { } } + void scaleWidgetSize(GlobalKey key, {required Badge badge, Badge? oldBadge}) { + double newSize = 0; + + if (badge.badgeContent is Text) { + final newText = badge.badgeContent as Text; + final size = + CalculationUtils.calculateSizeOfText(newText.data!, newText.style); + newSize = size.width >= size.height + ? size.width * 1.1764 + : size.height * 1.1764; + } else if (badge.badgeContent is Icon) { + newSize = (badge.badgeContent as Icon).size ?? 0; + } else { + final RenderBox? childBox = + _key.currentContext?.findRenderObject() as RenderBox?; + if (childBox != null) { + Size size = childBox.size; + newSize = size.height >= size.width ? size.height : size.width; + } + } + newSize *= badge.badgeStyle.shape == BadgeShape.triangle ? 1.7 : 1; + setState(() => _widgetSize = newSize); + } + @override Widget build(BuildContext context) { if (widget.child == null) { @@ -113,7 +143,8 @@ class BadgeState extends State with TickerProviderStateMixin { widget.onTap == null ? widget.child! : Padding( - padding: CalculationUtils.calculatePadding(widget.position), + padding: CalculationUtils.calculatePaddingByPosition( + widget.position), child: widget.child!, ), BadgePositioned( @@ -157,7 +188,9 @@ class BadgeState extends State with TickerProviderStateMixin { borderRadius: widget.badgeStyle.borderRadius, ); final isCustomShape = widget.badgeStyle.shape == BadgeShape.twitter || - widget.badgeStyle.shape == BadgeShape.instagram; + widget.badgeStyle.shape == BadgeShape.instagram || + widget.badgeStyle.shape == BadgeShape.triangle; + final isSquareShape = widget.badgeStyle.shape == BadgeShape.square; final gradientBorder = widget.badgeStyle.borderGradient != null ? BadgeBorderGradient( @@ -183,8 +216,18 @@ class BadgeState extends State with TickerProviderStateMixin { borderSide: widget.badgeStyle.borderSide, ), child: Padding( - padding: widget.badgeStyle.padding, - child: widget.badgeContent, + padding: CalculationUtils.calculateBadgeContentPadding( + widget.badgeContent, + widget.badgeStyle, + ), + child: SizedBox( + width: _widgetSize, + height: _widgetSize, + child: Center( + key: _key, + child: widget.badgeContent, + ), + ), ), ) : Material( @@ -214,8 +257,18 @@ class BadgeState extends State with TickerProviderStateMixin { border: gradientBorder, ), child: Padding( - padding: widget.badgeStyle.padding, - child: widget.badgeContent, + padding: CalculationUtils.calculateBadgeContentPadding( + widget.badgeContent, + widget.badgeStyle, + ), + child: SizedBox( + width: _widgetSize, + height: isSquareShape ? null : _widgetSize, + child: Center( + key: _key, + child: widget.badgeContent, + ), + ), ), ), ), @@ -261,6 +314,8 @@ class BadgeState extends State with TickerProviderStateMixin { @override void didUpdateWidget(Badge oldWidget) { super.didUpdateWidget(oldWidget); + SchedulerBinding.instance.addPostFrameCallback( + (_) => scaleWidgetSize(_key, badge: widget, oldBadge: oldWidget)); if (widget.badgeAnimation.toAnimate) { if (widget.badgeStyle.badgeColor != oldWidget.badgeStyle.badgeColor && widget.showBadge) { diff --git a/lib/src/badge_shape.dart b/lib/src/badge_shape.dart index 4788701..3aacf91 100644 --- a/lib/src/badge_shape.dart +++ b/lib/src/badge_shape.dart @@ -1,4 +1,5 @@ import 'package:badges/badges.dart' as badges; +import 'package:badges/src/painters/triangle_badge_shape_painter.dart'; import 'package:flutter/material.dart'; /// Set of shapes that you can use for your [badges.Badge] widget. @@ -15,6 +16,10 @@ enum BadgeShape { /// * [RoundedRectangleBorder] square, + /// To make the triangle badge . + /// See [TriangleBadgeShapePainter] for more details. + triangle, + /// To make the twitter badge . /// See [TwitterBadgeShapePainter] for more details. twitter, diff --git a/lib/src/badge_style.dart b/lib/src/badge_style.dart index 55486aa..1aad24c 100644 --- a/lib/src/badge_style.dart +++ b/lib/src/badge_style.dart @@ -31,7 +31,7 @@ class BadgeStyle { /// Specifies padding for [badgeContent]. /// The default value is EdgeInsets.all(5.0). - final EdgeInsetsGeometry padding; + final EdgeInsetsGeometry? padding; const BadgeStyle({ this.shape = BadgeShape.circle, @@ -41,6 +41,6 @@ class BadgeStyle { this.elevation = 2, this.badgeGradient, this.borderGradient, - this.padding = const EdgeInsets.all(5.0), + this.padding, }); } diff --git a/lib/src/painters/instagram_badge_shape_painter.dart b/lib/src/painters/instagram_badge_shape_painter.dart index 51560fa..65a16db 100644 --- a/lib/src/painters/instagram_badge_shape_painter.dart +++ b/lib/src/painters/instagram_badge_shape_painter.dart @@ -1,3 +1,5 @@ +import 'dart:math' as math; + import 'package:badges/badges.dart'; import 'package:badges/src/utils/gradient_utils.dart'; import 'package:flutter/material.dart'; @@ -21,6 +23,10 @@ class InstagramBadgeShapePainter extends CustomPainter { final width = size.width; final height = size.height; + final double maxSize = math.max(width, height); + + canvas.clipRect(Offset.zero & Size(maxSize, maxSize)); + Path path = Path(); Paint paint = Paint(); Paint paintBorder = Paint(); @@ -28,8 +34,8 @@ class InstagramBadgeShapePainter extends CustomPainter { if (badgeGradient != null) { paint.shader = GradientUtils.getGradientShader( badgeGradient: badgeGradient!, - width: width, - height: height, + width: maxSize, + height: maxSize, ); } paintBorder @@ -41,36 +47,36 @@ class InstagramBadgeShapePainter extends CustomPainter { if (borderGradient != null) { paintBorder.shader = GradientUtils.getGradientShader( badgeGradient: borderGradient!, - width: width, - height: height, + width: maxSize, + height: maxSize, ); } - path.moveTo(width * 0.14, height * 0.14); - path.lineTo(width * 0.3, height * 0.14); - path.lineTo(width * 0.385, 0); - path.lineTo(width * 0.515, height * 0.08); - path.lineTo(width * 0.627, height * 0.012); - path.lineTo(width * 0.7, height * 0.134); - path.lineTo(width * 0.867, height * 0.134); - path.lineTo(width * 0.867, height * 0.3); - path.lineTo(width, height * 0.38); - path.lineTo(width * 0.922, height * 0.505); - path.lineTo(width * 0.995, height * 0.629); - path.lineTo(width * 0.866, height * 0.706); - path.lineTo(width * 0.866, height * 0.868); - path.lineTo(width * 0.697, height * 0.868); - path.lineTo(width * 0.618, height * 0.996); - path.lineTo(width * 0.5, height * 0.924); - path.lineTo(width * 0.379, height * 0.996); - path.lineTo(width * 0.302, height * 0.868); - path.lineTo(width * 0.14, height * 0.868); - path.lineTo(width * 0.14, height * 0.702); - path.lineTo(width * 0.004, height * 0.618); - path.lineTo(width * 0.08, height * 0.494); - path.lineTo(width * 0.012, height * 0.379); - path.lineTo(width * 0.14, height * 0.306); - path.lineTo(width * 0.14, height * 0.14); + path.moveTo(maxSize * 0.14, maxSize * 0.14); + path.lineTo(maxSize * 0.3, maxSize * 0.14); + path.lineTo(maxSize * 0.385, 0); + path.lineTo(maxSize * 0.515, maxSize * 0.08); + path.lineTo(maxSize * 0.627, maxSize * 0.012); + path.lineTo(maxSize * 0.7, maxSize * 0.134); + path.lineTo(maxSize * 0.867, maxSize * 0.134); + path.lineTo(maxSize * 0.867, maxSize * 0.3); + path.lineTo(maxSize, maxSize * 0.38); + path.lineTo(maxSize * 0.922, maxSize * 0.505); + path.lineTo(maxSize * 0.995, maxSize * 0.629); + path.lineTo(maxSize * 0.866, maxSize * 0.706); + path.lineTo(maxSize * 0.866, maxSize * 0.868); + path.lineTo(maxSize * 0.697, maxSize * 0.868); + path.lineTo(maxSize * 0.618, maxSize * 0.996); + path.lineTo(maxSize * 0.5, maxSize * 0.924); + path.lineTo(maxSize * 0.379, maxSize * 0.996); + path.lineTo(maxSize * 0.302, maxSize * 0.868); + path.lineTo(maxSize * 0.14, maxSize * 0.868); + path.lineTo(maxSize * 0.14, maxSize * 0.702); + path.lineTo(maxSize * 0.004, maxSize * 0.618); + path.lineTo(maxSize * 0.08, maxSize * 0.494); + path.lineTo(maxSize * 0.012, maxSize * 0.379); + path.lineTo(maxSize * 0.14, maxSize * 0.306); + path.lineTo(maxSize * 0.14, maxSize * 0.14); paint.color = color!; canvas.drawPath(path, paint); diff --git a/lib/src/painters/triangle_badge_shape_painter.dart b/lib/src/painters/triangle_badge_shape_painter.dart new file mode 100644 index 0000000..37ce8bb --- /dev/null +++ b/lib/src/painters/triangle_badge_shape_painter.dart @@ -0,0 +1,78 @@ +import 'dart:math' as math; + +import 'package:badges/badges.dart'; +import 'package:badges/src/utils/gradient_utils.dart'; +import 'package:flutter/material.dart'; + +class TriangleBadgeShapePainter extends CustomPainter { + Color? color; + BadgeGradient? badgeGradient; + BadgeGradient? borderGradient; + BorderSide? borderSide; + + TriangleBadgeShapePainter({ + Key? key, + this.color = Colors.blue, + this.badgeGradient, + this.borderGradient, + this.borderSide, + }); + + @override + void paint(Canvas canvas, Size size) { + final width = size.width; + final height = size.height; + + final double maxSize = math.max(width, height); + + canvas.clipRect(Offset.zero & Size(maxSize, maxSize)); + + Path path = Path(); + Paint paint = Paint(); + Paint paintBorder = Paint(); + + if (badgeGradient != null) { + paint.shader = GradientUtils.getGradientShader( + badgeGradient: badgeGradient!, + width: maxSize, + height: maxSize, + ); + } + paintBorder + ..color = borderSide?.color ?? Colors.white + ..style = PaintingStyle.stroke + ..strokeCap = StrokeCap.round + ..strokeWidth = borderSide?.width ?? 0; + + if (borderGradient != null) { + paintBorder.shader = GradientUtils.getGradientShader( + badgeGradient: borderGradient!, + width: maxSize, + height: maxSize, + ); + } + path + ..moveTo(maxSize * 0.132, maxSize * 0.888) + ..arcToPoint(Offset(maxSize * 0.075, maxSize * 0.772), + radius: Radius.circular(maxSize * 0.09)) + ..lineTo(maxSize * 0.428, maxSize * 0.156) + ..arcToPoint(Offset(maxSize * 0.582, maxSize * 0.156), + radius: Radius.circular(maxSize * 0.09)) + ..lineTo(maxSize * 0.928, maxSize * 0.756) + ..arcToPoint(Offset(maxSize * 0.868, maxSize * 0.888), + radius: Radius.circular(maxSize * 0.09)) + ..lineTo(maxSize * 0.132, maxSize * 0.888); + path.close(); + + paint.color = color!; + canvas.drawPath(path, paint); + if (borderSide != BorderSide.none) { + canvas.drawPath(path, paintBorder); + } + } + + @override + bool shouldRepaint(covariant CustomPainter oldDelegate) { + return true; + } +} diff --git a/lib/src/painters/twitter_badge_shape_painter.dart b/lib/src/painters/twitter_badge_shape_painter.dart index 2b02642..1b05422 100644 --- a/lib/src/painters/twitter_badge_shape_painter.dart +++ b/lib/src/painters/twitter_badge_shape_painter.dart @@ -1,3 +1,5 @@ +import 'dart:math' as math; + import 'package:badges/src/badge_gradient.dart'; import 'package:badges/src/utils/gradient_utils.dart'; import 'package:flutter/material.dart'; @@ -21,6 +23,10 @@ class TwitterBadgeShapePainter extends CustomPainter { final width = size.width; final height = size.height; + final double maxSize = math.max(width, height); + + canvas.clipRect(Offset.zero & Size(maxSize, maxSize)); + Path path = Path(); Paint paint = Paint(); Paint paintBorder = Paint(); @@ -28,8 +34,8 @@ class TwitterBadgeShapePainter extends CustomPainter { if (badgeGradient != null) { paint.shader = GradientUtils.getGradientShader( badgeGradient: badgeGradient!, - width: width, - height: height, + width: maxSize, + height: maxSize, ); } paintBorder @@ -41,28 +47,28 @@ class TwitterBadgeShapePainter extends CustomPainter { if (borderGradient != null) { paintBorder.shader = GradientUtils.getGradientShader( badgeGradient: borderGradient!, - width: width, - height: height, + width: maxSize, + height: maxSize, ); } - path.moveTo(width * 0.357, height * 0.156); - path.arcToPoint(Offset(width * 0.643, height * 0.156), - radius: Radius.circular(height * 0.157)); - path.arcToPoint(Offset(width * 0.847, height * 0.396), - radius: Radius.circular(height * 0.165)); - path.arcToPoint(Offset(width * 0.857, height * 0.666), - radius: Radius.circular(height * 0.170)); - path.arcToPoint(Offset(width * 0.643, height * 0.844), - radius: Radius.circular(height * 0.163)); - path.arcToPoint(Offset(width * 0.357, height * 0.844), - radius: Radius.circular(height * 0.157)); - path.arcToPoint(Offset(width * 0.145, height * 0.665), - radius: Radius.circular(height * 0.163)); - path.arcToPoint(Offset(width * 0.154, height * 0.372), - radius: Radius.circular(height * 0.170)); - path.arcToPoint(Offset(width * 0.357, height * 0.156), - radius: Radius.circular(height * 0.163)); + path.moveTo(maxSize * 0.357, maxSize * 0.156); + path.arcToPoint(Offset(maxSize * 0.643, maxSize * 0.156), + radius: Radius.circular(maxSize * 0.157)); + path.arcToPoint(Offset(maxSize * 0.847, maxSize * 0.396), + radius: Radius.circular(maxSize * 0.165)); + path.arcToPoint(Offset(maxSize * 0.857, maxSize * 0.666), + radius: Radius.circular(maxSize * 0.170)); + path.arcToPoint(Offset(maxSize * 0.643, maxSize * 0.844), + radius: Radius.circular(maxSize * 0.163)); + path.arcToPoint(Offset(maxSize * 0.357, maxSize * 0.844), + radius: Radius.circular(maxSize * 0.157)); + path.arcToPoint(Offset(maxSize * 0.145, maxSize * 0.665), + radius: Radius.circular(maxSize * 0.163)); + path.arcToPoint(Offset(maxSize * 0.154, maxSize * 0.372), + radius: Radius.circular(maxSize * 0.170)); + path.arcToPoint(Offset(maxSize * 0.357, maxSize * 0.156), + radius: Radius.circular(maxSize * 0.163)); paint.color = color!; canvas.drawPath(path, paint); diff --git a/lib/src/utils/calculation_utils.dart b/lib/src/utils/calculation_utils.dart index b47f259..1e67604 100644 --- a/lib/src/utils/calculation_utils.dart +++ b/lib/src/utils/calculation_utils.dart @@ -1,3 +1,5 @@ +import 'dart:math' as math; + import 'package:badges/badges.dart'; import 'package:flutter/material.dart'; @@ -26,7 +28,7 @@ class CalculationUtils { /// When the onTap is specified, we need to add some padding /// to make the full badge tappable. - static EdgeInsets calculatePadding(BadgePosition? position) { + static EdgeInsets calculatePaddingByPosition(BadgePosition? position) { if (position == null) { return const EdgeInsets.only(top: 8, right: 10); } @@ -81,4 +83,40 @@ class CalculationUtils { } return Offset(width, height); } + + static Size calculateSizeOfText(String text, TextStyle? style) { + final TextPainter textPainter = TextPainter( + text: TextSpan(text: text, style: style), + maxLines: 1, + textDirection: TextDirection.ltr) + ..layout(minWidth: 0, maxWidth: double.infinity); + return textPainter.size; + } + + static EdgeInsetsGeometry calculateBadgeContentPadding( + Widget? badgeContent, + BadgeStyle style, + ) { + final isTextContent = badgeContent is Text; + final padding = style.padding as EdgeInsets?; + + final isNotCustomShape = + style.shape == BadgeShape.circle || style.shape == BadgeShape.square; + + if (isTextContent && isNotCustomShape) { + return padding ?? EdgeInsets.zero; + } else if (!isNotCustomShape) { + if (padding == null) return const EdgeInsets.all(5); + final top = padding.top; + final bottom = padding.bottom; + final left = padding.left; + final right = padding.right; + final horizontalMax = math.max(left, right); + final verticalMax = math.max(top, bottom); + final maxPadding = math.max(horizontalMax, verticalMax); + + return EdgeInsets.all(maxPadding); + } + return padding ?? const EdgeInsets.all(5); + } } diff --git a/lib/src/utils/drawing_utils.dart b/lib/src/utils/drawing_utils.dart index a896794..fa051af 100644 --- a/lib/src/utils/drawing_utils.dart +++ b/lib/src/utils/drawing_utils.dart @@ -1,5 +1,6 @@ import 'package:badges/badges.dart'; import 'package:badges/src/painters/instagram_badge_shape_painter.dart'; +import 'package:badges/src/painters/triangle_badge_shape_painter.dart'; import 'package:badges/src/painters/twitter_badge_shape_painter.dart'; import 'package:flutter/material.dart'; @@ -26,6 +27,13 @@ class DrawingUtils { borderSide: borderSide, borderGradient: borderGradient, ); + case BadgeShape.triangle: + return TriangleBadgeShapePainter( + color: color, + badgeGradient: badgeGradient, + borderSide: borderSide, + borderGradient: borderGradient, + ); case BadgeShape.square: case BadgeShape.circle: break; diff --git a/test/badges_test.dart b/test/badges_test.dart index fbf6bbd..6102f9d 100644 --- a/test/badges_test.dart +++ b/test/badges_test.dart @@ -2,6 +2,7 @@ import 'package:badges/badges.dart' as badges; import 'package:badges/src/badge_border_gradient.dart'; import 'package:badges/src/badge_gradient_type.dart'; import 'package:badges/src/painters/instagram_badge_shape_painter.dart'; +import 'package:badges/src/painters/triangle_badge_shape_painter.dart'; import 'package:badges/src/painters/twitter_badge_shape_painter.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; @@ -334,6 +335,76 @@ void main() { expect(painter.shouldRepaint(painter), true); }); }); + + group('Triangle shape', () { + const triangleBadge = badges.Badge( + badgeStyle: badges.BadgeStyle( + shape: badges.BadgeShape.triangle, + badgeColor: Colors.green, + badgeGradient: + badges.BadgeGradient.radial(colors: [Colors.black, Colors.green]), + borderGradient: + badges.BadgeGradient.linear(colors: [Colors.red, Colors.yellow]), + borderSide: BorderSide(width: 2), + ), + ); + + testWidgets('Triangle badge should render correctly', (tester) async { + await tester.pumpWidget(_wrapWithMaterialApp(triangleBadge)); + expect(find.byType(badges.Badge), findsOneWidget); + expect(find.byType(CustomPaint), findsWidgets); + }); + + testWidgets('Triangle badge color should match', (tester) async { + await tester.pumpWidget(_wrapWithMaterialApp(triangleBadge)); + + final customPaint = + tester.widgetList(find.byType(CustomPaint)).last; + final painter = customPaint.painter as TriangleBadgeShapePainter; + expect(painter.color, Colors.green); + }); + + testWidgets('Triangle badge gradient should match', (tester) async { + await tester.pumpWidget(_wrapWithMaterialApp(triangleBadge)); + final customPaint = + tester.widgetList(find.byType(CustomPaint)).last; + final painter = customPaint.painter as TriangleBadgeShapePainter; + expect(painter.badgeGradient?.gradientType, BadgeGradientType.radial); + expect(painter.badgeGradient?.colors.first, Colors.black); + expect(painter.badgeGradient?.colors.last, Colors.green); + expect(painter.badgeGradient?.colors.length, 2); + }); + + testWidgets('Triangle badge border gradient should match', + (tester) async { + await tester.pumpWidget(_wrapWithMaterialApp(triangleBadge)); + final customPaint = + tester.widgetList(find.byType(CustomPaint)).last; + final painter = customPaint.painter as TriangleBadgeShapePainter; + expect(painter.borderGradient?.gradientType, BadgeGradientType.linear); + expect(painter.borderGradient?.colors.first, Colors.red); + expect(painter.borderGradient?.colors.last, Colors.yellow); + expect(painter.borderGradient?.colors.length, 2); + }); + + testWidgets('Triangle badge border should match', (tester) async { + await tester.pumpWidget(_wrapWithMaterialApp(triangleBadge)); + final customPaint = + tester.widgetList(find.byType(CustomPaint)).last; + final painter = customPaint.painter as TriangleBadgeShapePainter; + expect(painter.borderSide?.width, 2); + expect(painter.borderSide?.style, BorderStyle.solid); + expect(painter.borderSide?.strokeAlign, BorderSide.strokeAlignInside); + }); + + testWidgets('Triangle badge repaint should match', (tester) async { + await tester.pumpWidget(_wrapWithMaterialApp(triangleBadge)); + final customPaint = + tester.widgetList(find.byType(CustomPaint)).last; + final painter = customPaint.painter as TriangleBadgeShapePainter; + expect(painter.shouldRepaint(painter), true); + }); + }); }); group('Badge tests', () { @@ -465,7 +536,7 @@ void main() { expect(badgeWidget.badgeStyle.elevation, 2); expect(badgeWidget.badgeStyle.badgeGradient, null); expect(badgeWidget.badgeStyle.borderGradient, null); - expect(badgeWidget.badgeStyle.padding, const EdgeInsets.all(5.0)); + expect(badgeWidget.badgeStyle.padding, null); // Animation expect(badgeWidget.badgeAnimation.toAnimate, true); diff --git a/test/utils_tests.dart b/test/utils_tests.dart index 9ad8e98..cdf7440 100644 --- a/test/utils_tests.dart +++ b/test/utils_tests.dart @@ -1,4 +1,4 @@ -import 'package:badges/badges.dart'; +import 'package:badges/badges.dart' as badges; import 'package:badges/src/painters/instagram_badge_shape_painter.dart'; import 'package:badges/src/painters/twitter_badge_shape_painter.dart'; import 'package:badges/src/utils/calculation_utils.dart'; @@ -9,7 +9,8 @@ import 'package:flutter_test/flutter_test.dart'; void testUtils() { group('CalculationUtils', () { test('Passing null', () async { - final BadgePosition position = CalculationUtils.calculatePosition(null); + final badges.BadgePosition position = + CalculationUtils.calculatePosition(null); expect(position.top, 0); expect(position.end, 0); expect(position.start, null); @@ -19,7 +20,8 @@ void testUtils() { test('Null values', () async { final position = CalculationUtils.calculatePosition( - BadgePosition.custom(top: null, end: null, bottom: null, start: null), + badges.BadgePosition.custom( + top: null, end: null, bottom: null, start: null), ); expect(position.top, null); expect(position.end, null); @@ -30,7 +32,8 @@ void testUtils() { test('Negative values', () async { final position = CalculationUtils.calculatePosition( - BadgePosition.custom(top: -10, end: -10, bottom: -10, start: -10)); + badges.BadgePosition.custom( + top: -10, end: -10, bottom: -10, start: -10)); expect(position.top, 0); expect(position.end, 0); expect(position.bottom, 0); @@ -40,7 +43,7 @@ void testUtils() { test('Normal values', () async { final position = CalculationUtils.calculatePosition( - BadgePosition.custom(top: 15, end: 15, bottom: 15, start: 15), + badges.BadgePosition.custom(top: 15, end: 15, bottom: 15, start: 15), ); expect(position.top, 15); expect(position.end, 15); @@ -51,7 +54,7 @@ void testUtils() { group('CalculationUtils.calculatePadding', () { test('Passing null', () async { - final padding = CalculationUtils.calculatePadding(null); + final padding = CalculationUtils.calculatePaddingByPosition(null); expect(padding.top, 8); expect(padding.right, 10); expect(padding.bottom, 0); @@ -59,8 +62,8 @@ void testUtils() { }); test('isCenter = true', () async { - final padding = CalculationUtils.calculatePadding( - BadgePosition.custom(isCenter: true, top: -10, end: 20), + final padding = CalculationUtils.calculatePaddingByPosition( + badges.BadgePosition.custom(isCenter: true, top: -10, end: 20), ); expect(padding.top, 0); expect(padding.right, 0); @@ -69,8 +72,9 @@ void testUtils() { }); test('Null values', () async { - final padding = CalculationUtils.calculatePadding( - BadgePosition.custom(top: null, end: null, bottom: null, start: null), + final padding = CalculationUtils.calculatePaddingByPosition( + badges.BadgePosition.custom( + top: null, end: null, bottom: null, start: null), ); expect(padding.top, 0); expect(padding.left, 0); @@ -79,8 +83,8 @@ void testUtils() { }); test('Top and start values', () async { - final padding = CalculationUtils.calculatePadding( - BadgePosition.custom(top: -5, end: -5, bottom: -5, start: -5), + final padding = CalculationUtils.calculatePaddingByPosition( + badges.BadgePosition.custom(top: -5, end: -5, bottom: -5, start: -5), ); expect(padding.top, 5); expect(padding.left, 5); @@ -90,8 +94,8 @@ void testUtils() { test('Without top and start values and negative end bottom values', () async { - final padding = CalculationUtils.calculatePadding( - BadgePosition.custom(end: -5, bottom: -5), + final padding = CalculationUtils.calculatePaddingByPosition( + badges.BadgePosition.custom(end: -5, bottom: -5), ); expect(padding.top, 0); expect(padding.left, 0); @@ -100,8 +104,8 @@ void testUtils() { }); test('Without top and start values and normal end bottom values', () async { - final padding = CalculationUtils.calculatePadding( - BadgePosition.custom(end: 5, bottom: 5), + final padding = CalculationUtils.calculatePaddingByPosition( + badges.BadgePosition.custom(end: 5, bottom: 5), ); expect(padding.top, 0); expect(padding.left, 0); @@ -180,26 +184,149 @@ void testUtils() { group('DrawingUtils.drawBadgeShape', () { test('Instagram badge shape painter should match', () async { final getCustomPainter = - DrawingUtils.drawBadgeShape(shape: BadgeShape.instagram); + DrawingUtils.drawBadgeShape(shape: badges.BadgeShape.instagram); expect(getCustomPainter.runtimeType, InstagramBadgeShapePainter); }); test('Twitter badge shape painter should match', () async { final getCustomPainter = - DrawingUtils.drawBadgeShape(shape: BadgeShape.twitter); + DrawingUtils.drawBadgeShape(shape: badges.BadgeShape.twitter); expect(getCustomPainter.runtimeType, TwitterBadgeShapePainter); }); test('Circle badge shape painter should be null', () async { final getCustomPainter = - DrawingUtils.drawBadgeShape(shape: BadgeShape.circle); + DrawingUtils.drawBadgeShape(shape: badges.BadgeShape.circle); expect(getCustomPainter, null); }); test('Square badge shape painter should be null', () async { final getCustomPainter = - DrawingUtils.drawBadgeShape(shape: BadgeShape.square); + DrawingUtils.drawBadgeShape(shape: badges.BadgeShape.square); expect(getCustomPainter, null); }); }); + + group('Text size calculation', () { + const text = 'H'; + const textStyle = TextStyle(fontSize: 16, fontWeight: FontWeight.bold); + + test('Returns correct size for custom parameters', () { + final size = CalculationUtils.calculateSizeOfText(text, textStyle); + expect(size.width, 16); + expect(size.height, 16); + }); + + test('Returns correct size for empty text', () { + final size = CalculationUtils.calculateSizeOfText('', textStyle); + expect(size.width, 0); + expect(size.height, 16); + }); + + test('Returns correct size for null style', () { + final size = CalculationUtils.calculateSizeOfText(text, null); + expect(size.width, 14); + expect(size.height, 14); + }); + }); + + group('Content padding calculation', () { + test('Padding in custom badge shape with text and null padding', () async { + const badge = badges.Badge( + badgeContent: Text('!'), + badgeStyle: badges.BadgeStyle(shape: badges.BadgeShape.triangle), + ); + final edgeInsets = CalculationUtils.calculateBadgeContentPadding( + badge.badgeContent, + badge.badgeStyle, + ) as EdgeInsets; + expect(edgeInsets.top, 5); + expect(edgeInsets.bottom, 5); + expect(edgeInsets.left, 5); + expect(edgeInsets.right, 5); + }); + test('Padding in custom badge shape with text and padding value', () async { + const badge = badges.Badge( + badgeContent: Icon(Icons.check, size: 10), + badgeStyle: badges.BadgeStyle( + shape: badges.BadgeShape.triangle, + padding: EdgeInsets.only(left: 2, right: 4, top: 6, bottom: 8)), + ); + final edgeInsets = CalculationUtils.calculateBadgeContentPadding( + badge.badgeContent, + badge.badgeStyle, + ) as EdgeInsets; + expect(edgeInsets.top, 8); + expect(edgeInsets.bottom, 8); + expect(edgeInsets.left, 8); + expect(edgeInsets.right, 8); + }); + + test('Padding in default badge shape with text and null padding', () async { + const badge = badges.Badge( + badgeContent: Text('H'), + badgeStyle: badges.BadgeStyle(shape: badges.BadgeShape.circle), + ); + final edgeInsets = CalculationUtils.calculateBadgeContentPadding( + badge.badgeContent, + badge.badgeStyle, + ) as EdgeInsets; + expect(edgeInsets.top, 0); + expect(edgeInsets.bottom, 0); + expect(edgeInsets.left, 0); + expect(edgeInsets.right, 0); + }); + + test('Padding in default badge shape with text and padding value', + () async { + const badge = badges.Badge( + badgeContent: Text('H'), + badgeStyle: badges.BadgeStyle( + shape: badges.BadgeShape.circle, + padding: EdgeInsets.only(left: 1, right: 2, top: 3, bottom: 4)), + ); + final edgeInsets = CalculationUtils.calculateBadgeContentPadding( + badge.badgeContent, + badge.badgeStyle, + ) as EdgeInsets; + expect(edgeInsets.top, 3); + expect(edgeInsets.bottom, 4); + expect(edgeInsets.left, 1); + expect(edgeInsets.right, 2); + }); + + test('Padding in default badge shape with icon and padding value', + () async { + const badge = badges.Badge( + badgeContent: Icon(Icons.add), + badgeStyle: badges.BadgeStyle( + shape: badges.BadgeShape.circle, + padding: EdgeInsets.only(left: 1, right: 2, top: 3, bottom: 4)), + ); + final edgeInsets = CalculationUtils.calculateBadgeContentPadding( + badge.badgeContent, + badge.badgeStyle, + ) as EdgeInsets; + expect(edgeInsets.top, 3); + expect(edgeInsets.bottom, 4); + expect(edgeInsets.left, 1); + expect(edgeInsets.right, 2); + }); + + test('Padding in default badge shape with icon and null padding ', + () async { + const badge = badges.Badge( + badgeContent: Icon(Icons.add), + badgeStyle: badges.BadgeStyle(shape: badges.BadgeShape.circle), + ); + final edgeInsets = CalculationUtils.calculateBadgeContentPadding( + badge.badgeContent, + badge.badgeStyle, + ) as EdgeInsets; + expect(edgeInsets.top, 5); + expect(edgeInsets.bottom, 5); + expect(edgeInsets.left, 5); + expect(edgeInsets.right, 5); + }); + }); }