skip to Main Content

I am trying to create a class to display a movie title and poster in a card. I am using the TMDB API. here are my dart files-
movie.dart

class Movie{
  String mtitle;
  String mposter;
  Movie({required this.mtitle, required this.mposter});
}

MovieCard.dart

// ignore_for_file: prefer_const_constructors, prefer_const_literals_to_create_immutables

import 'package:flutter/material.dart';
import 'package:movie_recommendation_ia/objects/movie.dart';

class MovieCard extends StatelessWidget {
  MovieCard({required this.movie,});
  final Movie movie;

  @override
  Widget build(BuildContext context) {
    return Card(
      margin: EdgeInsets.fromLTRB(16.0, 16.0, 16.0, 0.0),
      child: Padding(
        padding: const EdgeInsets.all(8.0),
        child: Column(
          children: <Widget>[
              Container(
                child: Image.network(
                  movie.mposter,
                  height: 150.0,
                  width: 120.0,
                  fit: BoxFit.cover,
                ),
              ),
              Text(
                movie.mtitle
              )
          ],
        ),
      ),
    );
  }
}

getMovie.dart

// ignore_for_file: file_names
import 'dart:async';
import 'package:movie_recommendation_ia/objects/movie.dart';
import 'package:tmdb_api/tmdb_api.dart';
import 'package:http/http.dart';
import 'dart:convert';

class getMovie{
  String? poster;
  String title='';
  final String APIKey = 'placeholder';
  final String readAccessToken = 'placeholder';
  
  Future<Movie> loadMovie() async{
    Response response = await get(Uri.parse('https://api.themoviedb.org/3/movie/550?api_key=$APIKey'));
    Map data = jsonDecode(response.body);
    //print (data['poster_path']);
    TMDB tmdbWithCustomLogs = TMDB(
      ApiKeys(APIKey, readAccessToken),
      logConfig: const ConfigLogger(
        showLogs: true,
        showErrorLogs: true
      )
    );
    poster = await tmdbWithCustomLogs.images.getUrl(data['poster_path']);
    title = data['title'];
    Movie set = Movie(mtitle: title, mposter: poster as String);
    return set;
    //print(poster);
    //print(title);
  }
}

recommended.dart

import 'package:flutter/material.dart';
import 'package:movie_recommendation_ia/objects/movie.dart';
import 'package:movie_recommendation_ia/objects/MovieCard.dart';
import 'package:movie_recommendation_ia/objects/getMovie.dart';

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

  @override
  State<Recommended> createState() => _RecommendedState();
}

class _RecommendedState extends State<Recommended> {

  @override
  void initState() {
    // TODO: implement initState
    super.initState();
  }
  load() async {
    Movie get = await getMovie().loadMovie();
    return get;
  }
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.white,
      appBar: AppBar(
        backgroundColor: Colors.black,
        foregroundColor: Colors.white,
        title: Column(
          children: [
            TextButton(
              onPressed: (){
                Navigator.pushNamed(context, '/search');
              }, 
              child: const Text(
                'Search',
                style: TextStyle(
                  color: Colors.white
                ),
              )
            ),
            Row(
              children: <Widget>[
                Expanded(
                  child: TextButton(
                    onPressed: (){
                      Navigator.pushReplacementNamed(context, '/following');
                    }, 
                    child: const Text(
                      'Following',
                      style: TextStyle(
                        color: Colors.white
                      ),
                      )
                  ),
                ),
                Expanded(
                  child: TextButton(
                    onPressed: (){
                      Navigator.pushReplacementNamed(context, '/recommended');
                    }, 
                    child: const Text(
                      'Recommended',
                      style: TextStyle(
                        color: Colors.white
                      ),
                      )
                  ),
                ),
                Expanded(
                  child: TextButton(
                    onPressed: (){
                      Navigator.pushReplacementNamed(context, '/myactivity');
                    }, 
                    child: const Text(
                      'My Activity',
                      style: TextStyle(
                        color: Colors.white
                      ),
                      )
                  ),
                ),
              ],
            ),
          ],
        ),
      ),
      body: Column(
        children: <Widget>[
          Row(
            children: <Widget>[
              MovieCard(movie: load(),)
            ],
          )
        ],
        )
    );
  }
}

I created an object called Movie which would have the properties title and poster, I used the object in a different class called MovieCard. I used an asynchronous function to fetch the title and poster url from the API. I wanted to put these in the Movie object and then the MovieCard object. When I run, I get an exception: "_TypeError (type ‘Future’ is not a subtype of type ‘Movie’)". I realize that this did not work because the async function is of type Future, but I cant figure out how to fix this.

2

Answers


  1. You are basically passing a Future instead of a Movie object in your MovieCard.

    In your state class, please adjust like this:

    class _RecommendedState extends State<Recommended> {
     Movie? movie;
     @override
      void initState() {
        super.initState();
        getMovie().loadMovie().then(value){
           movie = value;
           setState((){});
         }
      }
    
      .......
      .......
      body: movie == null ? Center(child: CircularProgressIndicator()) : Column(
        children: <Widget>[
          Row(
            children: <Widget>[
              MovieCard(movie: movie!)
            ],
          )
        ],
        )
    

    You can safely remove the load method.

    Also a minor but useful adjustment recommended: you should rename the getMovie class to GetMovie as class names should be PascalCase in Dart.

    Login or Signup to reply.
  2. Use Future builder to load UI which depends on data from Future/API.

    NOTE: Using setState after getting data and updating UI will rebuild the whole widget which is not recommended method to follow.

    FutureBuilder(
          future: load(),
          builder: (context, snapshot) {
            if (snapshot.connectionState == ConnectionState.waiting) {
              return const Center(child: AppProgressBar());
            }
            if (snapshot.hasError) {
              return Center(
                child: Text(
                  'Error: ${snapshot.error}',
                  style: const TextStyle(color: AppColor.white),
                ),
              );
            }
            if (!snapshot.hasData || snapshot.data == null) {
              return Center(
                child: Text(
                  S.current.noData,
                  style: const TextStyle(color: AppColor.white),
                ),
              );
            }
            return MovieCard(movie: snapshot.data);
          },
        );
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search