From 74ffd08c8d41a1746eca09bc98336e02f880f158 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ju=CC=81lio=20Reis?= Date: Wed, 4 Sep 2024 17:20:52 -0300 Subject: [PATCH 1/3] global dismiss showcase --- example/ios/Flutter/AppFrameworkInfo.plist | 2 +- example/ios/Runner.xcodeproj/project.pbxproj | 13 +- .../xcshareddata/xcschemes/Runner.xcscheme | 2 +- example/ios/Runner/Info.plist | 2 + example/lib/main.dart | 26 +- lib/src/showcase.dart | 1 + lib/src/showcase_widget.dart | 39 +-- lib/src/tooltip_widget.dart | 231 +++++++++--------- 8 files changed, 175 insertions(+), 141 deletions(-) diff --git a/example/ios/Flutter/AppFrameworkInfo.plist b/example/ios/Flutter/AppFrameworkInfo.plist index 9625e105..7c569640 100644 --- a/example/ios/Flutter/AppFrameworkInfo.plist +++ b/example/ios/Flutter/AppFrameworkInfo.plist @@ -21,6 +21,6 @@ CFBundleVersion 1.0 MinimumOSVersion - 11.0 + 12.0 diff --git a/example/ios/Runner.xcodeproj/project.pbxproj b/example/ios/Runner.xcodeproj/project.pbxproj index 18c726a3..586e568d 100644 --- a/example/ios/Runner.xcodeproj/project.pbxproj +++ b/example/ios/Runner.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 50; + objectVersion = 54; objects = { /* Begin PBXBuildFile section */ @@ -136,7 +136,7 @@ 97C146E61CF9000F007C117D /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 1300; + LastUpgradeCheck = 1510; ORGANIZATIONNAME = "The Chromium Authors"; TargetAttributes = { 97C146ED1CF9000F007C117D = { @@ -181,10 +181,12 @@ /* Begin PBXShellScriptBuildPhase section */ 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; buildActionMask = 2147483647; files = ( ); inputPaths = ( + "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}", ); name = "Thin Binary"; outputPaths = ( @@ -195,6 +197,7 @@ }; 9740EEB61CF901F6004384FC /* Run Script */ = { isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; buildActionMask = 2147483647; files = ( ); @@ -280,7 +283,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 11.0; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; TARGETED_DEVICE_FAMILY = "1,2"; @@ -359,7 +362,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 11.0; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -406,7 +409,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 11.0; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; diff --git a/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index f1560181..a00db7a9 100644 --- a/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -1,6 +1,6 @@ CADisableMinimumFrameDurationOnPhone + UIApplicationSupportsIndirectInputEvents + diff --git a/example/lib/main.dart b/example/lib/main.dart index 950c78c6..a7182fb3 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -5,10 +5,13 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:showcaseview/showcaseview.dart'; -void main() => runApp(const MyApp()); +void main() => runApp(MyApp()); class MyApp extends StatelessWidget { - const MyApp({Key? key}) : super(key: key); + MyApp({Key? key}) : super(key: key); + + final GlobalKey _myWidgetKey = + GlobalKey(); @override Widget build(BuildContext context) { @@ -20,6 +23,15 @@ class MyApp extends StatelessWidget { debugShowCheckedModeBanner: false, home: Scaffold( body: ShowCaseWidget( + key: _myWidgetKey, + skipShowcaseWidget: Positioned( + bottom: 10, + left: 10, + child: ElevatedButton( + child: const Text('Skip Showcase'), + onPressed: () => _myWidgetKey.currentState?.dismiss(), + ), + ), onStart: (index, key) { log('onStart: $index, $key'); }, @@ -214,14 +226,14 @@ class _MailPageState extends State { ), ), Showcase( - targetPadding: const EdgeInsets.all(5), + // targetPadding: const EdgeInsets.all(5), key: _two, - title: 'Profile', + // title: 'Profile', description: "Tap to see profile which contains user's name, profile picture, mobile number and country", - tooltipBackgroundColor: Theme.of(context).primaryColor, - textColor: Colors.white, - targetShapeBorder: const CircleBorder(), + // tooltipBackgroundColor: Theme.of(context).primaryColor, + // textColor: Colors.white, + // targetShapeBorder: const CircleBorder(), child: Container( padding: const EdgeInsets.all(5), width: 45, diff --git a/lib/src/showcase.dart b/lib/src/showcase.dart index 1779f98b..c589feb3 100644 --- a/lib/src/showcase.dart +++ b/lib/src/showcase.dart @@ -612,6 +612,7 @@ class _ShowcaseState extends State { tooltipBackgroundColor: widget.tooltipBackgroundColor, textColor: widget.textColor, showArrow: widget.showArrow, + staticContainer: showCaseWidgetState.skipShowcaseWidget, contentHeight: widget.height, contentWidth: widget.width, onTooltipTap: _getOnTooltipTap, diff --git a/lib/src/showcase_widget.dart b/lib/src/showcase_widget.dart index 16168ba6..d5cc3b1a 100644 --- a/lib/src/showcase_widget.dart +++ b/lib/src/showcase_widget.dart @@ -27,6 +27,8 @@ import '../showcaseview.dart'; class ShowCaseWidget extends StatefulWidget { final WidgetBuilder builder; + final Positioned? skipShowcaseWidget; + /// Triggered when all the showcases are completed. final VoidCallback? onFinish; @@ -83,22 +85,25 @@ class ShowCaseWidget extends StatefulWidget { /// Enable/disable showcase globally. Enabled by default. final bool enableShowcase; - const ShowCaseWidget({ - required this.builder, - this.onFinish, - this.onStart, - this.onComplete, - this.autoPlay = false, - this.autoPlayDelay = const Duration(milliseconds: 2000), - this.enableAutoPlayLock = false, - this.blurValue = 0, - this.scrollDuration = const Duration(milliseconds: 300), - this.disableMovingAnimation = false, - this.disableScaleAnimation = false, - this.enableAutoScroll = false, - this.disableBarrierInteraction = false, - this.enableShowcase = true, - }); + const ShowCaseWidget( + {required this.builder, + this.onFinish, + this.onStart, + this.onComplete, + this.autoPlay = false, + this.autoPlayDelay = const Duration(milliseconds: 2000), + this.enableAutoPlayLock = false, + this.blurValue = 0, + this.scrollDuration = const Duration(milliseconds: 300), + this.disableMovingAnimation = false, + this.disableScaleAnimation = false, + this.enableAutoScroll = false, + this.disableBarrierInteraction = false, + this.enableShowcase = true, + this.skipShowcaseWidget, + super.key}); + + void dismiss() {} static GlobalKey? activeTargetWidget(BuildContext context) { return context @@ -149,6 +154,8 @@ class ShowCaseWidgetState extends State { /// Returns value of [ShowCaseWidget.blurValue] double get blurValue => widget.blurValue; + get skipShowcaseWidget => widget.skipShowcaseWidget; + @override void initState() { super.initState(); diff --git a/lib/src/tooltip_widget.dart b/lib/src/tooltip_widget.dart index dba238a2..b58c60ce 100644 --- a/lib/src/tooltip_widget.dart +++ b/lib/src/tooltip_widget.dart @@ -63,6 +63,7 @@ class ToolTipWidget extends StatefulWidget { final TextDirection? titleTextDirection; final TextDirection? descriptionTextDirection; final double toolTipSlideEndDistance; + final Widget? staticContainer; const ToolTipWidget({ super.key, @@ -97,6 +98,7 @@ class ToolTipWidget extends StatefulWidget { this.titleTextDirection, this.descriptionTextDirection, this.toolTipSlideEndDistance = 7, + this.staticContainer, }); @override @@ -365,131 +367,138 @@ class _ToolTipWidgetState extends State } if (widget.container == null) { - return Positioned( - top: contentY, - left: _getLeft(), - right: _getRight(), - child: ScaleTransition( - scale: _scaleAnimation, - alignment: widget.scaleAnimationAlignment ?? - Alignment( - _getAlignmentX(), - _getAlignmentY(), - ), - child: FractionalTranslation( - translation: Offset(0.0, contentFractionalOffset as double), - child: ToolTipSlideTransition( - position: Tween( - begin: Offset.zero, - end: Offset( - 0, - widget.toolTipSlideEndDistance * contentOffsetMultiplier, - ), - ).animate(_movingAnimation), - child: Material( - type: MaterialType.transparency, - child: Container( - padding: widget.showArrow - ? EdgeInsets.only( - top: paddingTop - (isArrowUp ? arrowHeight : 0), - bottom: paddingBottom - (isArrowUp ? 0 : arrowHeight), - ) - : null, - child: Stack( - alignment: isArrowUp - ? Alignment.topLeft - : _getLeft() == null - ? Alignment.bottomRight - : Alignment.bottomLeft, - children: [ - if (widget.showArrow) - Positioned( - left: _getArrowLeft(arrowWidth), - right: _getArrowRight(arrowWidth), - child: CustomPaint( - painter: _Arrow( - strokeColor: widget.tooltipBackgroundColor!, - strokeWidth: 10, - paintingStyle: PaintingStyle.fill, - isUpArrow: isArrowUp, + return Stack( + children: [ + Positioned( + top: contentY, + left: _getLeft(), + right: _getRight(), + child: ScaleTransition( + scale: _scaleAnimation, + alignment: widget.scaleAnimationAlignment ?? + Alignment( + _getAlignmentX(), + _getAlignmentY(), + ), + child: FractionalTranslation( + translation: Offset(0.0, contentFractionalOffset as double), + child: ToolTipSlideTransition( + position: Tween( + begin: Offset.zero, + end: Offset( + 0, + widget.toolTipSlideEndDistance * contentOffsetMultiplier, + ), + ).animate(_movingAnimation), + child: Material( + type: MaterialType.transparency, + child: Container( + padding: widget.showArrow + ? EdgeInsets.only( + top: paddingTop - (isArrowUp ? arrowHeight : 0), + bottom: + paddingBottom - (isArrowUp ? 0 : arrowHeight), + ) + : null, + child: Stack( + alignment: isArrowUp + ? Alignment.topLeft + : _getLeft() == null + ? Alignment.bottomRight + : Alignment.bottomLeft, + children: [ + if (widget.showArrow) + Positioned( + left: _getArrowLeft(arrowWidth), + right: _getArrowRight(arrowWidth), + child: CustomPaint( + painter: _Arrow( + strokeColor: widget.tooltipBackgroundColor!, + strokeWidth: 10, + paintingStyle: PaintingStyle.fill, + isUpArrow: isArrowUp, + ), + child: const SizedBox( + height: arrowHeight, + width: arrowWidth, + ), + ), ), - child: const SizedBox( - height: arrowHeight, - width: arrowWidth, + Padding( + padding: EdgeInsets.only( + top: isArrowUp ? arrowHeight - 1 : 0, + bottom: isArrowUp ? 0 : arrowHeight - 1, ), - ), - ), - Padding( - padding: EdgeInsets.only( - top: isArrowUp ? arrowHeight - 1 : 0, - bottom: isArrowUp ? 0 : arrowHeight - 1, - ), - child: ClipRRect( - borderRadius: widget.tooltipBorderRadius ?? - BorderRadius.circular(8.0), - child: GestureDetector( - onTap: widget.onTooltipTap, - child: Container( - width: tooltipWidth, - padding: widget.tooltipPadding, - color: widget.tooltipBackgroundColor, - child: Column( - crossAxisAlignment: widget.title != null - ? CrossAxisAlignment.start - : CrossAxisAlignment.center, - children: [ - if (widget.title != null) - Padding( - padding: widget.titlePadding ?? - EdgeInsets.zero, - child: Text( - widget.title!, - textAlign: widget.titleAlignment, - textDirection: - widget.titleTextDirection, - style: widget.titleTextStyle ?? - Theme.of(context) - .textTheme - .titleLarge! - .merge( - TextStyle( - color: widget.textColor, + child: ClipRRect( + borderRadius: widget.tooltipBorderRadius ?? + BorderRadius.circular(8.0), + child: GestureDetector( + onTap: widget.onTooltipTap, + child: Container( + width: tooltipWidth, + padding: widget.tooltipPadding, + color: widget.tooltipBackgroundColor, + child: Column( + crossAxisAlignment: widget.title != null + ? CrossAxisAlignment.start + : CrossAxisAlignment.center, + children: [ + if (widget.title != null) + Padding( + padding: widget.titlePadding ?? + EdgeInsets.zero, + child: Text( + widget.title!, + textAlign: widget.titleAlignment, + textDirection: + widget.titleTextDirection, + style: widget.titleTextStyle ?? + Theme.of(context) + .textTheme + .titleLarge! + .merge( + TextStyle( + color: widget.textColor, + ), + ), + ), + ), + Padding( + padding: widget.descriptionPadding ?? + EdgeInsets.zero, + child: Text( + widget.description!, + textAlign: + widget.descriptionAlignment, + textDirection: + widget.descriptionTextDirection, + style: widget.descTextStyle ?? + Theme.of(context) + .textTheme + .titleSmall! + .merge( + TextStyle( + color: widget.textColor, + ), ), - ), + ), ), - ), - Padding( - padding: widget.descriptionPadding ?? - EdgeInsets.zero, - child: Text( - widget.description!, - textAlign: widget.descriptionAlignment, - textDirection: - widget.descriptionTextDirection, - style: widget.descTextStyle ?? - Theme.of(context) - .textTheme - .titleSmall! - .merge( - TextStyle( - color: widget.textColor, - ), - ), - ), + ], ), - ], + ), ), ), ), - ), + ], ), - ], + ), ), ), ), ), ), - ), + if (widget.staticContainer != null) ...[widget.staticContainer!], + ], ); } return Stack( From 197538ddcfba0feab0fa01a0edc8f88e2a71797e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ju=CC=81lio=20Reis?= Date: Wed, 4 Sep 2024 17:45:48 -0300 Subject: [PATCH 2/3] Update main.dart --- example/lib/main.dart | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/example/lib/main.dart b/example/lib/main.dart index a7182fb3..3eab8455 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -226,14 +226,14 @@ class _MailPageState extends State { ), ), Showcase( - // targetPadding: const EdgeInsets.all(5), + targetPadding: const EdgeInsets.all(5), key: _two, - // title: 'Profile', + title: 'Profile', description: "Tap to see profile which contains user's name, profile picture, mobile number and country", - // tooltipBackgroundColor: Theme.of(context).primaryColor, - // textColor: Colors.white, - // targetShapeBorder: const CircleBorder(), + tooltipBackgroundColor: Theme.of(context).primaryColor, + textColor: Colors.white, + targetShapeBorder: const CircleBorder(), child: Container( padding: const EdgeInsets.all(5), width: 45, From 1119e33f72d6f2c13cb68e24e7e47cc44a27f3c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ju=CC=81lio=20Reis?= Date: Wed, 4 Sep 2024 17:49:08 -0300 Subject: [PATCH 3/3] updated docs --- lib/src/showcase_widget.dart | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/src/showcase_widget.dart b/lib/src/showcase_widget.dart index d5cc3b1a..c0ce0909 100644 --- a/lib/src/showcase_widget.dart +++ b/lib/src/showcase_widget.dart @@ -27,6 +27,10 @@ import '../showcaseview.dart'; class ShowCaseWidget extends StatefulWidget { final WidgetBuilder builder; + /// Creates a button that can be used to skip showCase. For onTap: create a + /// global key (final showCaseKey = GlobalKey() + /// assign the key to ShowCaseWidget and use it like this: + /// onTap: () => showcaseKey.currentState?.dismiss(); final Positioned? skipShowcaseWidget; /// Triggered when all the showcases are completed.