Giter Club home page Giter Club logo

tmdb_movie_app_riverpod's Introduction

Flutter Movies app with Riverpod (TMDB API)

This is an improved version of my old movies app based on the latest Riverpod 2.0 APIs.

Movies app preview

Motivation

I built this app to showcase the latest APIs for popular packages such as Riverpod and GoRouter.

This is not meant to be a complete movies app, yet it should implement common use cases and features. ๐Ÿ‘‡

Current Features

  • Infinite scrolling with pagination
  • Pull to refresh
  • Search functionality
  • Loading UI with the Shimmer package
  • Stateful nested routing with StatefulShellRoute

Here's a detailed tutorial explaining how the pagination and search UI works:

Planned Features (no promises ๐Ÿ˜…)

  • Favourites
  • Responsive UI

Packages in use

App Architecture & Folder structure

The project follows my Riverpod app architecture with a feature-first project structure.

More details here:

It also uses the new Riverpod Generator package, which I have covered here:

Getting a TMDB API Key and Running the Project

This project uses the TMDB API to get the latest movies data.

Before running the app, you need to sign up on the TMDB website, then obtain an API key on the settings API page.

Once you have this, create an .env file at the root of the project and add your key:

// .env
TMDB_KEY=your-api-key

Then, run the code generator:

dart run build_runner build -d

This will generate a env.g.dart file inside lib/env. This contains the tmdbApiKey that is used when making requests to the TMDB API.

Congratulations, you're good to go. ๐Ÿ˜Ž

Note: Loading images from insecure HTTP endpoints

The data returned by the TMBD API points to image URLs using http rather than https. For the images to load correctly, the following changes have been made:

Android

Created a file at android/app/src/main/res/xml/network_security_config.xml with these contents:

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <base-config cleartextTrafficPermitted="true" />
</network-security-config>

Added this to the application tag in the AndroidManifest.xml:

android:networkSecurityConfig="@xml/network_security_config"

iOS

Add the following to ios/Runner/info.pList:

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

More information here:

macOS

Since macOS applications are sandboxed by default, we get a SocketException if we haven't added the required entitlements. This has been fixes by adding these lines to macos/Runner/DebugProfile.entitlements and macos/Runner/Release.entitlements:

<key>com.apple.security.network.client</key>
<true/>

More info here:

tmdb_movie_app_riverpod's People

Contributors

bizz84 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

tmdb_movie_app_riverpod's Issues

Pub get not working

[tmdb_movie_app_riverpod] flutter pub get

Running "flutter pub get" in tmdb_movie_app_riverpod...         
The current Dart SDK version is 2.18.4.

Because riverpod_generator >=2.0.0 depends on riverpod_analyzer_utils ^0.1.0 which depends on custom_lint_core ^0.2.12, riverpod_generator >=2.0.0 requires custom_lint_core ^0.2.12.
So, because custom_lint_core >=0.2.11 requires SDK version >=2.19.0 <3.0.0 and tmdb_movie_app_riverpod depends on riverpod_generator ^2.0.0, version solving failed.
pub get failed (1; So, because custom_lint_core >=0.2.11 requires SDK version >=2.19.0 <3.0.0 and tmdb_movie_app_riverpod depends on riverpod_generator ^2.0.0, version solving failed.)
exit code 1

$ flutter --version

Flutter 3.3.8 โ€ข channel stable โ€ข https://github.com/flutter/flutter.git
Framework โ€ข revision 52b3dc25f6 (4 months ago) โ€ข 2022-11-09 12:09:26 +0800
Engine โ€ข revision 857bd6b74c
Tools โ€ข Dart 2.18.4 โ€ข DevTools 2.15.0

small bug with envied

using TMDBKEY with an underscore causes the build runner to throw and error:

[SEVERE] envied_generator:envied on lib/env/env.dart (cached):

Environment variable not found for field `tmdbApiKey`.
package:tmdb_movie_app_riverpod/env/env.dart:8:23
  โ•ท
8 โ”‚   static final String tmdbApiKey = _Env.tmdbApiKey;
  โ”‚                       ^^^^^^^^^^
  โ•ต
[SEVERE] Failed after 122ms

Removing the underscore in the .env file and envied.dart allows the runner to complete.

'FileSystemEvent' can't be extended, implemented, or mixed in outside of its library

Cannot run the build runner, getting the following error:

โฏ flutter pub run build_runner build --delete-conflicting-outputs
Deprecated. Use `dart run` instead.
Building package executable...
Failed to build build_runner:build_runner:
../../../.pub-cache/hosted/pub.dev/watcher-1.0.2/lib/src/constructable_file_system_event.dart:7:57: Error: The class 'FileSystemEvent' can't be extended, implemented, or mixed in outside of its library because it's a sealed class.
abstract class _ConstructableFileSystemEvent implements FileSystemEvent {

Generated Riverpod autodispose With Chrome Target

I am fairly sure that this is a @riverpod issue, not one with your app, but reporting it nonetheless in the hope that you could verify that this is the case.

When setting Chrome as the target, you find immediately on application launch:

Invalid argument: Maximum call stack size exceeded.

In the stack trace, autodispose seems to be the culprit


โ•โ•โ•ก EXCEPTION CAUGHT BY WIDGETS LIBRARY โ•žโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
The following JSRangeError was thrown building:
Invalid argument: Maximum call stack size exceeded
When the exception was thrown, this was the stack:
packages/riverpod/src/framework/auto_dispose.dart 7:24                                                    <computed>
packages/riverpod/src/future_provider/base.dart 52:56                                                     __
packages/riverpod/src/future_provider/auto_dispose.dart 41:7                                              __
packages/riverpod/src/future_provider/auto_dispose.dart 33:45                                             createElement
packages/riverpod/src/framework/container.dart 49:32                                                      [_create]
packages/riverpod/src/framework/container.dart 41:52                                                      getElement
packages/riverpod/src/framework/container.dart 455:39                                                     <fn>

Thanks for taking a look.

build_runner error in bootstrap

Congratulations Andrea,
Your articles are fantastic.
Just wanting to help follows some errors when running in my environment.
image
So I commented this line and proceeding generated another error and commented these other lines.
image

How can we litmit loading item?

How can i limit the number of MovieListTileShimmer? For example i want prevent user scroll to far and make hundred api requests

Fetches all pages when refreshing

If you scroll a few pages down (eg: to page 5) and scroll up and do a pull to refresh, it fetches pages 1-5 while it should only fetch page 1.

This happens because the list items are still mounted when you invalidate all providers.

pagination-bug.mp4

How to return error or loading states for function annotated with @riverpod?

Hi, thanks for writing the article on https://codewithandrea.com/articles/flutter-riverpod-generator/. One thing I would like to ask is how to return error or loading states for function annotated with @riverpod [1] as I saw that you were handling the different states on the presentation page [2]. I don't see the states being returned on the pub documentation of the library as well [3].

Thanks!

[1]

@riverpod
Future<List<TMDBMovie>> fetchMovies(
FetchMoviesRef ref, {
required MoviesPagination pagination,
}) async {
final moviesRepo = ref.watch(moviesRepositoryProvider);
// See this for how the timeout is implemented:
// https://codewithandrea.com/articles/flutter-riverpod-data-caching-providers-lifecycle/#caching-with-timeout
// Cancel the page request if the UI no longer needs it.
// This happens if the user scrolls very fast or if we type a different search
// term.
final cancelToken = CancelToken();
// When a page is no-longer used, keep it in the cache.
final link = ref.keepAlive();
// a timer to be used by the callbacks below
Timer? timer;
// When the provider is destroyed, cancel the http request and the timer
ref.onDispose(() {
cancelToken.cancel();
timer?.cancel();
});
// When the last listener is removed, start a timer to dispose the cached data
ref.onCancel(() {
// start a 30 second timer
timer = Timer(const Duration(seconds: 30), () {
// dispose on timeout
link.close();
});
});
// If the provider is listened again after it was paused, cancel the timer
ref.onResume(() {
timer?.cancel();
});
if (pagination.query.isEmpty) {
// use non-search endpoint
return moviesRepo.nowPlayingMovies(
page: pagination.page,
cancelToken: cancelToken,
);
} else {
// Debounce the request. By having this delay, consumers can subscribe to
// different parameters. In which case, this request will be aborted.
await Future.delayed(const Duration(milliseconds: 500));
if (cancelToken.isCancelled) throw AbortedException();
// use search endpoint
return moviesRepo.searchMovies(
page: pagination.page,
query: pagination.query,
cancelToken: cancelToken,
);
}
}

[2]
error: (err, stack) => Text('Error $err'),
loading: () => const MovieListTileShimmer(),
data: (movies) {

[3]
https://pub.dev/packages/riverpod_generator

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.