diff --git a/example/lib/main.dart b/example/lib/main.dart index bc2ee34..5006e81 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -97,11 +97,15 @@ class _MyHomePageState extends State with TickerProviderStateMixin { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text("SpeedDial Location", style: Theme.of(context).textTheme.bodyLarge), + Text("SpeedDial Location", + style: Theme.of(context).textTheme.bodyLarge), const SizedBox(height: 10), Container( decoration: BoxDecoration( - color: Theme.of(context).brightness == Brightness.dark ? Colors.grey[800] : Colors.grey[200], + color: Theme.of(context).brightness == + Brightness.dark + ? Colors.grey[800] + : Colors.grey[200], borderRadius: BorderRadius.circular(10)), child: DropdownButton( value: selectedfABLocation, @@ -109,16 +113,21 @@ class _MyHomePageState extends State with TickerProviderStateMixin { icon: const Icon(Icons.arrow_drop_down), iconSize: 20, underline: const SizedBox(), - onChanged: (fABLocation) => setState(() => selectedfABLocation = fABLocation!), + onChanged: (fABLocation) => setState( + () => selectedfABLocation = fABLocation!), selectedItemBuilder: (BuildContext context) { return items.map((item) { return Align( alignment: Alignment.centerLeft, - child: Container(padding: const EdgeInsets.symmetric(vertical: 4, horizontal: 10), child: Text(item.value))); + child: Container( + padding: const EdgeInsets.symmetric( + vertical: 4, horizontal: 10), + child: Text(item.value))); }).toList(); }, items: items.map((item) { - return DropdownMenuItem( + return DropdownMenuItem< + FloatingActionButtonLocation>( value: item, child: Text( item.value, @@ -137,11 +146,15 @@ class _MyHomePageState extends State with TickerProviderStateMixin { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text("SpeedDial Direction", style: Theme.of(context).textTheme.bodyLarge), + Text("SpeedDial Direction", + style: Theme.of(context).textTheme.bodyLarge), const SizedBox(height: 10), Container( decoration: BoxDecoration( - color: Theme.of(context).brightness == Brightness.dark ? Colors.grey[800] : Colors.grey[200], + color: Theme.of(context).brightness == + Brightness.dark + ? Colors.grey[800] + : Colors.grey[200], borderRadius: BorderRadius.circular(10)), child: DropdownButton( value: speedDialDirection, @@ -152,25 +165,42 @@ class _MyHomePageState extends State with TickerProviderStateMixin { onChanged: (sdo) { setState(() { speedDialDirection = sdo!; - selectedfABLocation = (sdo.isUp && selectedfABLocation.value.contains("Top")) || - (sdo.isLeft && selectedfABLocation.value.contains("start")) + selectedfABLocation = (sdo.isUp && + selectedfABLocation.value + .contains("Top")) || + (sdo.isLeft && + selectedfABLocation.value + .contains("start")) ? FloatingActionButtonLocation.endDocked - : sdo.isDown && !selectedfABLocation.value.contains("Top") + : sdo.isDown && + !selectedfABLocation.value + .contains("Top") ? FloatingActionButtonLocation.endTop - : sdo.isRight && selectedfABLocation.value.contains("end") - ? FloatingActionButtonLocation.startDocked + : sdo.isRight && + selectedfABLocation.value + .contains("end") + ? FloatingActionButtonLocation + .startDocked : selectedfABLocation; }); }, selectedItemBuilder: (BuildContext context) { - return SpeedDialDirection.values.toList().map((item) { + return SpeedDialDirection.values + .toList() + .map((item) { return Container( - padding: const EdgeInsets.symmetric(vertical: 4, horizontal: 10), - child: Align(alignment: Alignment.centerLeft, child: Text(describeEnum(item).toUpperCase())), + padding: const EdgeInsets.symmetric( + vertical: 4, horizontal: 10), + child: Align( + alignment: Alignment.centerLeft, + child: Text( + describeEnum(item).toUpperCase())), ); }).toList(); }, - items: SpeedDialDirection.values.toList().map((item) { + items: SpeedDialDirection.values + .toList() + .map((item) { return DropdownMenuItem( value: item, child: Text(describeEnum(item).toUpperCase()), @@ -290,12 +320,21 @@ class _MyHomePageState extends State with TickerProviderStateMixin { setState(() { switchLabelPosition = val; if (val) { - if ((selectedfABLocation.value.contains("end") || selectedfABLocation.value.toLowerCase().contains("top")) && + if ((selectedfABLocation.value.contains("end") || + selectedfABLocation.value + .toLowerCase() + .contains("top")) && speedDialDirection.isUp) { - selectedfABLocation = FloatingActionButtonLocation.startDocked; - } else if ((selectedfABLocation.value.contains("end") || !selectedfABLocation.value.toLowerCase().contains("top")) && + selectedfABLocation = + FloatingActionButtonLocation.startDocked; + } else if ((selectedfABLocation.value + .contains("end") || + !selectedfABLocation.value + .toLowerCase() + .contains("top")) && speedDialDirection.isDown) { - selectedfABLocation = FloatingActionButtonLocation.startTop; + selectedfABLocation = + FloatingActionButtonLocation.startTop; } } }); @@ -330,13 +369,15 @@ class _MyHomePageState extends State with TickerProviderStateMixin { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text("Navigation", style: Theme.of(context).textTheme.bodyLarge), + Text("Navigation", + style: Theme.of(context).textTheme.bodyLarge), const SizedBox(height: 10), ElevatedButton( onPressed: () { Navigator.of(context).push( MaterialPageRoute( - builder: (_) => MyHomePage(theme: widget.theme), + builder: (_) => + MyHomePage(theme: widget.theme), ), ); }, @@ -368,7 +409,8 @@ class _MyHomePageState extends State with TickerProviderStateMixin { onPressed: toggleChildren, style: ElevatedButton.styleFrom( backgroundColor: Colors.blue[900], - padding: const EdgeInsets.symmetric(horizontal: 22, vertical: 18), + padding: const EdgeInsets.symmetric( + horizontal: 22, vertical: 18), ), child: const Text( "Custom Dial Root", @@ -377,9 +419,12 @@ class _MyHomePageState extends State with TickerProviderStateMixin { ); } : null, - buttonSize: buttonSize, // it's the SpeedDial size which defaults to 56 itself + buttonSize: + buttonSize, // it's the SpeedDial size which defaults to 56 itself // iconTheme: IconThemeData(size: 22), - label: extend ? const Text("Open") : null, // The label of the main button. + label: extend + ? const Text("Open") + : null, // The label of the main button. /// The active label of the main button, Defaults to label if not specified. activeLabel: extend ? const Text("Close") : null, @@ -410,7 +455,9 @@ class _MyHomePageState extends State with TickerProviderStateMixin { elevation: 8.0, animationCurve: Curves.elasticInOut, isOpenOnStart: false, - shape: customDialRoot ? const RoundedRectangleBorder() : const StadiumBorder(), + shape: customDialRoot + ? const RoundedRectangleBorder() + : const StadiumBorder(), // childMargin: EdgeInsets.symmetric(horizontal: 10, vertical: 5), children: [ SpeedDialChild( @@ -434,7 +481,8 @@ class _MyHomePageState extends State with TickerProviderStateMixin { foregroundColor: Colors.white, label: 'Show Snackbar', visible: true, - onTap: () => ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text(("Third Child Pressed")))), + onTap: () => ScaffoldMessenger.of(context).showSnackBar( + const SnackBar(content: Text(("Third Child Pressed")))), onLongPress: () => debugPrint('THIRD CHILD LONG PRESS'), ), ], @@ -443,7 +491,8 @@ class _MyHomePageState extends State with TickerProviderStateMixin { shape: const CircularNotchedRectangle(), notchMargin: 8.0, child: Row( - mainAxisAlignment: selectedfABLocation == FloatingActionButtonLocation.startDocked + mainAxisAlignment: selectedfABLocation == + FloatingActionButtonLocation.startDocked ? MainAxisAlignment.end : selectedfABLocation == FloatingActionButtonLocation.endDocked ? MainAxisAlignment.start @@ -453,7 +502,11 @@ class _MyHomePageState extends State with TickerProviderStateMixin { IconButton( icon: const Icon(Icons.nightlight_round), tooltip: "Switch Theme", - onPressed: () => {widget.theme.value = widget.theme.value.index == 2 ? ThemeMode.light : ThemeMode.dark}, + onPressed: () => { + widget.theme.value = widget.theme.value.index == 2 + ? ThemeMode.light + : ThemeMode.dark + }, ), ValueListenableBuilder( valueListenable: isDialOpen, diff --git a/lib/src/speed_dial.dart b/lib/src/speed_dial.dart index 137e2ee..3960075 100644 --- a/lib/src/speed_dial.dart +++ b/lib/src/speed_dial.dart @@ -10,7 +10,8 @@ import 'background_overlay.dart'; import 'speed_dial_child.dart'; import 'speed_dial_direction.dart'; -typedef AsyncChildrenBuilder = Future> Function(BuildContext context); +typedef AsyncChildrenBuilder = Future> Function( + BuildContext context); /// Builds the Speed Dial class SpeedDial extends StatefulWidget { @@ -149,7 +150,8 @@ class SpeedDial extends StatefulWidget { /// ignore backgroundColor, foregroundColor or any other property /// that was specific to FAB before like onPress, you will have to provide /// it again to your dialRoot button. - final Widget Function(BuildContext context, bool open, VoidCallback toggleChildren)? dialRoot; + final Widget Function( + BuildContext context, bool open, VoidCallback toggleChildren)? dialRoot; /// This is the child of the FAB, if specified it will ignore icon, activeIcon. final Widget? child; @@ -222,7 +224,8 @@ class SpeedDial extends StatefulWidget { State createState() => _SpeedDialState(); } -class _SpeedDialState extends State with SingleTickerProviderStateMixin { +class _SpeedDialState extends State + with SingleTickerProviderStateMixin { late final AnimationController _controller = AnimationController( duration: widget.animationDuration, vsync: this, @@ -271,7 +274,8 @@ class _SpeedDialState extends State with SingleTickerProviderStateMix void _checkChildren() { if (widget.children.length > 5) { - debugPrint('Warning ! You are using more than 5 children, which is not compliant with Material design specs.'); + debugPrint( + 'Warning ! You are using more than 5 children, which is not compliant with Material design specs.'); } } @@ -307,7 +311,9 @@ class _SpeedDialState extends State with SingleTickerProviderStateMix if (_open) { _controller.reverse().whenComplete(() { overlayEntry?.remove(); - if (widget.renderOverlay && backgroundOverlay != null && backgroundOverlay!.mounted) { + if (widget.renderOverlay && + backgroundOverlay != null && + backgroundOverlay!.mounted) { backgroundOverlay?.remove(); } }); @@ -340,7 +346,8 @@ class _SpeedDialState extends State with SingleTickerProviderStateMix onTap: _toggleChildren, // (_open && !widget.closeManually) ? _toggleChildren : null, animation: _controller, - color: widget.overlayColor ?? (dark ? Colors.grey[900] : Colors.white)!, + color: widget.overlayColor ?? + (dark ? Colors.grey[900] : Colors.white)!, opacity: widget.overlayOpacity, ); }, @@ -379,14 +386,18 @@ class _SpeedDialState extends State with SingleTickerProviderStateMix : AnimatedBuilder( animation: _controller, builder: (BuildContext context, _) => Transform.rotate( - angle: (widget.activeChild != null || widget.activeIcon != null) && widget.useRotationAnimation - ? _controller.value * widget.animationAngle - : 0, + angle: + (widget.activeChild != null || widget.activeIcon != null) && + widget.useRotationAnimation + ? _controller.value * widget.animationAngle + : 0, child: AnimatedSwitcher( duration: widget.animationDuration, child: (widget.child != null && _controller.value < 0.4) ? widget.child - : (widget.activeIcon == null && widget.activeChild == null || _controller.value < 0.4) + : (widget.activeIcon == null && + widget.activeChild == null || + _controller.value < 0.4) ? Container( decoration: BoxDecoration( shape: widget.gradientBoxShape, @@ -404,7 +415,8 @@ class _SpeedDialState extends State with SingleTickerProviderStateMix ), ) : Transform.rotate( - angle: widget.useRotationAnimation ? -pi * 1 / 2 : 0, + angle: + widget.useRotationAnimation ? -pi * 1 / 2 : 0, child: widget.activeChild ?? Container( decoration: BoxDecoration( @@ -431,11 +443,17 @@ class _SpeedDialState extends State with SingleTickerProviderStateMix opacity: animation, child: child, ), - child: (!_open || widget.activeLabel == null) ? widget.label : widget.activeLabel, + child: (!_open || widget.activeLabel == null) + ? widget.label + : widget.activeLabel, ); - final backgroundColorTween = ColorTween(begin: widget.backgroundColor, end: widget.activeBackgroundColor ?? widget.backgroundColor); - final foregroundColorTween = ColorTween(begin: widget.foregroundColor, end: widget.activeForegroundColor ?? widget.foregroundColor); + final backgroundColorTween = ColorTween( + begin: widget.backgroundColor, + end: widget.activeBackgroundColor ?? widget.backgroundColor); + final foregroundColorTween = ColorTween( + begin: widget.foregroundColor, + end: widget.activeForegroundColor ?? widget.foregroundColor); var animatedFloatingButton = AnimatedBuilder( animation: _controller, @@ -446,12 +464,20 @@ class _SpeedDialState extends State with SingleTickerProviderStateMix visible: widget.visible, tooltip: widget.tooltip, mini: widget.mini, - dialRoot: widget.dialRoot != null ? widget.dialRoot!(context, _open, _toggleChildren) : null, - backgroundColor: widget.backgroundColor != null ? backgroundColorTween.lerp(_controller.value) : null, - foregroundColor: widget.foregroundColor != null ? foregroundColorTween.lerp(_controller.value) : null, + dialRoot: widget.dialRoot != null + ? widget.dialRoot!(context, _open, _toggleChildren) + : null, + backgroundColor: widget.backgroundColor != null + ? backgroundColorTween.lerp(_controller.value) + : null, + foregroundColor: widget.foregroundColor != null + ? foregroundColorTween.lerp(_controller.value) + : null, elevation: widget.elevation, onLongPress: _toggleChildren, - callback: (_open || widget.onPress == null) ? _toggleChildren : widget.onPress, + callback: (_open || widget.onPress == null) + ? _toggleChildren + : widget.onPress, size: widget.buttonSize, label: widget.label != null ? label : null, heroTag: widget.heroTag, @@ -542,7 +568,9 @@ class _ChildrensOverlay extends StatelessWidget { if (!widget.closeManually) toggleChildren(); }, shape: child.shape, - heroTag: widget.heroTag != null ? '${widget.heroTag}-child-$index' : null, + heroTag: widget.heroTag != null + ? '${widget.heroTag}-child-$index' + : null, childMargin: widget.childMargin, childPadding: widget.childPadding, child: child.child, @@ -575,18 +603,30 @@ class _ChildrensOverlay extends StatelessWidget { : Alignment.center, offset: widget.direction.isDown ? Offset( - (widget.switchLabelPosition || dialKey.globalPaintBounds == null ? 0 : dialKey.globalPaintBounds!.size.width) + + (widget.switchLabelPosition || + dialKey.globalPaintBounds == null + ? 0 + : dialKey.globalPaintBounds!.size.width) + max(widget.childrenButtonSize.height - 56, 0) / 2, dialKey.globalPaintBounds!.size.height) : widget.direction.isUp ? Offset( - (widget.switchLabelPosition || dialKey.globalPaintBounds == null ? 0 : dialKey.globalPaintBounds!.size.width) + + (widget.switchLabelPosition || + dialKey.globalPaintBounds == null + ? 0 + : dialKey.globalPaintBounds!.size.width) + max(widget.childrenButtonSize.width - 56, 0) / 2, 0) : widget.direction.isLeft - ? Offset(-10.0, dialKey.globalPaintBounds == null ? 0 : dialKey.globalPaintBounds!.size.height / 2) - : widget.direction.isRight && dialKey.globalPaintBounds != null - ? Offset(dialKey.globalPaintBounds!.size.width + 12, dialKey.globalPaintBounds!.size.height / 2) + ? Offset( + -10.0, + dialKey.globalPaintBounds == null + ? 0 + : dialKey.globalPaintBounds!.size.height / 2) + : widget.direction.isRight && + dialKey.globalPaintBounds != null + ? Offset(dialKey.globalPaintBounds!.size.width + 12, + dialKey.globalPaintBounds!.size.height / 2) : const Offset(-10.0, 0.0), link: layerLink, showWhenUnlinked: false, @@ -594,7 +634,9 @@ class _ChildrensOverlay extends StatelessWidget { type: MaterialType.transparency, child: Container( padding: EdgeInsets.symmetric( - horizontal: widget.direction.isUp || widget.direction.isDown ? max(widget.buttonSize.width - 56, 0) / 2 : 0, + horizontal: widget.direction.isUp || widget.direction.isDown + ? max(widget.buttonSize.width - 56, 0) / 2 + : 0, ), margin: widget.spacing != null ? EdgeInsets.fromLTRB( @@ -606,9 +648,13 @@ class _ChildrensOverlay extends StatelessWidget { : null, child: _buildColumnOrRow( widget.direction.isUp || widget.direction.isDown, - crossAxisAlignment: widget.switchLabelPosition ? CrossAxisAlignment.start : CrossAxisAlignment.end, + crossAxisAlignment: widget.switchLabelPosition + ? CrossAxisAlignment.start + : CrossAxisAlignment.end, mainAxisSize: MainAxisSize.min, - children: widget.direction.isDown || widget.direction.isRight ? _getChildrenList().reversed.toList() : _getChildrenList(), + children: widget.direction.isDown || widget.direction.isRight + ? _getChildrenList().reversed.toList() + : _getChildrenList(), ), ), ), @@ -619,7 +665,10 @@ class _ChildrensOverlay extends StatelessWidget { } Widget _buildColumnOrRow(bool isColumn, - {CrossAxisAlignment? crossAxisAlignment, MainAxisAlignment? mainAxisAlignment, required List children, MainAxisSize? mainAxisSize}) { + {CrossAxisAlignment? crossAxisAlignment, + MainAxisAlignment? mainAxisAlignment, + required List children, + MainAxisSize? mainAxisSize}) { return isColumn ? Column( mainAxisSize: mainAxisSize ?? MainAxisSize.max,