Skip to content
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,8 @@ class _MailPageState extends State<MailPage> {
//Start showcase view after current widget frames are drawn.
WidgetsBinding.instance.addPostFrameCallback(
(_) => ShowcaseView.get().startShowCase(
[_firstShowcaseWidget, _two, _three, _four, _lastShowcaseWidget]),
[_firstShowcaseWidget, _two, _three, _four, _lastShowcaseWidget],
),
);
mails = [
Mail(
Expand Down Expand Up @@ -192,6 +193,8 @@ class _MailPageState extends State<MailPage> {
@override
void dispose() {
scrollController.dispose();
// Unregister the showcase view when the widget is disposed
ShowcaseView.get().unregister();
super.dispose();
}

Expand Down
11 changes: 11 additions & 0 deletions lib/src/models/action_button_icon.dart
Original file line number Diff line number Diff line change
Expand Up @@ -51,4 +51,15 @@ class ActionButtonIcon {

/// Optional padding to apply around the icon.
final EdgeInsets? padding;

@override
bool operator ==(Object other) {
if (identical(this, other)) return true;
return other is ActionButtonIcon &&
icon == other.icon &&
padding == other.padding;
}

@override
int get hashCode => Object.hash(icon, padding);
}
13 changes: 13 additions & 0 deletions lib/src/models/showcase_scope.dart
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
import 'package:flutter/foundation.dart';
import 'package:flutter/widgets.dart';

import '../showcase/showcase_controller.dart';
Expand Down Expand Up @@ -51,4 +52,16 @@ class ShowcaseScope {
/// - Key: GlobalKey of a showcase (provided by user)
/// - Value: Map of showcase IDs to their controllers
final Map<GlobalKey, Map<int, ShowcaseController>> controllers = {};

@override
bool operator ==(Object other) {
if (identical(this, other)) return true;
return other is ShowcaseScope &&
name == other.name &&
showcaseView == other.showcaseView &&
mapEquals(controllers, other.controllers);
}

@override
int get hashCode => Object.hash(name, showcaseView, controllers);
}
41 changes: 41 additions & 0 deletions lib/src/models/tooltip_action_button.dart
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';

import '../../showcaseview.dart';
Expand Down Expand Up @@ -126,4 +127,44 @@ class TooltipActionButton {
/// This only works for the global action widgets
/// Defaults to []
final List<GlobalKey> hideActionWidgetForShowcase;

@override
bool operator ==(Object other) {
if (identical(this, other)) return true;
return other is TooltipActionButton &&
other.type == type &&
other.borderRadius == borderRadius &&
other.padding == padding &&
other.backgroundColor == backgroundColor &&
other.textStyle == textStyle &&
other.leadIcon == leadIcon &&
other.tailIcon == tailIcon &&
other.name == name &&
other.button == button &&
other.border == border &&
listEquals(
other.hideActionWidgetForShowcase,
hideActionWidgetForShowcase,
);
}

@override
int get hashCode {
return Object.hashAllUnordered(
[
type,
borderRadius,
padding,
hideActionWidgetForShowcase,
backgroundColor,
textStyle,
leadIcon,
tailIcon,
name,
onTap,
button,
border,
],
);
}
}
24 changes: 23 additions & 1 deletion lib/src/models/tooltip_action_config.dart
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
*/
import 'package:flutter/material.dart';

import '../../showcaseview.dart';
import '../utils/enum.dart';

class TooltipActionConfig {
/// Configuration options for tooltip action buttons.
Expand Down Expand Up @@ -59,4 +59,26 @@ class TooltipActionConfig {
/// If aligning items according to their baseline, which baseline to use.
/// This must be set if using baseline alignment.
final TextBaseline? textBaseline;

@override
bool operator ==(Object other) {
if (identical(this, other)) return true;
return other is TooltipActionConfig &&
alignment == other.alignment &&
actionGap == other.actionGap &&
position == other.position &&
gapBetweenContentAndAction == other.gapBetweenContentAndAction &&
crossAxisAlignment == other.crossAxisAlignment &&
textBaseline == other.textBaseline;
}

@override
int get hashCode => Object.hashAllUnordered([
alignment,
actionGap,
position,
gapBetweenContentAndAction,
crossAxisAlignment,
textBaseline,
]);
}
15 changes: 10 additions & 5 deletions lib/src/showcase/showcase.dart
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ import 'package:flutter/material.dart';
import '../models/showcase_scope.dart';
import '../models/tooltip_action_button.dart';
import '../models/tooltip_action_config.dart';
import '../showcase_widget.dart';
import '../utils/constants.dart';
import '../utils/enum.dart';
import '../utils/overlay_manager.dart';
Expand Down Expand Up @@ -251,7 +250,7 @@ class Showcase extends StatefulWidget {
/// A key that is unique across the entire app.
///
/// This Key will be used to control state of individual showcase and also
/// used in [ShowcaseView.startShowcase] to define position of current
/// used in [ShowcaseView.setupShowcase] to define position of current
/// target widget while showcasing.
final GlobalKey showcaseKey;

Expand Down Expand Up @@ -573,7 +572,12 @@ class _ShowcaseState extends State<Showcase> {
// This is to support hot reload
_updateControllerValues();

_controller.recalculateRootWidgetSize(context);
_controller.recalculateRootWidgetSize(
context,
shouldUpdateOverlay:
_showCaseWidgetManager.showcaseView.getActiveShowcaseKey ==
widget.showcaseKey,
);
return widget.child;
}

Expand All @@ -584,14 +588,15 @@ class _ShowcaseState extends State<Showcase> {
id: _uniqueId,
scope: _showCaseWidgetManager.name,
);

super.dispose();
}

void _updateControllerValues() {
_showCaseWidgetManager = ShowcaseService.instance.getScope(
final manager = ShowcaseService.instance.getScope(
scope: _showCaseWidgetManager.name,
);
if (manager == _showCaseWidgetManager) return;
_showCaseWidgetManager = manager;
ShowcaseService.instance.addController(
controller: _controller
..showcaseView = _showCaseWidgetManager.showcaseView,
Expand Down
60 changes: 26 additions & 34 deletions lib/src/showcase/showcase_controller.dart
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import 'dart:math';
import 'package:flutter/foundation.dart';
import 'package:flutter/widgets.dart';

import '../models/linked_showcase_data.dart';
import '../models/linked_showcase_data_model.dart';
import '../models/tooltip_action_config.dart';
import '../tooltip/tooltip.dart';
import '../utils/overlay_manager.dart';
Expand Down Expand Up @@ -119,7 +119,7 @@ class ShowcaseController {
/// tree.
bool get _mounted => getState().mounted;

/// Callback to start the showcase.
/// Callback to setup the showcase.
///
/// Initializes the showcase by calculating positions and preparing visual
/// elements.
Expand All @@ -134,20 +134,16 @@ class ShowcaseController {
///
/// This method is typically called internally by the showcase system but
/// can also be called manually to force a recalculation of showcase elements.
void startShowcase() {
void setupShowcase({bool shouldUpdateOverlay = true}) {
if (!showcaseView.enableShowcase || !_mounted) return;

recalculateRootWidgetSize(_context);
recalculateRootWidgetSize(
_context,
shouldUpdateOverlay: shouldUpdateOverlay,
);
globalFloatingActionWidget = showcaseView
.getFloatingActionWidget(config.showcaseKey)
?.call(_context);
final size = rootWidgetSize ?? MediaQuery.sizeOf(_context);
position ??= TargetPositionService(
rootRenderObject: rootRenderObject,
screenSize: size,
renderBox: _context.findRenderObject() as RenderBox?,
padding: config.targetPadding,
);
}

/// Used to scroll the target into view.
Expand All @@ -165,32 +161,22 @@ class ShowcaseController {
///
/// Returns a Future that completes when scrolling is finished. If the widget
/// is unmounted during scrolling, the operation will be canceled safely.
Future<void> scrollIntoView() async {
Future<void> scrollIntoView({bool shouldUpdateOverlay = true}) async {
if (!_mounted) {
assert(_mounted, 'Widget has been unmounted');
return;
}

isScrollRunning = true;
updateControllerData();
startShowcase();
OverlayManager.instance.update(
show: showcaseView.isShowcaseRunning,
scope: showcaseView.scope,
);
setupShowcase(shouldUpdateOverlay: shouldUpdateOverlay);
await Scrollable.ensureVisible(
_context,
duration: showcaseView.scrollDuration,
alignment: config.scrollAlignment,
);

isScrollRunning = false;
updateControllerData();
startShowcase();
OverlayManager.instance.update(
show: showcaseView.isShowcaseRunning,
scope: showcaseView.scope,
);
setupShowcase(shouldUpdateOverlay: shouldUpdateOverlay);
}

/// Handles tap on barrier area.
Expand All @@ -214,20 +200,26 @@ class ShowcaseController {
///
/// Parameter:
/// * [context] The BuildContext of the [Showcase] widget.
void recalculateRootWidgetSize(BuildContext context) {
void recalculateRootWidgetSize(
BuildContext context, {
bool shouldUpdateOverlay = true,
}) {
if (!showcaseView.enableShowcase || !showcaseView.isShowcaseRunning) return;
WidgetsBinding.instance.addPostFrameCallback((_) {
if (!context.mounted) return;
if (!context.mounted ||
!showcaseView.enableShowcase ||
!showcaseView.isShowcaseRunning) {
return;
}

_initRootWidget();
if (!showcaseView.enableShowcase) return;

updateControllerData();
if (!showcaseView.isShowcaseRunning) return;

OverlayManager.instance.update(
show: showcaseView.isShowcaseRunning,
scope: showcaseView.scope,
);
if (shouldUpdateOverlay) {
OverlayManager.instance.update(
show: showcaseView.isShowcaseRunning,
scope: showcaseView.scope,
);
}
});
}

Expand Down
2 changes: 1 addition & 1 deletion lib/src/showcase/showcase_service.dart
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,11 @@
*/
import 'package:flutter/widgets.dart';

import '../../showcaseview.dart';
import '../models/showcase_scope.dart';
import '../utils/constants.dart';
import '../utils/extensions.dart';
import 'showcase_controller.dart';
import 'showcase_view.dart';

/// A scoped service locator for showcase functionality.
///
Expand Down
Loading