Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Allow the passthrough of pointer events inside the highlighted area #17

Merged
merged 3 commits into from Sep 27, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
63 changes: 59 additions & 4 deletions example/lib/main.dart
Expand Up @@ -28,6 +28,9 @@ class _BubbleShowcaseDemoWidget extends StatelessWidget {
/// The first button global key.
final GlobalKey _firstButtonKey = GlobalKey();

/// The second button global key.
final GlobalKey _secondButtonKey = GlobalKey();

@override
Widget build(BuildContext context) {
TextStyle textStyle = Theme.of(context).textTheme.bodyText2!.copyWith(
Expand All @@ -40,8 +43,13 @@ class _BubbleShowcaseDemoWidget extends StatelessWidget {
_firstSlide(textStyle),
_secondSlide(textStyle),
_thirdSlide(textStyle),
_fourthSlide(textStyle),
],
child: _BubbleShowcaseDemoChild(_titleKey, _firstButtonKey),
child: _BubbleShowcaseDemoChild(
_titleKey,
_firstButtonKey,
_secondButtonKey,
),
);
}

Expand Down Expand Up @@ -143,6 +151,46 @@ class _BubbleShowcaseDemoWidget extends StatelessWidget {
),
),
);

/// Creates the fourth slide.
BubbleSlide _fourthSlide(TextStyle textStyle) => RelativeBubbleSlide(
highlightPadding: 4,
passThroughMode: PassthroughMode.INSIDE_WITH_NOTIFICATION,
widgetKey: _secondButtonKey,
shape: const Oval(
spreadRadius: 15,
),
child: RelativeBubbleSlideChild(
widget: Padding(
padding: const EdgeInsets.only(top: 8),
child: SpeechBubble(
nipLocation: NipLocation.TOP,
color: Colors.blue,
child: Padding(
padding: const EdgeInsets.all(10),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
Text(
'Going through!',
style: textStyle.copyWith(
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 10),
Text(
'Passthrough is on!\nTo finish the tutorial, you need to click this button',
style: textStyle,
),
],
),
),
),
),
),
);
}

/// The main demo widget child.
Expand All @@ -152,9 +200,11 @@ class _BubbleShowcaseDemoChild extends StatelessWidget {

/// The first button global key.
final GlobalKey _firstButtonKey;
final GlobalKey _secondButtonKey;

/// Creates a new bubble showcase demo child instance.
_BubbleShowcaseDemoChild(this._titleKey, this._firstButtonKey);
_BubbleShowcaseDemoChild(
this._titleKey, this._firstButtonKey, this._secondButtonKey);

@override
Widget build(BuildContext context) => Padding(
Expand Down Expand Up @@ -183,8 +233,13 @@ class _BubbleShowcaseDemoChild extends StatelessWidget {
),
),
ElevatedButton(
onPressed: () {},
child: const Text('This button is old, please don\'t pay attention.'),
key: _secondButtonKey,
onPressed: () {
const BubbleShowcaseNotification()..dispatch(context);
},
child: const Text(
'This button is old, please don\'t pay attention.',
),
)
],
),
Expand Down
28 changes: 27 additions & 1 deletion lib/src/shape.dart
Expand Up @@ -7,6 +7,8 @@ abstract class Shape {

/// Draw the shape on the specified canvas.
void drawOnCanvas(Canvas canvas, Rect rectangle, Paint paint);

void makePath(Path path, Rect rectangle);
}

/// A rectangle shape.
Expand All @@ -23,6 +25,11 @@ class Rectangle extends Shape {
void drawOnCanvas(Canvas canvas, Rect rectangle, Paint paint) {
canvas.drawRect(rectangle.inflate(spreadRadius), paint);
}

@override
void makePath(Path path, Rect rectangle) {
path.addRect(rectangle);
}
}

/// A rounded rectangle shape.
Expand All @@ -41,7 +48,14 @@ class RoundedRectangle extends Shape {

@override
void drawOnCanvas(Canvas canvas, Rect rectangle, Paint paint) {
canvas.drawRRect(RRect.fromRectAndRadius(rectangle.inflate(spreadRadius), radius), paint);
canvas.drawRRect(
RRect.fromRectAndRadius(rectangle.inflate(spreadRadius), radius),
paint);
}

@override
void makePath(Path path, Rect rectangle) {
path.addRRect(RRect.fromRectAndRadius(rectangle, radius));
}
}

Expand All @@ -59,6 +73,11 @@ class Oval extends Shape {
void drawOnCanvas(Canvas canvas, Rect rectangle, Paint paint) {
canvas.drawOval(rectangle.inflate(spreadRadius), paint);
}

@override
void makePath(Path path, Rect rectangle) {
path.addOval(rectangle.inflate(spreadRadius));
}
}

/// A circle shape.
Expand All @@ -76,4 +95,11 @@ class Circle extends Shape {
Rect circle = rectangle.inflate(spreadRadius);
canvas.drawCircle(circle.center, circle.longestSide / 2, paint);
}

@override
void makePath(Path path, Rect rectangle) {
path.addOval(
Rect.fromCircle(center: rectangle.center, radius: rectangle.width / 2),
);
}
}
39 changes: 31 additions & 8 deletions lib/src/showcase.dart
Expand Up @@ -29,7 +29,7 @@ class BubbleShowcase extends StatefulWidget {
final bool showCloseButton;

// Duration by which delay showcase initialization.
final Duration initialDelay;
final Duration initialDelay;

/// Creates a new bubble showcase instance.
BubbleShowcase({
Expand All @@ -52,13 +52,15 @@ class BubbleShowcase extends StatefulWidget {
return true;
}
SharedPreferences preferences = await SharedPreferences.getInstance();
bool? result = preferences.getBool('$bubbleShowcaseId.$bubbleShowcaseVersion');
bool? result =
preferences.getBool('$bubbleShowcaseId.$bubbleShowcaseVersion');
return result == null || result;
}
}

/// The BubbleShowcase state.
class _BubbleShowcaseState extends State<BubbleShowcase> with WidgetsBindingObserver {
class _BubbleShowcaseState extends State<BubbleShowcase>
with WidgetsBindingObserver {
/// The current slide index.
int currentSlideIndex = -1;

Expand All @@ -79,7 +81,11 @@ class _BubbleShowcaseState extends State<BubbleShowcase> with WidgetsBindingObse
}

@override
Widget build(BuildContext context) => widget.child;
Widget build(BuildContext context) =>
NotificationListener<BubbleShowcaseNotification>(
onNotification: processNotification,
child: widget.child,
);

@override
void dispose() {
Expand All @@ -98,8 +104,16 @@ class _BubbleShowcaseState extends State<BubbleShowcase> with WidgetsBindingObse
});
}

bool processNotification(BubbleShowcaseNotification notif) {
if (isFinished) return true;
goToNextEntryOrClose(currentSlideIndex + 1);
return true;
}

/// Returns whether the showcasing is finished.
bool get isFinished => currentSlideIndex == -1 || currentSlideIndex == widget.bubbleSlides.length;
bool get isFinished =>
currentSlideIndex == -1 ||
currentSlideIndex == widget.bubbleSlides.length;

/// Allows to go to the next entry (or to close the showcase if needed).
void goToNextEntryOrClose(int position) {
Expand All @@ -111,7 +125,9 @@ class _BubbleShowcaseState extends State<BubbleShowcase> with WidgetsBindingObse
currentSlideEntry = null;
if (widget.doNotReopenOnClose) {
SharedPreferences.getInstance().then((preferences) {
preferences.setBool('${widget.bubbleShowcaseId}.${widget.bubbleShowcaseVersion}', false);
preferences.setBool(
'${widget.bubbleShowcaseId}.${widget.bubbleShowcaseVersion}',
false);
});
}
} else {
Expand All @@ -135,7 +151,8 @@ class _BubbleShowcaseState extends State<BubbleShowcase> with WidgetsBindingObse

/// Allows to trigger enter callbacks.
void triggerOnEnter() {
if (currentSlideIndex >= 0 && currentSlideIndex < widget.bubbleSlides.length) {
if (currentSlideIndex >= 0 &&
currentSlideIndex < widget.bubbleSlides.length) {
VoidCallback? callback = widget.bubbleSlides[currentSlideIndex].onEnter;
if (callback != null) {
callback();
Expand All @@ -145,11 +162,17 @@ class _BubbleShowcaseState extends State<BubbleShowcase> with WidgetsBindingObse

/// Allows to trigger exit callbacks.
void triggerOnExit() {
if (currentSlideIndex >= 0 && currentSlideIndex < widget.bubbleSlides.length) {
if (currentSlideIndex >= 0 &&
currentSlideIndex < widget.bubbleSlides.length) {
VoidCallback? callback = widget.bubbleSlides[currentSlideIndex].onExit;
if (callback != null) {
callback();
}
}
}
}

/// Notification Used to tell the [BubbleShowcase] to continue the showcase
class BubbleShowcaseNotification extends Notification {
const BubbleShowcaseNotification();
}