reels_video_player 1.0.0 copy "reels_video_player: ^1.0.0" to clipboard
reels_video_player: ^1.0.0 copied to clipboard

A high-performance Flutter package for TikTok/Reels vertical video feeds with background pre-caching, session rotation, and 100% customizable UI.

example/lib/main.dart

import 'package:flutter/material.dart';
import 'package:reels_video_player/reels_video_player.dart';
import 'package:video_player/video_player.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await ReelsCacheManager.init();
  // Clear old session storage once to remove legacy test URLs
  await SessionVideoStore.clearSessionStore();
  runApp(const ReelsExampleApp());
}

/// Main entry point for the Reels video player example app.
class ReelsExampleApp extends StatelessWidget {
  /// Creates a new [ReelsExampleApp] widget instance.
  const ReelsExampleApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Reels Video Player Example',
      debugShowCheckedModeBanner: false,
      theme: ThemeData.dark(useMaterial3: true),
      home: const ReelsFeedScreen(),
    );
  }
}

/// Feed screen demonstrating [ReelsViewer] usage with custom social overlays.
class ReelsFeedScreen extends StatefulWidget {
  /// Creates a new [ReelsFeedScreen] widget instance.
  const ReelsFeedScreen({super.key});

  @override
  State<ReelsFeedScreen> createState() => _ReelsFeedScreenState();
}

class _ReelsFeedScreenState extends State<ReelsFeedScreen> {
  final List<ReelsVideoItem> _sampleVideos = const <ReelsVideoItem>[
    ReelsVideoItem(
      id: 'reel_1',
      videoUrl: 'https://flutter.github.io/assets-for-api-docs/assets/videos/bee.mp4',
      thumbnailUrl: 'https://images.unsplash.com/photo-1518709268805-4e9042af9f23?w=800',
      metadata: <String, dynamic>{
        'username': '@flutter_dev',
        'caption': 'Honeybee buzzing on yellow flowers 🐝 #flutter #nature',
        'likes': 1240,
        'comments': 86,
      },
    ),
    ReelsVideoItem(
      id: 'reel_2',
      videoUrl: 'https://flutter.github.io/assets-for-api-docs/assets/videos/butterfly.mp4',
      thumbnailUrl: 'https://images.unsplash.com/photo-1507525428034-b723cf961d3e?w=800',
      metadata: <String, dynamic>{
        'username': '@nature_explorer',
        'caption': 'Beautiful monarch butterfly in nature 🦋 #nature #travel',
        'likes': 4520,
        'comments': 312,
      },
    ),
    ReelsVideoItem(
      id: 'reel_3',
      videoUrl: 'https://interactive-examples.mdn.mozilla.net/media/cc0-videos/flower.mp4',
      thumbnailUrl: 'https://images.unsplash.com/photo-1534447677768-be436bb09401?w=800',
      metadata: <String, dynamic>{
        'username': '@flower_power',
        'caption': 'Blooming spring flowers macro video 🌸 #flowers #nature',
        'likes': 8930,
        'comments': 540,
      },
    ),
    ReelsVideoItem(
      id: 'reel_4',
      videoUrl: 'https://www.w3schools.com/html/mov_bbb.mp4',
      thumbnailUrl: 'https://images.unsplash.com/photo-1518709268805-4e9042af9f23?w=800',
      metadata: <String, dynamic>{
        'username': '@animation_world',
        'caption': 'Big Buck Bunny open animation clip 🐰 #animation #open_source',
        'likes': 3100,
        'comments': 195,
      },
    ),
  ];

  final Map<String, bool> _likedMap = <String, bool>{};

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.black,
      body: Stack(
        children: <Widget>[
          ReelsViewer(
            videos: _sampleVideos,
            preCacheBefore: 1,
            preCacheAfter: 5,
            enableSessionRotation: true,
            maxPersistedSessionVideos: 10,
            onPageChanged: (int index) {
              debugPrint('Active reel page changed to index: $index');
            },

            // Interactive Bottom Progress Bar Scrubber
            progressBarBuilder: (BuildContext context, VideoPlayerController controller) {
              return ReelsProgressBar(
                controller: controller,
                playedColor: Colors.redAccent,
                bufferedColor: Colors.white38,
                backgroundColor: Colors.white12,
                barHeight: 4.0,
                allowScrubbing: true,
              );
            },

            // Social Overlay (Likes, Comments, Captions, Profile)
            overlayBuilder: (BuildContext context, VideoPlayerController controller, ReelsVideoItem item) {
              final Map<String, dynamic>? meta = item.metadata;
              final String username = meta?['username'] as String? ?? '@user';
              final String caption = meta?['caption'] as String? ?? '';
              final int likes = meta?['likes'] as int? ?? 0;
              final int comments = meta?['comments'] as int? ?? 0;
              final bool isLiked = _likedMap[item.id] ?? false;

              return Positioned.fill(
                child: SafeArea(
                  child: Padding(
                    padding: const EdgeInsets.only(left: 16.0, right: 16.0, top: 16.0, bottom: 36.0),
                    child: Row(
                      crossAxisAlignment: CrossAxisAlignment.end,
                      children: <Widget>[
                        // Left Column: User details and caption
                        Expanded(
                          child: Column(
                            mainAxisAlignment: MainAxisAlignment.end,
                            crossAxisAlignment: CrossAxisAlignment.start,
                            children: <Widget>[
                              Row(
                                children: <Widget>[
                                  const CircleAvatar(
                                    radius: 18,
                                    backgroundColor: Colors.white24,
                                    child: Icon(Icons.person, color: Colors.white, size: 20),
                                  ),
                                  const SizedBox(width: 10),
                                  Text(
                                    username,
                                    style: const TextStyle(
                                      color: Colors.white,
                                      fontWeight: FontWeight.bold,
                                      fontSize: 16,
                                    ),
                                  ),
                                  const SizedBox(width: 10),
                                  OutlinedButton(
                                    onPressed: () {},
                                    style: OutlinedButton.styleFrom(
                                      side: const BorderSide(color: Colors.white),
                                      padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 0),
                                      minimumSize: Size.zero,
                                      tapTargetSize: MaterialTapTargetSize.shrinkWrap,
                                    ),
                                    child: const Text(
                                      'Follow',
                                      style: TextStyle(color: Colors.white, fontSize: 12),
                                    ),
                                  ),
                                ],
                              ),
                              const SizedBox(height: 10),
                              Text(
                                caption,
                                maxLines: 2,
                                overflow: TextOverflow.ellipsis,
                                style: const TextStyle(color: Colors.white, fontSize: 14),
                              ),
                            ],
                          ),
                        ),

                        // Right Column: Social Action Buttons (Likes, Comments, Share)
                        Column(
                          mainAxisAlignment: MainAxisAlignment.end,
                          children: <Widget>[
                            // Like Button
                            GestureDetector(
                              onTap: () {
                                setState(() {
                                  _likedMap[item.id] = !isLiked;
                                });
                              },
                              child: Column(
                                children: <Widget>[
                                  Icon(
                                    isLiked ? Icons.favorite : Icons.favorite_border,
                                    color: isLiked ? Colors.redAccent : Colors.white,
                                    size: 32,
                                  ),
                                  const SizedBox(height: 4),
                                  Text(
                                    '${likes + (isLiked ? 1 : 0)}',
                                    style: const TextStyle(color: Colors.white, fontSize: 12),
                                  ),
                                ],
                              ),
                            ),
                            const SizedBox(height: 20),

                            // Comments Button
                            Column(
                              children: <Widget>[
                                const Icon(Icons.comment, color: Colors.white, size: 30),
                                const SizedBox(height: 4),
                                Text(
                                  '$comments',
                                  style: const TextStyle(color: Colors.white, fontSize: 12),
                                ),
                              ],
                            ),
                            const SizedBox(height: 20),

                            // Share Button
                            const Column(
                              children: <Widget>[
                                Icon(Icons.share, color: Colors.white, size: 30),
                                SizedBox(height: 4),
                                Text(
                                  'Share',
                                  style: TextStyle(color: Colors.white, fontSize: 12),
                                ),
                              ],
                            ),
                            const SizedBox(height: 24),
                          ],
                        ),
                      ],
                    ),
                  ),
                ),
              );
            },
          ),

          // Header Overlay Title
          const Positioned(
            top: 0,
            left: 0,
            right: 0,
            child: SafeArea(
              child: Padding(
                padding: EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0),
                child: Row(
                  mainAxisAlignment: MainAxisAlignment.center,
                  children: <Widget>[
                    Text(
                      'Reels Feed',
                      style: TextStyle(
                        color: Colors.white,
                        fontSize: 18,
                        fontWeight: FontWeight.bold,
                        shadows: <Shadow>[
                          Shadow(blurRadius: 4, color: Colors.black54),
                        ],
                      ),
                    ),
                  ],
                ),
              ),
            ),
          ),
        ],
      ),
    );
  }
}
2
likes
160
points
64
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

A high-performance Flutter package for TikTok/Reels vertical video feeds with background pre-caching, session rotation, and 100% customizable UI.

Repository (GitHub)
View/report issues

License

MIT (license)

Dependencies

flutter, http_cache_stream, path_provider, shared_preferences, video_player

More

Packages that depend on reels_video_player