flutter_story_kit 0.1.3 copy "flutter_story_kit: ^0.1.3" to clipboard
flutter_story_kit: ^0.1.3 copied to clipboard

Lightweight Instagram-style Flutter stories: images, videos, YouTube and Facebook embeds, media preload, and tap-to-action callbacks.

flutter_story_kit #

Lightweight Instagram-style stories for Flutter: images, native videos, YouTube links, Facebook embeds, a horizontal tray, media preload, and callback-based call-to-action buttons.

The package stays small on purpose. It does not fetch your API, does not navigate to offers, and does not depend on GetX, Sizer, or Sentry. You own networking and navigation; the widget owns playback, gestures, and progress.

Story viewer Story tray Story action

Features #

  • Image, video, YouTube, and Facebook slides
  • Multi-slide stories with animated progress bars
  • Tap left / right, hold to pause, swipe between stories
  • Horizontal tray with seen / unseen gradient rings
  • Optional video + image preloader
  • CTA button with a typed StoryAction (link, offer, category, partner, …)
  • Story.fromMap compatible with typical { items: [...] } JSON
  • First-class YoutubeLink helpers (id, embed URL, thumbnail, watch URL)

Install #

dependencies:
  flutter_story_kit: ^0.1.3

Then:

flutter pub get

Platform setup #

video_player and webview_flutter need the usual platform config:

Android (android/app/src/main/AndroidManifest.xml):

<uses-permission android:name="android.permission.INTERNET"/>

iOS (ios/Runner/Info.plist) — allow HTTP only if you really need it:

<key>NSAppTransportSecurity</key>
<dict>
  <key>NSAllowsArbitraryLoads</key>
  <true/>
</dict>

YouTube and Facebook slides run inside a WebView. Test them on a real device; some embeds are blocked in simulators.

Quick start #

import 'package:flutter/material.dart';
import 'package:flutter_story_kit/flutter_story_kit.dart';

final stories = [
  Story(
    id: '1',
    title: 'Studio',
    thumbnailUrl: 'https://picsum.photos/200',
    media: [
      StoryMedia.image('https://picsum.photos/1080/1920', duration: Duration(seconds: 5)),
      StoryMedia.video('https://example.com/clip.mp4', duration: Duration(seconds: 12)),
      StoryMedia.youtube('https://youtu.be/dQw4w9WgXcQ', duration: Duration(seconds: 15)),
    ],
    action: StoryAction(type: 'link', url: 'https://flutter.dev'),
  ),
];

class Home extends StatelessWidget {
  const Home({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: SafeArea(
        child: StoryTray(
          stories: stories,
          onStoryTap: (index) {
            // Mark as seen on your backend here.
          },
        ),
      ),
    );
  }
}

StoryTray opens StoryViewer for you. For full control (preload, seen callback, CTA):

Navigator.of(context).push(
  MaterialPageRoute(
    builder: (_) => StoryViewer(
      stories: stories,
      initialIndex: index,
      preloader: preloader,
      onSeen: (story) {
        // POST /stories/:id/seen
      },
      onAction: (story, media, action) async {
        switch (action.normalizedType) {
          case 'link':
          case 'weblink':
            // open action.url in your webview
            break;
          case 'offre':
            // open your offer page with action.relatedId
            break;
        }
      },
    ),
  ),
);

YouTube is a first-class media kind, not a special case of Facebook. Pass any public URL:

StoryMedia.youtube('https://www.youtube.com/watch?v=VIDEO_ID');
StoryMedia.youtube('https://youtu.be/VIDEO_ID');
StoryMedia.youtube('https://www.youtube.com/shorts/VIDEO_ID');

Or use the helpers directly:

final id = YoutubeLink.videoId(url);          // 'dQw4w9WgXcQ'
final embed = YoutubeLink.embedUrl(url);      // autoplay + mute + playsinline
final thumb = YoutubeLink.thumbnailUrl(id!);  // hqdefault.jpg
final watch = YoutubeLink.watchUrl(id);

Embeds mute by default so mobile autoplay is allowed. Pass mute: false if you want sound (the user may have to tap).

Models #

Story(
  id: '42',
  title: 'Brand',
  thumbnailUrl: '...',
  seen: false,
  media: [StoryMedia.image('...'), StoryMedia.youtube('...')],
  action: StoryAction(type: 'weblink', url: 'https://...'),
  extra: {'adult_content': false}, // anything your app still needs
)

Parse a backend payload:

final stories = storiesFromResponse(jsonDecode(response.body));
// or
final story = Story.fromMap(map);

fromMap understands both:

  • { "video_url": "...", "duration": 5 }
  • { "items": [{ "media_type": "youtube", "media_url": "...", "duration": 15000 }] }

App-specific nested objects (offre, categorie, partenaire) are stored in Story.extra. CTA ids land on StoryAction.relatedId / StoryAction.data.

Preload #

final preloader = StoryPreloader();

await preloader.preload(stories, context: context);

// later, when leaving the home screen
await preloader.disposeAll();

Only native videos and images are warmed up. YouTube / Facebook cannot be preloaded with video_player.

Architecture (why it is small) #

This package Your app
Playback, gestures, progress API (http, auth, tokens)
Models + JSON parsing Mapping to your domain if needed
YouTube / Facebook embed URLs Opening offers, categories, webviews
Optional preloader When to preload / dispose

That split is what keeps the package publishable and reusable. Heavy app services (Sentry, GetX, your baseUrl) stay out.

Publish to pub.dev #

Source lives at github.com/Moettaz/oui_stories. From this folder:

dart pub publish --dry-run
dart pub publish

dry-run lists files that will be uploaded and the static analysis score. Fix warnings before the real publish. Packages cannot be deleted after publish, only discontinued, so start at 0.1.0.

Useful local checks:

dart format .
flutter analyze
flutter test

Example #

See example/ for a runnable demo with an image, a video, and a YouTube slide.

Author #

Created by Moatez Zaghdoudi.

License #

MIT © Moatez Zaghdoudi

1
likes
160
points
37
downloads
screenshot

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

Lightweight Instagram-style Flutter stories: images, videos, YouTube and Facebook embeds, media preload, and tap-to-action callbacks.

Repository (GitHub)
View/report issues

Topics

#stories #instagram #youtube #video #flutter

License

MIT (license)

Dependencies

cached_network_image, flutter, video_player, webview_flutter

More

Packages that depend on flutter_story_kit