FeatureDiscoveryService<E extends Object> class
Orchestrates feature-discovery tips. Parameterized on E — the consumer-
defined event type (typically an enum) whose values are emitted from
screens as emit(context, MyEvent.onFoo, ctx).
Usage (typically a single instance per app, held in a top-level final
or exposed through your DI / provider framework):
enum AppEvent { onStartupTick, onProductViewed }
final discovery = FeatureDiscoveryService<AppEvent>()
..registerAll([
DiscoveryTip<AppEvent>(
id: 'welcome_banner',
priority: DiscoveryPriority.standard,
triggers: {AppEvent.onStartupTick},
shouldShow: (ctx) async => ctx.appLaunches >= 2,
presentation: BannerPresentation(/* ... */),
),
]);
Priorities:
critical— always evaluated, ignores session lock, can chain with other critical tips in a single emit (e.g. permissions, data disclosures).standard/optional— respect the session lock; claim the lock and end the chain when they fire.tip— respects the session lock AND is suppressed by a held lock.
Only one non-critical tip runs per session-lock window. The lock is cleared automatically when onAppResumed detects a background long enough (see backgroundResetThreshold), or manually via resetSession.
Constructors
- FeatureDiscoveryService({Duration backgroundResetThreshold = const Duration(seconds: 10)})
Properties
- backgroundResetThreshold → Duration
-
How long the app must stay backgrounded before onAppResumed clears
the session lock. Short foregrounds (quickly checking a notification,
answering a call) should NOT re-open the tip queue.
final
- hashCode → int
-
The hash code for this object.
no setterinherited
- runtimeType → Type
-
A representation of the runtime type of the object.
no setterinherited
Methods
-
clear(
) → void - Drop every registered tip and reset internal state. Mainly for tests.
-
emit(
BuildContext context, E event, DiscoveryContext ctx) → Future< bool> -
Emit an event. Evaluates every tip whose
triggerscontainevent, in priority + order, and presents the first eligible one (or a chain of critical tips). -
noSuchMethod(
Invocation invocation) → dynamic -
Invoked when a nonexistent method or property is accessed.
inherited
-
onAppPaused(
) → void -
Record the moment the app went to background. Call from
WidgetsBindingObserver.didChangeAppLifecycleStateonAppLifecycleState.paused. -
onAppResumed(
) → void - On foreground resume, clear the session lock if the app was backgrounded for at least backgroundResetThreshold. Short foregrounds preserve the lock so a tip the user just dismissed doesn't re-fire mid-interaction.
-
register(
DiscoveryTip< E> tip) → void - Register a tip once at app start. Duplicate ids are ignored.
-
registerAll(
Iterable< DiscoveryTip< tips) → voidE> > -
Register every tip in
tips. Convenience for bulk registration. -
resetSession(
) → void - Manually clear the session lock so the next eligible non-critical tip can fire. Use when a lifecycle event outside the app's pause/resume cycle should re-open the tip queue (e.g. the user completed onboarding).
-
toString(
) → String -
A string representation of this object.
inherited
-
wasPresentedInCurrentEmit(
String tipId) → bool -
Whether
tipIdhas already been presented during the current emit call. Useful inside a tip'sshouldShowto avoid piling tips on top of one another within a single trigger.
Operators
-
operator ==(
Object other) → bool -
The equality operator.
inherited