0

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.

6
  • 2
    Please hide your API key & read access token, you can put dummy values or placeholder instead. Commented Jul 7 at 15:12
  • edit history can be found, well even deleted one for some high rep, instead share the json response Commented Jul 7 at 16:54
  • I don't know why people have to do things like this! You could just return the constructed Movie object from the loadMovie() method instead of making things complicated. Commented Jul 8 at 6:52
  • @S.M.JAHANGIR I changed the returntype from void to Movie in loadMovie() and returned the Movie from there itself but I still get the same error Commented Jul 8 at 10:05
  • Please share the updated code. Commented Jul 8 at 14:44

2 Answers 2

0

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.

0

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);
      },
    );

Not the answer you're looking for? Browse other questions tagged or ask your own question.