eureel_flutter
Per-screen tutorial videos for Flutter apps — the Eureel SDK. Upload videos and map them to screens in the Eureel dashboard; this package shows them as a corner bubble that opens a full player with a playlist picker.
Install
flutter pub add eureel_flutter
The player uses the Cupertino icon font, so make sure your app also depends on cupertino_icons (new Flutter apps already do).
Set up
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await Eureel.init(
apiKey: 'pk_live_…', // Dashboard → Install
appId: 'com.example.app', // needed if the project restricts "Mobile app IDs"
);
runApp(const MyApp());
}
Show it on a screen
Add EureelOverlay as the last child of the screen's Stack:
Stack(children: [
const ProductsList(),
const EureelOverlay(screenKey: 'products'),
]);
"How to use" button
Users can close the bubble (✕). Add a EureelHelpButton so they can always play the tutorial again — it opens the player and brings the bubble back. It hides itself on screens without videos.
It's a normal widget, so put it anywhere — AppBar actions, a card, under a form, a menu:
const EureelHelpButton(screenKey: 'products') // outlined pill
const EureelHelpButton(screenKey: 'products', style: EureelHelpStyle.icon) // pill | filled | text | icon
EureelHelpButton(screenKey: 'products', icon: const Icon(Icons.help_outline)) // any widget as icon
const EureelHelpButton(screenKey: 'products', showIcon: false, label: 'Watch how')
Or float it over the screen — add it to the same Stack (taps around it pass through):
Stack(children: [
const ProductsList(),
const EureelOverlay(screenKey: 'products'),
const EureelHelpButton.floating(
screenKey: 'products',
alignment: Alignment.topRight, // any Alignment; default = bottom corner opposite the bubble
margin: EdgeInsets.all(16), // default = the bubble's insets
),
]);
EureelHelpButton(builder: (context, onPressed, label) => …) renders a completely custom button. From your own code: Eureel.play('products').
Ways to pick the screen:
EureelOverlay(screenKey: 'products') |
the screen's key in the dashboard |
EureelOverlay(route: '/products') |
matched against each screen's Flutter route |
EureelOverlay() |
uses the current route name (ModalRoute.of(context)?.settings.name) |
Nothing renders on screens without videos, so you can add it everywhere up front.
Open automatically (welcome video)
Open the player by itself the first time a user reaches a screen — e.g. Home right after sign-up:
const EureelOverlay(screenKey: 'home', autoOpen: true)
- First time on the device only (default).
autoOpenOnce: falseopens it every time. autoOpenDelay: Duration(seconds: 1)to wait longer after the screen appears.- Call
await Eureel.resetAutoOpen();on logout so the next user sees it again.
Inline player (e.g. a welcome video page)
EureelPlayer plays a dashboard screen's video inside your own layout — no bubble. It fills its parent, so you add the corners, padding and buttons. onCompleted fires when the video reaches the end, e.g. to reveal a Continue button:
class WelcomeVideoPage extends StatefulWidget {
const WelcomeVideoPage({super.key});
@override
State<WelcomeVideoPage> createState() => _WelcomeVideoPageState();
}
class _WelcomeVideoPageState extends State<WelcomeVideoPage> {
bool _done = false;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Welcome')),
body: SafeArea(
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
children: [
Expanded(
child: ClipRRect(
borderRadius: BorderRadius.circular(20),
child: EureelPlayer(
screenKey: 'welcome', // the screen's key in the dashboard
onCompleted: () => setState(() => _done = true),
empty: const Center(child: Text('No video yet')),
),
),
),
const SizedBox(height: 16),
if (_done)
SizedBox(
width: double.infinity,
child: FilledButton(
onPressed: () => Navigator.of(context).pushReplacementNamed('/home'),
child: const Text('Continue'),
),
),
],
),
),
),
);
}
}
- Plays immediately; at the end it stays on the last frame with a play button (tap replays). It never loops or closes itself.
showTopBar: trueadds the player's own title + ✕ bar (off by default here).placeholder:shows while the config loads on a cold start (default: a spinner).Eureel.isLoadedtells you whether a config has arrived at all.- Views count in the dashboard analytics for that screen, like the bubble.
- In the dashboard, create a screen with key
welcome(no route needed) and attach the video.
Styling: dashboard or code
The bubble uses the look set in Settings → Widget (color, size, corner, shape, help label). Code overrides win:
await Eureel.init(
apiKey: 'pk_live_…',
appearance: const EureelAppearance(
primaryColor: Color(0xFFE11D48),
bubbleSize: 96,
bubbleOnRight: false,
roundedBubble: true,
edgeInset: 24,
backdropBlur: 12, // blur behind the opened player (0 = none)
backdropColor: Colors.black12, // tint over it (Colors.transparent = none)
fullscreen: true, // opened player covers the whole app (false = rounded card)
// per screen: EureelOverlay(screenKey: 'home', fullscreen: true)
),
);
Other API
Eureel.identify(user.id); // analytics user id (never names/emails)
await Eureel.play('products'); // open the tutorial player now
await Eureel.showAgain('products'); // bring back a dismissed bubble (without opening)
await Eureel.showAllAgain(); // e.g. a "Replay tutorials" setting
await Eureel.refresh(); // force-refresh the config
How it behaves
- Config is fetched from
/v1/configat start-up, cached on the device (works offline), refreshed every 10 minutes and whenever the app returns to the foreground. Bubbles update in place. - Videos play the 720p MP4 rendition (
Eureel.init(preferHls: true)for HLS). - Events — bubble shown, opened, video started, 25/50/75 % progress, completed, dismissed, help clicked — are batched every 5 s and flushed when the app is backgrounded.
- Dismissal (the small ✕ on the bubble) is remembered per screen;
EureelHelpButton/Eureel.play/showAgainbrings it back. - If the workspace is over its monthly view limit, overlays hide themselves.
Local development
- Android emulator: your computer is
http://10.0.2.2:8000. Plain-HTTP needsandroid:usesCleartextTraffic="true"on<application>inAndroidManifest.xml(debug only). - iOS simulator:
http://localhost:8000works; for a LAN IP addNSAppTransportSecurity → NSAllowsLocalNetworking = YEStoInfo.plist.
Example app
cd example
flutter create . --platforms=ios,android # once, generates the platform folders
flutter run --dart-define=EUREEL_KEY=pk_live_xxx
It has /home, /products, /sales and /settings routes — set each screen's Flutter route in the dashboard to match.
Credits
The bubble and player are based on flutter_video_onboarding (MIT) — see THIRD_PARTY_LICENSE_flutter_video_onboarding.
Libraries
- eureel_flutter
- Eureel — per-screen tutorial videos for Flutter apps.