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: false opens 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: true adds the player's own title + ✕ bar (off by default here).
  • placeholder: shows while the config loads on a cold start (default: a spinner). Eureel.isLoaded tells 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/config at 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 / showAgain brings 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 needs android:usesCleartextTraffic="true" on <application> in AndroidManifest.xml (debug only).
  • iOS simulator: http://localhost:8000 works; for a LAN IP add NSAppTransportSecurity → NSAllowsLocalNetworking = YES to Info.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.