diff --git a/example/lib/main.dart b/example/lib/main.dart index 289251a..dd05f4b 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -68,7 +68,9 @@ class HomeScreen extends StatelessWidget { onPressed: () { print('[HomeScreen.build] Fill pressed'); }, - fillColor: Colors.red.withOpacity(0.2), + theme: PressableFillTheme( + fillColor: Colors.red.withOpacity(0.2), + ), child: const ExampleButton(title: 'Fill'), ), SizedBox( diff --git a/example/pubspec.lock b/example/pubspec.lock index e40992f..43e7a0b 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -43,6 +43,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.15.0" + equatable: + dependency: transitive + description: + name: equatable + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.3" fake_async: dependency: transitive description: diff --git a/lib/pressable.dart b/lib/pressable.dart index e022f77..08e0466 100644 --- a/lib/pressable.dart +++ b/lib/pressable.dart @@ -8,6 +8,10 @@ import 'package:pressable/src/ripple.dart'; import 'package:pressable/src/scale.dart'; export 'package:pressable/src/builder.dart' show PressableBuilderCallback; +export 'package:pressable/src/fill.dart' show PressableFillTheme; +export 'package:pressable/src/opacity.dart' show PressableOpacityTheme; +export 'package:pressable/src/ripple.dart' show PressableRippleTheme; +export 'package:pressable/src/scale.dart' show PressableScaleTheme; /// Choose named constructors to pick press effect. abstract class Pressable extends StatefulWidget { @@ -19,67 +23,55 @@ abstract class Pressable extends StatefulWidget { required Widget child, VoidCallback? onPressed, VoidCallback? onLongPressed, - BorderRadius? borderRadius, - Color? splashColor, - Color? highlightColor, + PressableRippleTheme? theme, }) { return PressableRipple( key: key, onPressed: onPressed, onLongPressed: onLongPressed, - borderRadius: borderRadius, - splashColor: splashColor, - highlightColor: highlightColor, + theme: theme ?? const PressableRippleTheme(), child: child, ); } - /// Scales the [child] by [scaleFactor] when tapped. + /// Scales the [child] to [PressableScaleTheme.scaleFactor] when tapped. factory Pressable.scale({ Key? key, required Widget child, VoidCallback? onPressed, VoidCallback? onLongPressed, - Duration duration = const Duration(milliseconds: 100), - Curve curve = Curves.easeInOut, - double scaleFactor = 0.6, + PressableScaleTheme? theme, }) { return PressableScale( key: key, onPressed: onPressed, onLongPressed: onLongPressed, - curve: curve, - duration: duration, - scaleFactor: scaleFactor, + theme: theme ?? const PressableScaleTheme(), child: child, ); } - /// Adds [opacityFactor] opacity to the [child] when pressed. + /// Adds [PressableOpacityTheme.opacityFactor] opacity to the [child] + /// when pressed. factory Pressable.opacity({ Key? key, required Widget child, VoidCallback? onPressed, VoidCallback? onLongPressed, - Duration duration = const Duration(milliseconds: 100), - Curve curve = Curves.linear, - double opacityFactor = 0.6, - Color backgroundColor = Colors.transparent, + PressableOpacityTheme? theme, }) { return PressableOpacity( key: key, onPressed: onPressed, onLongPressed: onLongPressed, - duration: duration, - curve: curve, - opacityFactor: opacityFactor, - backgroundColor: backgroundColor, + theme: theme ?? const PressableOpacityTheme(), child: child, ); } - /// Puts [fillColor] over the [child] when pressed. [fillColor] needs to be - /// semi-transparent so that the [child] can be visible. + /// Puts [PressableFillTheme.fillColor] over the [child] when pressed. + /// [PressableFillTheme.fillColor] needs to be semi-transparent so that + /// the [child] can be visible. /// /// Uses [InkWell] for the implementation. factory Pressable.fill({ @@ -87,19 +79,13 @@ abstract class Pressable extends StatefulWidget { required Widget child, VoidCallback? onPressed, VoidCallback? onLongPressed, - Duration duration = const Duration(milliseconds: 100), - Curve curve = Curves.linear, - Color fillColor = Colors.black38, - BorderRadius? borderRadius, + PressableFillTheme? theme, }) { return PressableFill( key: key, onPressed: onPressed, onLongPressed: onLongPressed, - duration: duration, - curve: curve, - fillColor: fillColor, - borderRadius: borderRadius, + theme: theme ?? const PressableFillTheme(), child: child, ); } diff --git a/lib/src/fill.dart b/lib/src/fill.dart index e13a9ec..bda3102 100644 --- a/lib/src/fill.dart +++ b/lib/src/fill.dart @@ -1,3 +1,4 @@ +import 'package:equatable/equatable.dart'; import 'package:flutter/material.dart'; import 'package:pressable/pressable.dart'; import 'package:pressable/src/base.dart'; @@ -8,19 +9,13 @@ class PressableFill extends Pressable { required this.child, this.onPressed, this.onLongPressed, - required this.duration, - required this.fillColor, - required this.curve, - this.borderRadius, + required this.theme, }) : super(key: key); final Widget child; final VoidCallback? onPressed; final VoidCallback? onLongPressed; - final Duration duration; - final Color fillColor; - final Curve curve; - final BorderRadius? borderRadius; + final PressableFillTheme theme; @override _PressableFillState createState() => _PressableFillState(); @@ -33,10 +28,23 @@ class _PressableFillState extends PressableBaseState { onTap: widget.onPressed, onLongPress: widget.onLongPressed, splashFactory: InkRipple.splashFactory, - highlightColor: widget.fillColor, + highlightColor: widget.theme.fillColor, splashColor: Colors.transparent, - borderRadius: widget.borderRadius, + borderRadius: widget.theme.borderRadius, child: widget.child, ); } } + +class PressableFillTheme extends Equatable { + const PressableFillTheme({ + this.fillColor = Colors.black38, + this.borderRadius = BorderRadius.zero, + }); + + final Color fillColor; + final BorderRadius borderRadius; + + @override + List get props => [fillColor, borderRadius]; +} diff --git a/lib/src/opacity.dart b/lib/src/opacity.dart index ec27cd0..61f514b 100644 --- a/lib/src/opacity.dart +++ b/lib/src/opacity.dart @@ -1,3 +1,4 @@ +import 'package:equatable/equatable.dart'; import 'package:flutter/material.dart'; import 'package:pressable/pressable.dart'; import 'package:pressable/src/base.dart'; @@ -8,19 +9,13 @@ class PressableOpacity extends Pressable { required this.child, this.onPressed, this.onLongPressed, - required this.duration, - required this.opacityFactor, - required this.curve, - required this.backgroundColor, + required this.theme, }) : super(key: key); final Widget child; final VoidCallback? onPressed; final VoidCallback? onLongPressed; - final Duration duration; - final double opacityFactor; - final Curve curve; - final Color backgroundColor; + final PressableOpacityTheme theme; @override _PressableOpacityState createState() => _PressableOpacityState(); @@ -37,11 +32,28 @@ class _PressableOpacityState extends PressableBaseState { onLongPress: widget.onLongPressed, behavior: HitTestBehavior.opaque, child: AnimatedOpacity( - opacity: isPressed ? widget.opacityFactor : 1.0, - duration: widget.duration, - curve: widget.curve, + opacity: isPressed ? widget.theme.opacityFactor : 1.0, + duration: widget.theme.duration, + curve: widget.theme.curve, child: widget.child, ), ); } } + +class PressableOpacityTheme extends Equatable { + const PressableOpacityTheme({ + this.duration = const Duration(milliseconds: 100), + this.curve = Curves.linear, + this.opacityFactor = 0.6, + this.backgroundColor = Colors.transparent, + }); + + final Duration duration; + final double opacityFactor; + final Curve curve; + final Color backgroundColor; + + @override + List get props => [duration, opacityFactor, curve, backgroundColor]; +} diff --git a/lib/src/ripple.dart b/lib/src/ripple.dart index 356ca28..5a70a38 100644 --- a/lib/src/ripple.dart +++ b/lib/src/ripple.dart @@ -1,3 +1,4 @@ +import 'package:equatable/equatable.dart'; import 'package:flutter/material.dart'; import 'package:pressable/pressable.dart'; @@ -7,17 +8,13 @@ class PressableRipple extends Pressable { required this.child, this.onPressed, this.onLongPressed, - this.splashColor, - this.highlightColor, - this.borderRadius, + this.theme, }) : super(key: key); final Widget child; final VoidCallback? onPressed; final VoidCallback? onLongPressed; - final Color? splashColor; - final Color? highlightColor; - final BorderRadius? borderRadius; + final PressableRippleTheme? theme; @override _PressableRippleState createState() => _PressableRippleState(); @@ -30,10 +27,25 @@ class _PressableRippleState extends State { onTap: widget.onPressed, onLongPress: widget.onLongPressed, splashFactory: InkRipple.splashFactory, - highlightColor: widget.highlightColor, - splashColor: widget.splashColor, - borderRadius: widget.borderRadius, + highlightColor: widget.theme?.highlightColor, + splashColor: widget.theme?.splashColor, + borderRadius: widget.theme?.borderRadius, child: widget.child, ); } } + +class PressableRippleTheme extends Equatable { + const PressableRippleTheme({ + this.splashColor, + this.highlightColor, + this.borderRadius, + }); + + final Color? splashColor; + final Color? highlightColor; + final BorderRadius? borderRadius; + + @override + List get props => [splashColor, highlightColor, borderRadius]; +} diff --git a/lib/src/scale.dart b/lib/src/scale.dart index 3b04f5f..a4b9b3a 100644 --- a/lib/src/scale.dart +++ b/lib/src/scale.dart @@ -1,3 +1,4 @@ +import 'package:equatable/equatable.dart'; import 'package:flutter/material.dart'; import 'package:pressable/pressable.dart'; import 'package:pressable/src/base.dart'; @@ -8,17 +9,13 @@ class PressableScale extends Pressable { required this.child, this.onPressed, this.onLongPressed, - this.scaleFactor = 0.6, - this.duration = const Duration(milliseconds: 100), - this.curve = Curves.bounceInOut, + this.theme = const PressableScaleTheme(), }) : super(key: key); final Widget child; final VoidCallback? onPressed; final VoidCallback? onLongPressed; - final double scaleFactor; - final Duration duration; - final Curve curve; + final PressableScaleTheme theme; @override _PressableScaleState createState() => _PressableScaleState(); @@ -27,16 +24,16 @@ class PressableScale extends Pressable { class _PressableScaleState extends PressableBaseState with TickerProviderStateMixin { late final AnimationController _controller = AnimationController( - duration: widget.duration, + duration: widget.theme.duration, vsync: this, value: 1.0, - lowerBound: widget.scaleFactor, + lowerBound: widget.theme.scaleFactor, upperBound: 1.0, ); late final Animation _animation = CurvedAnimation( parent: _controller, - curve: widget.curve, + curve: widget.theme.curve, ); @override @@ -67,7 +64,7 @@ class _PressableScaleState extends PressableBaseState @override void onPressStarted(TapDownDetails details) { super.onPressStarted(details); - _controller.animateTo(widget.scaleFactor); + _controller.animateTo(widget.theme.scaleFactor); } @override @@ -88,3 +85,18 @@ class _PressableScaleState extends PressableBaseState super.dispose(); } } + +class PressableScaleTheme extends Equatable { + const PressableScaleTheme({ + this.scaleFactor = 0.6, + this.duration = const Duration(milliseconds: 100), + this.curve = Curves.easeInOut, + }); + + final double scaleFactor; + final Duration duration; + final Curve curve; + + @override + List get props => [scaleFactor, duration, curve]; +} diff --git a/pubspec.lock b/pubspec.lock index 816c48a..7337c58 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -43,6 +43,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.15.0" + equatable: + dependency: "direct main" + description: + name: equatable + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.3" fake_async: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index a84ad63..a9eff06 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -8,6 +8,7 @@ environment: flutter: ">=1.17.0" dependencies: + equatable: ^2.0.3 flutter: sdk: flutter