Skip to content

Commit 34cb40f

Browse files
committed
feat:✨Added feature to add action buttons for the tooltip
1 parent 2c7ab28 commit 34cb40f

11 files changed

+716
-521
lines changed

CHANGELOG.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## [4.0.0]
2+
3+
- Feature ✨: Added Action widget for tooltip
4+
15
## [3.0.1]
26

37
- Feature [#475](https://github.com/SimformSolutionsPvtLtd/flutter_showcaseview/issues/475) - Add
@@ -9,7 +13,6 @@
913
- Fixed [#449](https://github.com/SimformSolutionsPvtLtd/flutter_showcaseview/issues/449) - Null check operator used on a null value
1014
- [BREAKING] Improvement [#400](https://github.com/SimformSolutionsPvtLtd/flutter_showcaseview/issues/400) - remove Builder widget
1115
- Fixed [#435](https://github.com/SimformSolutionsPvtLtd/flutter_showcaseview/issues/435) - Extra padding when add targetShapeBorder
12-
- Feature [#466](https://github.com/SimformSolutionsPvtLtd/flutter_showcaseview/pull/466) - Provide tooltip action buttons
1316

1417
## [2.1.1]
1518
- Fixed [#425](https://github.com/SimformSolutionsPvtLtd/flutter_showcaseview/issues/425) - Unhandled breaking change in v2.1.0

README.md

Lines changed: 60 additions & 60 deletions
Large diffs are not rendered by default.

example/lib/main.dart

Lines changed: 67 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ class MyApp extends StatelessWidget {
3939
builder: (context) => const MailPage(),
4040
globalTooltipActionConfig: const TooltipActionConfig(
4141
position: TooltipActionPosition.inside,
42-
alignment: TooltipActionAlignment.spread,
42+
alignment: MainAxisAlignment.spaceBetween,
4343
),
4444
),
4545
),
@@ -186,7 +186,7 @@ class _MailPageState extends State<MailPage> {
186186
debugPrint('Barrier clicked'),
187187
tooltipActionConfig:
188188
const TooltipActionConfig(
189-
alignment: TooltipActionAlignment.right,
189+
alignment: MainAxisAlignment.end,
190190
position: TooltipActionPosition.outside,
191191
gapBetweenContentAndAction: 10,
192192
),
@@ -236,7 +236,20 @@ class _MailPageState extends State<MailPage> {
236236
"Tap to see profile which contains user's name, profile picture, mobile number and country",
237237
tooltipBackgroundColor: Theme.of(context).primaryColor,
238238
textColor: Colors.white,
239+
onTargetClick: () {
240+
print('target cliecked');
241+
},
242+
disposeOnTap: false,
243+
onToolTipClick: () {
244+
print('clicked tool tip');
245+
},
246+
disableDefaultTargetGestures: true,
239247
targetShapeBorder: const CircleBorder(),
248+
tooltipActionConfig: const TooltipActionConfig(
249+
alignment: MainAxisAlignment.spaceBetween,
250+
gapBetweenContentAndAction: 10,
251+
position: TooltipActionPosition.outside,
252+
),
240253
tooltipActions: [
241254
TooltipActionButton.withDefault(
242255
backgroundColor: Colors.transparent,
@@ -249,7 +262,7 @@ class _MailPageState extends State<MailPage> {
249262
textStyle: const TextStyle(
250263
color: Colors.pinkAccent,
251264
),
252-
)
265+
),
253266
],
254267
child: Container(
255268
padding: const EdgeInsets.all(5),
@@ -308,8 +321,8 @@ class _MailPageState extends State<MailPage> {
308321
targetShapeBorder: const CircleBorder(),
309322
showArrow: false,
310323
tooltipActionConfig: const TooltipActionConfig(
311-
alignment: TooltipActionAlignment.spread,
312-
actionGap: 15,
324+
alignment: MainAxisAlignment.spaceBetween,
325+
actionGap: 12,
313326
),
314327
tooltipActions: [
315328
TooltipActionButton.withDefault(
@@ -324,7 +337,7 @@ class _MailPageState extends State<MailPage> {
324337
color: Colors.pink,
325338
)),
326339
TooltipActionButton.withDefault(
327-
type: TooltipDefaultActionType.next,
340+
type: TooltipDefaultActionType.skip,
328341
name: 'Close',
329342
tailIcon: const ActionButtonIcon.withIcon(
330343
icon: Icon(
@@ -333,10 +346,6 @@ class _MailPageState extends State<MailPage> {
333346
size: 15,
334347
),
335348
),
336-
onTap: () {
337-
// Write your code on button tap
338-
ShowCaseWidget.of(context).next();
339-
},
340349
),
341350
],
342351
child: FloatingActionButton(
@@ -375,8 +384,37 @@ class _MailPageState extends State<MailPage> {
375384
child: Showcase(
376385
key: key,
377386
description: 'Tap to check mail',
378-
tooltipPosition: TooltipPosition.top,
379387
disposeOnTap: true,
388+
tooltipActionConfig: const TooltipActionConfig(
389+
alignment: MainAxisAlignment.spaceBetween,
390+
actionGap: 15,
391+
position: TooltipActionPosition.outside,
392+
gapBetweenContentAndAction: 16,
393+
),
394+
tooltipActions: [
395+
TooltipActionButton.withDefault(
396+
type: TooltipDefaultActionType.previous,
397+
name: 'Back',
398+
onTap: () {
399+
// Write your code on button tap
400+
ShowCaseWidget.of(context).previous();
401+
},
402+
backgroundColor: Colors.pink.shade50,
403+
textStyle: const TextStyle(
404+
color: Colors.pink,
405+
)),
406+
TooltipActionButton.withDefault(
407+
type: TooltipDefaultActionType.skip,
408+
name: 'Close',
409+
tailIcon: const ActionButtonIcon.withIcon(
410+
icon: Icon(
411+
Icons.close,
412+
color: Colors.white,
413+
size: 15,
414+
),
415+
),
416+
),
417+
],
380418
onTargetClick: () {
381419
Navigator.push<void>(
382420
context,
@@ -475,6 +513,24 @@ class MailTile extends StatelessWidget {
475513
key: showCaseKey!,
476514
height: 50,
477515
width: 140,
516+
tooltipActionConfig: const TooltipActionConfig(
517+
alignment: MainAxisAlignment.center,
518+
crossAxisAlignment: CrossAxisAlignment.center,
519+
),
520+
tooltipActions: [
521+
TooltipActionButton.withDefault(
522+
backgroundColor: Colors.transparent,
523+
type: TooltipDefaultActionType.previous,
524+
padding: EdgeInsets.zero,
525+
),
526+
TooltipActionButton.withDefault(
527+
type: TooltipDefaultActionType.next,
528+
backgroundColor: Colors.white,
529+
textStyle: const TextStyle(
530+
color: Colors.pinkAccent,
531+
),
532+
),
533+
],
478534
targetShapeBorder: const CircleBorder(),
479535
targetBorderRadius: const BorderRadius.all(
480536
Radius.circular(150),

lib/src/enum.dart

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,18 @@
2222

2323
import 'package:flutter/cupertino.dart';
2424

25+
import 'showcase_widget.dart';
26+
2527
enum TooltipPosition { top, bottom }
2628

27-
enum TooltipActionPosition { outside, inside }
29+
enum TooltipActionPosition {
30+
outside,
31+
inside;
32+
33+
bool get isInside => this == inside;
34+
35+
bool get isOutside => this == outside;
36+
}
2837

2938
enum TooltipActionAlignment {
3039
left(MainAxisAlignment.start),
@@ -47,4 +56,20 @@ enum TooltipDefaultActionType {
4756
});
4857

4958
final String actionName;
59+
60+
void onTap(ShowCaseWidgetState showCaseState) {
61+
switch (this) {
62+
case TooltipDefaultActionType.next:
63+
showCaseState.next();
64+
break;
65+
case TooltipDefaultActionType.previous:
66+
showCaseState.previous();
67+
break;
68+
case TooltipDefaultActionType.skip:
69+
showCaseState.dismiss();
70+
break;
71+
default:
72+
throw ArgumentError('Invalid tooltip default action type');
73+
}
74+
}
5075
}

lib/src/models/tooltip_action_button.dart

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,60 @@ import 'package:flutter/material.dart';
33
import '../../showcaseview.dart';
44

55
class TooltipActionButton {
6+
/// To Provide Background color to the action
67
final Color? backgroundColor;
8+
9+
/// To Provide borderRadius to the action
10+
///
11+
/// Defaults to const BorderRadius.all(Radius.circular(50)),
712
final BorderRadius? borderRadius;
13+
14+
/// To Provide textStyle to the action text
15+
///
16+
/// Defaults to const TextStyle(color: Colors.white,),
817
final TextStyle? textStyle;
18+
19+
/// To Provide padding to the action widget
20+
///
21+
/// Defaults to const EdgeInsets.symmetric(horizontal: 15,vertical: 4,)
922
final EdgeInsets? padding;
23+
24+
/// To Provide a custom widget for the action in [TooltipActionButton.custom]
1025
final Widget? button;
26+
27+
/// To Provide a leading icon for the action
1128
final ActionButtonIcon? leadIcon;
29+
30+
/// To Provide a tail icon for the action
1231
final ActionButtonIcon? tailIcon;
32+
33+
/// To Provide a action type
1334
final TooltipDefaultActionType? type;
35+
36+
/// To Provide a text for action
37+
///
38+
/// If type is provided then it will take type name
1439
final String? name;
40+
41+
/// To Provide a onTap for action
42+
///
43+
/// If type is provided then it will take type's OnTap
1544
final VoidCallback? onTap;
45+
46+
/// To Provide a border for action
1647
final double? borderWidth;
48+
49+
/// To Provide a borderColor for action
1750
final Color? borderColor;
51+
52+
/// To show or hide action for the first tooltip
53+
///
54+
/// defaults to true
1855
final bool shouldShowForFirstTooltip;
56+
57+
/// To show or hide action for the hide tooltip
58+
///
59+
/// defaults to true
1960
final bool shouldShowForLastTooltip;
2061

2162
TooltipActionButton.withDefault({

lib/src/models/tooltip_action_config.dart

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,12 @@ import '../../showcaseview.dart';
44

55
class TooltipActionConfig {
66
const TooltipActionConfig({
7-
this.alignment = TooltipActionAlignment.left,
7+
this.alignment = MainAxisAlignment.spaceBetween,
88
this.actionGap = 5,
99
this.padding = EdgeInsets.zero,
1010
this.position = TooltipActionPosition.inside,
1111
this.gapBetweenContentAndAction = 10,
12+
this.crossAxisAlignment = CrossAxisAlignment.start,
1213
});
1314

1415
/// Defines tooltip action widget position.
@@ -20,7 +21,7 @@ class TooltipActionConfig {
2021
/// Defines the alignment of actions buttons of tooltip action widget
2122
///
2223
/// Default to [TooltipActionAlignment.left]
23-
final TooltipActionAlignment alignment;
24+
final MainAxisAlignment alignment;
2425

2526
/// Defines the gap between the actions buttons of tooltip action widget
2627
///
@@ -36,4 +37,9 @@ class TooltipActionConfig {
3637
///
3738
/// Default to 10.0
3839
final double gapBetweenContentAndAction;
40+
41+
/// Defines running direction alignment for the Action widgets.
42+
///
43+
/// Default to [crossAxisAlignment.start]
44+
final CrossAxisAlignment crossAxisAlignment;
3945
}

lib/src/showcase.dart

Lines changed: 38 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,8 @@ import 'dart:ui';
2525

2626
import 'package:flutter/foundation.dart';
2727
import 'package:flutter/material.dart';
28-
import 'package:showcaseview/showcaseview.dart';
2928

29+
import '../showcaseview.dart';
3030
import 'get_position.dart';
3131
import 'layout_overlays.dart';
3232
import 'shape_clipper.dart';
@@ -317,8 +317,8 @@ class Showcase extends StatefulWidget {
317317
this.toolTipSlideEndDistance = 7,
318318
this.toolTipMargin = 14,
319319
this.tooltipActionConfig,
320-
}) : width = null,
321-
height = null,
320+
}) : height = null,
321+
width = null,
322322
container = null,
323323
assert(overlayOpacity >= 0.0 && overlayOpacity <= 1.0,
324324
"overlay opacity must be between 0 and 1."),
@@ -655,9 +655,6 @@ class _ShowcaseState extends State<Showcase> {
655655
descriptionTextDirection: widget.descriptionTextDirection,
656656
toolTipSlideEndDistance: widget.toolTipSlideEndDistance,
657657
toolTipMargin: widget.toolTipMargin,
658-
tooltipActionPosition: widget.tooltipActionPosition,
659-
gapBetweenContentAndAction: widget.gapBetweenContentAndAction,
660-
showCaseState: ShowCaseWidget.of(context),
661658
tooltipActionConfig: _getTooltipActionConfig(),
662659
tooltipActions: _getTooltipActions(),
663660
),
@@ -666,10 +663,41 @@ class _ShowcaseState extends State<Showcase> {
666663
);
667664
}
668665

669-
List<TooltipActionButton> _getTooltipActions() =>
670-
(widget.tooltipActions?.isEmpty ?? true)
671-
? ShowCaseWidget.of(context).globalTooltipActions ?? []
672-
: widget.tooltipActions ?? [];
666+
List<Widget> _getTooltipActions() {
667+
final showCaseState = ShowCaseWidget.of(context);
668+
final actionData = (widget.tooltipActions?.isEmpty ?? true)
669+
? showCaseState.globalTooltipActions ?? []
670+
: widget.tooltipActions ?? [];
671+
672+
final actionWidgets = <Widget>[];
673+
for (var action = 0; action < actionData.length; action++) {
674+
/// This checks that if it is first or last tooltip and
675+
/// [shouldShowForLastTooltip] or [shouldShowForFirstTooltip] is true
676+
/// then we will ignore that action
677+
if (((showCaseState.activeWidgetId == 0 &&
678+
actionData[action].shouldShowForFirstTooltip) ||
679+
(showCaseState.activeWidgetId ==
680+
(showCaseState.ids?.length ?? 0) - 1 &&
681+
!actionData[action].shouldShowForLastTooltip)) &&
682+
(widget.tooltipActions?.isEmpty ?? true)) {
683+
continue;
684+
}
685+
actionWidgets.add(
686+
Padding(
687+
padding: EdgeInsetsDirectional.only(
688+
end: action < actionData.length - 1
689+
? _getTooltipActionConfig().actionGap
690+
: 0,
691+
),
692+
child: TooltipActionButtonWidget(
693+
config: actionData[action],
694+
showCaseState: ShowCaseWidget.of(context),
695+
),
696+
),
697+
);
698+
}
699+
return actionWidgets;
700+
}
673701

674702
TooltipActionConfig _getTooltipActionConfig() {
675703
final showCaseState = ShowCaseWidget.of(context);

lib/src/showcase_widget.dart

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,10 @@ class ShowCaseWidget extends StatefulWidget {
8383
/// Enable/disable showcase globally. Enabled by default.
8484
final bool enableShowcase;
8585

86+
/// Global action to apply on every tooltip widget
8687
final List<TooltipActionButton>? globalTooltipActions;
88+
89+
/// Global Config for tooltip action to auto apply for all the toolTip
8790
final TooltipActionConfig? globalTooltipActionConfig;
8891

8992
const ShowCaseWidget({
@@ -132,6 +135,7 @@ class ShowCaseWidgetState extends State<ShowCaseWidget> {
132135
Key? anchoredOverlayKey;
133136

134137
late final TooltipActionConfig? globalTooltipActionConfig;
138+
135139
late final List<TooltipActionButton>? globalTooltipActions;
136140

137141
/// These properties are only here so that it can be accessed by

0 commit comments

Comments
 (0)