tmdb_flutter 0.1.0 copy "tmdb_flutter: ^0.1.0" to clipboard
tmdb_flutter: ^0.1.0 copied to clipboard

A comprehensive Flutter package for TMDB (The Movie Database) integration with modern UI components, search, and metadata display.

example/lib/main.dart

// example/lib/main.dart - Update to include new features
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:tmdb_flutter/tmdb_flutter.dart';
import 'package:url_launcher/url_launcher.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart';

// Import providers

Future<void> main() async {
  // Initialize the TMDB Flutter package with your API key
  await dotenv.load(fileName: '.env');
  TmdbFlutter.init(apiKey: dotenv.env['TMDB_API_KEY'] ?? '');

  runApp(const MyApp());
}

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

  @override
  Widget build(BuildContext context) {
    return MultiProvider(
      providers: [
        ChangeNotifierProvider(create: (_) => SearchProvider()),
        ChangeNotifierProvider(create: (_) => TitleDetailsProvider()),
        ChangeNotifierProvider(create: (_) => SeasonEpisodesProvider()),
        ChangeNotifierProvider(create: (_) => PersonProvider()),
        ChangeNotifierProvider(create: (_) => GenreProvider()),
        ChangeNotifierProvider(create: (_) => DiscoveryProvider()),
      ],
      child: MaterialApp(
        debugShowCheckedModeBanner: false,
        title: 'TMDB Flutter Example',
        theme: ThemeData(
          primarySwatch: Colors.blue,
          useMaterial3: true,
        ),
        home: const HomePage(),
      ),
    );
  }
}

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

  @override
  State<HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  int _currentIndex = 0;

  final List<Widget> _pages = [
    const DiscoveryPage(),
    const SearchPage(),
    const GenresPage(),
  ];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('TMDB Flutter Demo'),
      ),
      body: _pages[_currentIndex],
      bottomNavigationBar: BottomNavigationBar(
        currentIndex: _currentIndex,
        onTap: (index) {
          setState(() {
            _currentIndex = index;
          });
        },
        items: const [
          BottomNavigationBarItem(
            icon: Icon(Icons.home),
            label: 'Discover',
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.search),
            label: 'Search',
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.category),
            label: 'Genres',
          ),
        ],
      ),
    );
  }
}

/// Discovery page for trending and popular content
class DiscoveryPage extends StatelessWidget {
  const DiscoveryPage({super.key});

  @override
  Widget build(BuildContext context) {
    return TmdbDiscoveryWidget(
      onTitleSelected: (title) {
        Navigator.push(
          context,
          MaterialPageRoute(
            builder: (context) => TitleDetailsPage(
              titleId: title.id,
              titleType: title.type,
            ),
          ),
        );
      },
    );
  }
}

/// Search page for finding content
class SearchPage extends StatefulWidget {
  const SearchPage({super.key});

  @override
  State<SearchPage> createState() => _SearchPageState();
}

class _SearchPageState extends State<SearchPage> {
  TmdbTitle? _selectedTitle;
  String _searchQuery = '';
  TmdbSearchCategory _searchCategory = TmdbSearchCategory.multi;
  bool _showSearchResults = false;

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        // Search bar - fixed at the top
        Padding(
          padding: const EdgeInsets.all(16.0),
          child: TmdbSearchBar(
            onTitleSelected: (title) {
              setState(() {
                _selectedTitle = title;
              });

              // Navigate to details page
              Navigator.push(
                context,
                MaterialPageRoute(
                  builder: (context) => TitleDetailsPage(
                    titleId: title.id,
                    titleType: title.type,
                  ),
                ),
              );
            },
            onSearchCleared: () {
              setState(() {
                _selectedTitle = null;
                _showSearchResults = false;
                _searchQuery = '';
              });
            },
            // Handle Enter key press with onSearchSubmitted
            onSearchSubmitted: (query, category) {
              setState(() {
                _searchQuery = query;
                _searchCategory = category;
                _showSearchResults = true;
              });
            },
          ),
        ),

        // Content - takes remaining screen space with lazy loading
        Expanded(
          child: _buildContent(),
        ),
      ],
    );
  }

  Widget _buildContent() {
    // Show search results either when Enter key was pressed or a title was selected
    if (_showSearchResults || _selectedTitle != null) {
      final query = _selectedTitle?.name ?? _searchQuery;
      final category = _selectedTitle != null
          ? (_selectedTitle!.type == TmdbTitleType.movie
              ? TmdbSearchCategory.movie
              : TmdbSearchCategory.tv)
          : _searchCategory;

      // Use the updated lazy loading search results widget
      return TmdbSearchResults(
        query: query,
        category: category,
        scrollable: true, // Enable scrolling
        scrollThreshold: 0.8, // Load more when 80% scrolled
        onTitleSelected: (title) {
          Navigator.push(
            context,
            MaterialPageRoute(
              builder: (context) => TitleDetailsPage(
                titleId: title.id,
                titleType: title.type,
              ),
            ),
          );
        },
      );
    } else {
      // Show a placeholder when no search has been performed
      return const Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Icon(Icons.search, size: 64, color: Colors.grey),
            SizedBox(height: 16),
            Text(
              'Search for a movie or TV show',
              style: TextStyle(fontSize: 18, color: Colors.grey),
            ),
            SizedBox(height: 8),
            Text(
              'Press Enter or select a suggestion to see results',
              style: TextStyle(fontSize: 14, color: Colors.grey),
            ),
          ],
        ),
      );
    }
  }
}

/// Genres page for browsing by genre
class GenresPage extends StatelessWidget {
  const GenresPage({super.key});

  @override
  Widget build(BuildContext context) {
    return TmdbGenreSearch(
      onTitleSelected: (title) {
        Navigator.push(
          context,
          MaterialPageRoute(
            builder: (context) => TitleDetailsPage(
              titleId: title.id,
              titleType: title.type,
            ),
          ),
        );
      },
    );
  }
}

/// Title details page
class TitleDetailsPage extends StatelessWidget {
  final int titleId;
  final TmdbTitleType titleType;

  const TitleDetailsPage({
    super.key,
    required this.titleId,
    required this.titleType,
  });

  @override
  Widget build(BuildContext context) {
    // Reset the providers for a fresh state
    WidgetsBinding.instance.addPostFrameCallback((_) {
      Provider.of<TitleDetailsProvider>(context, listen: false)
          .loadTitleDetails(titleId, titleType);
    });

    return Scaffold(
      body: TmdbTitleDetailsWidget(
        titleId: titleId,
        titleType: titleType,
        onSimilarTitleSelected: (id, type) {
          Navigator.push(
            context,
            MaterialPageRoute(
              builder: (context) => TitleDetailsPage(
                titleId: id,
                titleType: type,
              ),
            ),
          );
        },
        onCastMemberSelected: (personId) {
          Navigator.push(
            context,
            MaterialPageRoute(
              builder: (context) => PersonDetailsPage(
                personId: personId,
              ),
            ),
          );
        },
        onTrailerTap: (trailerUrl) async {
          final url = Uri.parse(trailerUrl);
          try {
            // Force using external browser instead of in-app webview
            await launchUrl(
              url,
              mode: LaunchMode.externalApplication,
            );
          } catch (e) {
            if (context.mounted) {
              ScaffoldMessenger.of(context).showSnackBar(
                SnackBar(content: Text('Could not open trailer: $e')),
              );
            }
          }
        },
      ),
    );
  }
}

/// Person details page
class PersonDetailsPage extends StatelessWidget {
  final int personId;

  const PersonDetailsPage({
    super.key,
    required this.personId,
  });

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Person Details'),
      ),
      body: TmdbPersonDetailsWidget(
        personId: personId,
        onTitleSelected: (title) {
          Navigator.push(
            context,
            MaterialPageRoute(
              builder: (context) => TitleDetailsPage(
                titleId: title.id,
                titleType: title.type,
              ),
            ),
          );
        },
      ),
    );
  }
}
1
likes
150
points
33
downloads

Publisher

unverified uploader

Weekly Downloads

A comprehensive Flutter package for TMDB (The Movie Database) integration with modern UI components, search, and metadata display.

Homepage

Documentation

API reference

License

MIT (license)

Dependencies

cached_network_image, flutter, flutter_rating_bar, http, provider

More

Packages that depend on tmdb_flutter