feed_player 0.0.1 copy "feed_player: ^0.0.1" to clipboard
feed_player: ^0.0.1 copied to clipboard

A reusable Flutter SDK for building and playing a media feed (video-first) with clean architecture and a minimal public API.

example/lib/main.dart

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

import 'comments_demo_screen.dart';

void main() {
  WidgetsFlutterBinding.ensureInitialized();
  FeedPlayer.initialize(
    const FeedConfig(
      baseUrl: 'https://api.example.com',
      apiKey: 'REPLACE_ME',
      feedEndpointPath: '/v1/feed',
    ),
  );
  runApp(const MyApp());
}

class DemoFeedRepository implements FeedRepository {
  @override
  Future<List<FeedItem>> fetchFeed({int limit = 20, String? cursor}) async {
    const urls = <String>[
      'https://user-images.githubusercontent.com/28951144/229373695-22f88f13-d18f-4288-9bf1-c3e078d83722.mp4',
      'https://user-images.githubusercontent.com/28951144/229373709-603a7a89-2105-4e1b-a5a5-a6c3567c9a59.mp4',
      'https://user-images.githubusercontent.com/28951144/229373716-76da0a4e-225a-44e4-9ee7-3e9006dbc3e3.mp4',
      'https://user-images.githubusercontent.com/28951144/229373718-86ce5e1d-d195-45d5-baa6-ef94041d0b90.mp4',
      'https://user-images.githubusercontent.com/28951144/229373720-14d69157-1a56-4a78-a2f4-d7a134d7c3e9.mp4',
      'https://user-images.githubusercontent.com/28951144/229373695-22f88f13-d18f-4288-9bf1-c3e078d83722.mp4',
      'https://user-images.githubusercontent.com/28951144/229373695-22f88f13-d18f-4288-9bf1-c3e078d83722.mp4',
      'https://user-images.githubusercontent.com/28951144/229373695-22f88f13-d18f-4288-9bf1-c3e078d83722.mp4',
      'https://user-images.githubusercontent.com/28951144/229373695-22f88f13-d18f-4288-9bf1-c3e078d83722.mp4',
      'https://user-images.githubusercontent.com/28951144/229373695-22f88f13-d18f-4288-9bf1-c3e078d83722.mp4',
    ];

    return List<FeedItem>.generate(
      urls.length,
      (i) => FeedItem(

        id: 'demo_$i',
        authorId: 'user_$i',
        authorAvatarUrl: 'https://i.pravatar.cc/150?img=${i + 10}',
        authorName: 'Demo Creator ${i + 1}',
        metaLine: 'Just now · Demo feed',
        caption:
            'Swipe like TikTok. Tap heart/comment/share on the right. '
            'Toggle the app bar button to switch to post cards.',
        isLiked: i.isEven,
        likeCount: 12 + i * 3,
        commentCount: 2 + i,
        shareCount: 1,
        viewCount: 480 + i * 42,
        media: [FeedMedia(type: FeedMediaType.video, url: urls[i])],
        raw: const {'source': 'demo'},
      ),
    );
  }
}

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Feed Player Example',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.green),
      ),
      home: const FeedHomePage(),
    );
  }
}

class FeedHomePage extends StatefulWidget {
  const FeedHomePage({super.key});

  @override
  State<FeedHomePage> createState() => _FeedHomePageState();
}

class _FeedHomePageState extends State<FeedHomePage> {
  bool _reelView = true;

  @override
  Widget build(BuildContext context) {
    final feed = FeedPlayerWidget(
      repository: DemoFeedRepository(),
      pageSize: 20,
      reelView: _reelView,
      padding: const EdgeInsets.all(12),
      postChrome: const FeedPostChromeOptions(
        hideEngagementWithoutCallbacks: true,
      ),
      postActions: FeedPostActions(
            onProfileTap: (ctx, item) {
              Navigator.of(ctx).push<void>(
                MaterialPageRoute<void>(
                  builder: (_) => ExampleProfilePage(item: item),
                ),
              );
            },
            onLikeTap: (ctx, item) {
              ScaffoldMessenger.of(ctx).showSnackBar(
                SnackBar(
                  content: Text('Like toggled for post ${item.id} — wire API'),
                ),
              );
            },
            onCommentTap: (ctx, item) {
              Navigator.of(ctx).push<void>(
                MaterialPageRoute<void>(
                  builder: (_) => CommentsDemoScreen(item: item),
                ),
              );
            },
            onShareTap: (ctx, item) {
              ScaffoldMessenger.of(
                ctx,
              ).showSnackBar(SnackBar(content: Text('Share post ${item.id}')));
            },
            onMoreTap: (ctx, item) {
              showModalBottomSheet<void>(
                context: ctx,
                showDragHandle: true,
                builder: (sheetCtx) {
                  return SafeArea(
                    child: Column(
                      mainAxisSize: MainAxisSize.min,
                      children: [
                        ListTile(
                          leading: const Icon(Icons.flag_outlined),
                          title: const Text('Report'),
                          onTap: () => Navigator.pop(sheetCtx),
                        ),
                        ListTile(
                          leading: const Icon(Icons.visibility_off_outlined),
                          title: const Text('Hide post'),
                          onTap: () => Navigator.pop(sheetCtx),
                        ),
                      ],
                    ),
                  );
                },
              );
            },
            onLikesSummaryTap: (ctx, item) {
              showModalBottomSheet<void>(
                context: ctx,
                showDragHandle: true,
                builder: (sheetCtx) {
                  return ListView.builder(
                    padding: const EdgeInsets.symmetric(vertical: 8),
                    itemCount: 8,
                    itemBuilder: (_, index) {
                      return ListTile(
                        leading: CircleAvatar(child: Text('${index + 1}')),
                        title: Text('Demo liker ${index + 1}'),
                        subtitle: const Text(
                          'Replace with your likes bottom sheet + API',
                        ),
                      );
                    },
                  );
                },
              );
            },
            onViewsTap: (ctx, item) {
              ScaffoldMessenger.of(ctx).showSnackBar(
                SnackBar(content: Text('Views detail for ${item.id}')),
              );
            },
          ),
    );

    return Scaffold(
      extendBodyBehindAppBar: _reelView,
      appBar: AppBar(
        backgroundColor: _reelView
            ? Colors.black.withValues(alpha: 0.35)
            : Theme.of(context).colorScheme.onPrimaryFixed,
        foregroundColor: _reelView ? Colors.white : null,
        elevation: _reelView ? 0 : null,
        title: Text(_reelView ? 'Reels (TikTok)' : 'Post feed'),
        actions: [
          IconButton(
            tooltip: _reelView ? 'Switch to post feed' : 'Switch to reels',
            icon: Icon(
              _reelView
                  ? Icons.view_agenda_outlined
                  : Icons.video_library_outlined,
            ),
            onPressed: () => setState(() => _reelView = !_reelView),
          ),
        ],
      ),
      body: _reelView ? feed : SafeArea(child: feed),
    );
  }
}

/// Stand-in for your profile route.
class ExampleProfilePage extends StatelessWidget {
  const ExampleProfilePage({super.key, required this.item});

  final FeedItem item;

  @override
  Widget build(BuildContext context) {
    final name = item.authorName ?? item.title ?? 'Profile';
    return Scaffold(
      appBar: AppBar(title: Text(name)),
      body: ListView(
        padding: const EdgeInsets.all(24),
        children: [
          Center(
            child: CircleAvatar(
              radius: 48,
              child: Text(
                name.isNotEmpty ? name[0].toUpperCase() : '?',
                style: const TextStyle(fontSize: 36),
              ),
            ),
          ),
          const SizedBox(height: 24),
          Text('authorId: ${item.authorId ?? '—'}'),
          const SizedBox(height: 8),
          Text('post id: ${item.id}'),
        ],
      ),
    );
  }
}
4
likes
150
points
91
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

A reusable Flutter SDK for building and playing a media feed (video-first) with clean architecture and a minimal public API.

Homepage

License

unknown (license)

Dependencies

flutter, http, media_kit, media_kit_libs_video, media_kit_video

More

Packages that depend on feed_player