Mudanças entre as edições de "Flutter - Consumindo API"

De Aulas
 
(13 revisões intermediárias pelo mesmo usuário não estão sendo mostradas)
Linha 19: Linha 19:
 
== main.dart ==
 
== main.dart ==
  
<syntaxhighlight lang=dart line>
+
<syntaxhighlight lang=dart>
 
import 'package:flutter/material.dart';
 
import 'package:flutter/material.dart';
 
import 'movies.dart';
 
import 'movies.dart';
Linha 42: Linha 42:
 
O arquivo api.dart faz referência à API TVMaze e gerencia o objeto de transferência de um filme.
 
O arquivo api.dart faz referência à API TVMaze e gerencia o objeto de transferência de um filme.
  
<syntaxhighlight lang=dart line>
+
<syntaxhighlight lang=dart>
 
import 'package:http/http.dart' as http;
 
import 'package:http/http.dart' as http;
  
Linha 66: Linha 66:
 
   String image;
 
   String image;
  
   Movie(int id, String name, String link, String image) {
+
   Movie(this.id, this.name, this.link, this.image);
    this.id = id;
 
    this.name = name;
 
    this.link = link;
 
    this.image = image;
 
  }
 
  
 
   Movie.fromJson(Map json)
 
   Movie.fromJson(Map json)
Linha 85: Linha 80:
 
O arquivo movie.dart conteém a lista de filmes no formato JSON que ele vai trazer da API e cria uma LIST com objetos do tipo '''Movie''' criado no arquivo api.dart.
 
O arquivo movie.dart conteém a lista de filmes no formato JSON que ele vai trazer da API e cria uma LIST com objetos do tipo '''Movie''' criado no arquivo api.dart.
  
<syntaxhighlight lang=dart line>
+
<syntaxhighlight lang=dart>
 
import 'package:flutter/material.dart';
 
import 'package:flutter/material.dart';
 
import 'dart:convert';
 
import 'dart:convert';
Linha 93: Linha 88:
 
// Vamos precisar de uma aplicação com estado
 
// Vamos precisar de uma aplicação com estado
 
class MoviesListView extends StatefulWidget {
 
class MoviesListView extends StatefulWidget {
 +
  const MoviesListView({super.key});
 +
 
   @override
 
   @override
   _MoviesListViewState createState() => _MoviesListViewState();
+
   State<MoviesListView> createState() => _MoviesListViewState();
 
}
 
}
  
Linha 116: Linha 113:
 
     return Scaffold(
 
     return Scaffold(
 
       appBar: AppBar(
 
       appBar: AppBar(
         title: Text("Lista de Filmes"),
+
         title: const Text("Lista de Filmes"),
 
       ),
 
       ),
 
       // Aqui vem nossa lista
 
       // Aqui vem nossa lista
Linha 134: Linha 131:
 
             title: Text(
 
             title: Text(
 
               movies[index].name,
 
               movies[index].name,
               style: TextStyle(fontSize: 20.0, color: Colors.black),
+
               style: const TextStyle(
 +
                fontSize: 20.0,
 +
                color: Colors.black,
 +
              ),
 
             ),
 
             ),
 
             // No subtítulo colocamos o link
 
             // No subtítulo colocamos o link
Linha 145: Linha 145:
 
               Navigator.push(
 
               Navigator.push(
 
                 context,
 
                 context,
                 new MaterialPageRoute(
+
                 MaterialPageRoute(
 
                   builder: (context) => DetailPage(movies[index]),
 
                   builder: (context) => DetailPage(movies[index]),
 
                 ),
 
                 ),
Linha 158: Linha 158:
 
</syntaxhighlight>
 
</syntaxhighlight>
  
== details.dart ==
+
== detail.dart ==
  
 
Esse arquivo contém a página que é chamada para mostrar detalhes de um filme depois que você clicar nele na lista de filmes de movies.dart.
 
Esse arquivo contém a página que é chamada para mostrar detalhes de um filme depois que você clicar nele na lista de filmes de movies.dart.
  
<syntaxhighlight lang=dart line>
+
<syntaxhighlight lang=dart>
 
import 'package:flutter/material.dart';
 
import 'package:flutter/material.dart';
 
import 'package:url_launcher/url_launcher.dart';
 
import 'package:url_launcher/url_launcher.dart';
Linha 173: Linha 173:
 
   final Movie movie;
 
   final Movie movie;
  
   DetailPage(this.movie);
+
   const DetailPage(this.movie, {super.key});
  
 
   @override
 
   @override
Linha 182: Linha 182:
 
       ),
 
       ),
 
       body: Container(
 
       body: Container(
         padding: new EdgeInsets.all(10.0),
+
         padding: const EdgeInsets.all(10.0),
 
         child: Column(
 
         child: Column(
 
           children: [
 
           children: [
Linha 192: Linha 192:
 
               ),
 
               ),
 
             ),
 
             ),
             Text("Link:"),
+
             const Text("Link:"),
 
             // Aqui a gente coloca um link clicável.
 
             // Aqui a gente coloca um link clicável.
 
             Linkify(
 
             Linkify(
 
               onOpen: (link) async {
 
               onOpen: (link) async {
                 if (await canLaunch(movie.link)) {
+
                Uri link = Uri.parse(movie.link);
                   await launch(movie.link);
+
                 if (await canLaunchUrl(link)) {
 +
                   await launchUrl(link);
 
                 } else {
 
                 } else {
 
                   throw 'Não foi possível abrir {$movie.link}';
 
                   throw 'Não foi possível abrir {$movie.link}';
Linha 216: Linha 217:
 
== Desafio 1 ==
 
== Desafio 1 ==
  
1. Implemente o exemplo anterior em seu comptuador.
+
# Implemente o exemplo anterior em seu computador.
 +
# Adicione um campo texto e um botão "Procurar". Quando clicar no botão procurar, atualiza a lista de filmes conforme a string do campo texto.
  
 
== Desafio 2 ==
 
== Desafio 2 ==
  
Implemente uma aplicação que consuma alguma outra API de sua escolha.
+
* Implemente uma aplicação que consuma alguma outra API de sua escolha.
 +
* Se você já estiver trabalhando com criação de microsserviços web na disciplina de Sistemas Distribuídos, você pode criar uma API pra consumir no flutter.

Edição atual tal como às 13h51min de 10 de março de 2023

Afluentes: Dispositivos Móveis; Usabilidade, desenvolvimento web, mobile e jogos

Pré-requisitos

Primeiro vamos criar nosso projeto e incluir alguns pacotes, então digite na pasta do projeto:

flutter create movies
cd movies
flutter pub add url_launcher
flutter pub add flutter_linkify
flutter pub add http

Código

O Aplicativo faz uma requisição de filmes em uma API. Tal como fizemos no Consumindo API com React.js, só que agora em Flutter.

O arquivo main.dart é simples e ele só inicia a página principal.

main.dart

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

void main() => runApp(const App());

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

  @override
  build(context) {
    return const MaterialApp(
      title: 'Filmes',
      home: MoviesListView(),
    );
  }
}

api.dart

O arquivo api.dart faz referência à API TVMaze e gerencia o objeto de transferência de um filme.

import 'package:http/http.dart' as http;

// A URL da API
const baseUrl = "https://api.tvmaze.com/search/shows?q=";

// Criamos a classe da nossa API. O nome você que escolhe. Fazemos aqui
// uma requisição get (como fizemos no react) e passamos a URL, mas usamos
// um Uri.parse pra transformar a string em uma URI.
class API {
  static Future getMovie(search) async {
    var url = baseUrl + search;
    return await http.get(Uri.parse(url));
  }
}

// Criamos uma classe para representar os objetos que vão conter os filmes
// e colocamos só os campos que vamos usar.
class Movie {
  int id;
  String name;
  String link;
  String image;

  Movie(this.id, this.name, this.link, this.image);

  Movie.fromJson(Map json)
      : id = json['show']['id'],
        name = json['show']['name'],
        link = json['show']['url'],
        image = json['show']['image']['medium'];
}

movies.dart

O arquivo movie.dart conteém a lista de filmes no formato JSON que ele vai trazer da API e cria uma LIST com objetos do tipo Movie criado no arquivo api.dart.

import 'package:flutter/material.dart';
import 'dart:convert';
import 'api.dart';
import 'detail.dart';

// Vamos precisar de uma aplicação com estado
class MoviesListView extends StatefulWidget {
  const MoviesListView({super.key});

  @override
  State<MoviesListView> createState() => _MoviesListViewState();
}

class _MoviesListViewState extends State<MoviesListView> {
  List<Movie> movies = List<Movie>.empty(); // Lista dos filmes
  String search = "star%20trek"; // Plavra chave da pesquisa

  // Construtor, atualiza com setState a lista de filmes.
  _MoviesListViewState() {
    API.getMovie(search).then((response) {
      setState(() {
        Iterable lista = json.decode(response.body); // Usamos um iterator
        movies = lista.map((model) => Movie.fromJson(model)).toList();
      });
    });
  }

  // Método build sobrecarregado que vai construir nossa página
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text("Lista de Filmes"),
      ),
      // Aqui vem nossa lista
      body: ListView.builder(
        itemCount: movies.length, // quantidade de elementos
        // Os elementos da lista
        itemBuilder: (context, index) {
          // Vai ser um item de lista tipo ListTile
          return ListTile(
            // Uma imagem de avatar redondinho com a imagem do filme
            leading: CircleAvatar(
              backgroundImage: NetworkImage(
                movies[index].image,
              ),
            ),
            // No título é o nome do filme
            title: Text(
              movies[index].name,
              style: const TextStyle(
                fontSize: 20.0,
                color: Colors.black,
              ),
            ),
            // No subtítulo colocamos o link
            subtitle: Text(movies[index].link),
            // Ação de clicar
            onTap: () {
              // Abrimos uma nova página, outra classe, que está no arquivo
              // detail.dart. Veja que é um MaterialPageRote, tipo o
              // MaterialApp, só que é só uma página nova.
              Navigator.push(
                context,
                MaterialPageRoute(
                  builder: (context) => DetailPage(movies[index]),
                ),
              );
            },
          );
        },
      ),
    );
  }
}

detail.dart

Esse arquivo contém a página que é chamada para mostrar detalhes de um filme depois que você clicar nele na lista de filmes de movies.dart.

import 'package:flutter/material.dart';
import 'package:url_launcher/url_launcher.dart';
import 'package:flutter_linkify/flutter_linkify.dart';
import 'api.dart';

// Uma página para mostrar os detalhes de cada filme. Passamos o objeto
// do filme como parâmetro no constructor
class DetailPage extends StatelessWidget {
  final Movie movie;

  const DetailPage(this.movie, {super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(movie.name),
      ),
      body: Container(
        padding: const EdgeInsets.all(10.0),
        child: Column(
          children: [
            Center(
              child: Image(
                image: NetworkImage(
                  movie.image,
                ),
              ),
            ),
            const Text("Link:"),
            // Aqui a gente coloca um link clicável.
            Linkify(
              onOpen: (link) async {
                Uri link = Uri.parse(movie.link);
                if (await canLaunchUrl(link)) {
                  await launchUrl(link);
                } else {
                  throw 'Não foi possível abrir {$movie.link}';
                }
              },
              text: movie.link,
            ),
          ],
        ),
      ),
    );
  }
}

Atividades

Desafio 1

  1. Implemente o exemplo anterior em seu computador.
  2. Adicione um campo texto e um botão "Procurar". Quando clicar no botão procurar, atualiza a lista de filmes conforme a string do campo texto.

Desafio 2

  • Implemente uma aplicação que consuma alguma outra API de sua escolha.
  • Se você já estiver trabalhando com criação de microsserviços web na disciplina de Sistemas Distribuídos, você pode criar uma API pra consumir no flutter.