Twitter com JavaFX

twitterfx Neste post, mostraremos um pequeno exemplo de aplicação JavaFX integrada ao Twitter. Você também verá um pouco mais de css e o FadeTransition. Para o exemplo, utilizamos o NetBeans e o Twitter4J, e criamos uma conta de desenvolvedor no Twitter para cadastrar o aplicativo.

1. Obtendo as credenciais para comunicação com o Twitter

Para utilizar os serviços do Twitter, é necessário obter as credenciais de desenvolvedor para o aplicativo. Visite https://dev.twitter.com e realize o login com sua conta do Twitter. Em seguida, vá em “My applications” e “Create new application” para criar sua aplicação.

twitter2

twitter4

Preencha os campos para criar o aplicativo:

  • Name: Nome do aplicativo (até 32 caracteres e sem a palavra “Twitter”);
  • Description: descrição do aplicativo (entre 10 e 200 caracteres);
  • Website: endereço que os usuários poderão visitar para obter mais informações sobre o aplicativo;
  • Callback URL: endereço para o qual o usuário será redirecionado após a autenticação no Twitter. Para este exemplo, esse campo deverá ser deixado em branco.
  • Aceitar os termos e condições de uso. Há várias regras, e se você for fazer alguma coisa séria ou usar com muita frequência, deveria prestar bastante atenção a esses termos para evitar frustrações;
  • Captcha: para que o robô que cuida do formulário ache que você não é um robô.

Clique em “Create your Twitter application“. Após cadastrar seu aplicativo do Twitter, você verá algumas informações básicas, como o “OAuth settings“, que contém as credenciais para acessar os serviços do Twitter. Agora, é necessário ter um token de acesso, que é equivalente ao login. Há várias formas de obter os tokens. Uma delas envolve enviar um link para o usuário para que ele obtenha um PIN para ser digitado no aplicativo (Autorização baseada em PIN). Outra forma é direcionar um usuário para uma página do twitter no qual ele autorizará o aplicativo a acessar algumas informações da conta, e a página vai redirecionar o usuário de volta para o aplicativo (Autorização de três pernas). Para este exemplo, foi utilizado um token de acesso próprio para o aplicativo, então clique em “Create my access token“. Mais a frente, você verá como essas informações serão utilizadas.

2. Iniciando o projeto

No NetBeans, crie um projeto de JavaFX com FXML (como mostrado em Iniciando no JavaFX). Neste exemplo, eu criei o projeto com nome TwitterFX. Faça o download do Twitter4J de http://twitter4j.org/en/. Em seguida adicione às bibliotecas do projeto, clicando com o botão direito no projeto, selecionando “Propriedades”, “Bibliotecas”, “Adicionar JAR/Pasta”, e adicionando os jars do Twitter4J da pasta lib.

twitter

twitter5

twitter6

3. A classe TwitterUtil

Criaremos uma classe TwitterUtil para facilitar o acesso aos tuítes, ao nome e à foto de um usuário do Twitter. Note as informações utilizadas no topo da classe. Você deverá utilizar as informações de OAuth settings e Access Token obtidos do dev.twitter.com.

package br.com.matruskan.twitterfx;

import java.util.List;
import twitter4j.Paging;
import twitter4j.Status;
import twitter4j.Twitter;
import twitter4j.TwitterFactory;
import twitter4j.User;
import twitter4j.auth.AccessToken;

public class TwitterUtil {

    private static final String twitter_consumer_key =
            "aaaaaaaaaaaaaaaaaaaaa";
    private static final String twitter_consumer_secret =
            "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
    private static final String access_token =
            "1111111111-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
    private static final String access_token_secret =
            "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";

    private Twitter twitter;

    /**
     * Constrói o Twitter, já com os dados de autenticação
     */
    public TwitterUtil(){
        twitter = new TwitterFactory().getInstance();
        twitter.setOAuthConsumer(twitter_consumer_key,
            twitter_consumer_secret);
        twitter.setOAuthAccessToken(new AccessToken(access_token,
            access_token_secret));
    }

    /**
     * Obtém o URL da imagem de perfil do usuário
     * 
     * @param username usuário do qual se deseja obter a imagem
     * @return URL da imagem de perfil do usuário
     */
    public String getProfileImage(String username) {
        String url = null;

        try {
            User user = twitter.showUser(username);
            url = user.getProfileImageURL();
        } catch (Exception e) {
            e.printStackTrace();
        }

        return url;
    }

    /**
     * Obtém o nome do usuário
     * 
     * @param username usuário do qual se deseja obter o nome
     * @return nome do usuário
     */
    public String getScreenName(String username) {
        String screenName = null;

        try {
            User user = twitter.showUser(username);
            screenName = user.getName();
        } catch (Exception e) {
            e.printStackTrace();
        }

        return screenName;
    }

    /**
     * Obtém uma lista paginada de tuítes do usuário.
     * @param username usuário do qual se obterá os tuítes
     * @param pagina número da página
     * @param quantidade quantidade de tuítes por página
     * @return lista de tuítes
     */
    public List getTweets(String username, int pagina, int quantidade) {
        List tweets = null;

        try {
            if (username != null && !username.equals("")) {
                Paging p = new Paging(pagina, quantidade);
                tweets = twitter.getUserTimeline(username,p);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        return tweets;
    }
}

4. Criando a tela

Clique duas vezes no arquivo fxml para contruir a tela do aplicativo. Na figura abaixo, é possível ver na tela Hierarchy os componentes utilizados. Lembre-se de aplicar o “Fit to parent” onde for necessário.

twitter11

O TwitterFXController irá obter o texto do TextField e buscar os tuítes do usuário digitado. As buscas serão paginadas e o botão “Mais” irá buscar a próxima página de tuítes.

package br.com.matruskan.twitterfx;

import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.List;
import java.util.Locale;
import java.util.ResourceBundle;
import javafx.animation.FadeTransition;
import javafx.application.Platform;
import javafx.concurrent.Task;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Label;
import javafx.scene.control.ListView;
import javafx.scene.control.TextField;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.text.Text;
import javafx.util.Duration;
import twitter4j.Status;

public class TwitterFXController implements Initializable {

    // TextField com o nome do usuário do qual serão obtidos os tuítes.
    @FXML
    private TextField username;
    //Nome do usuário.
    @FXML
    private Label  nome;
    // Lista onde serão mostrados os tuítes.
    @FXML
    private ListView tweets;
    //Imagem do usuário.
    @FXML
    private ImageView imagem;

    // Nossa classe TwitterUtil facilitará a interação com o Twitter.
    private TwitterUtil twitterUtil;

    // Usuário do qual buscaremos os tuítes
    private String usuario;
    // Número da página (para busca paginada de tuítes).
    private int pagina = 1;
    // Quantidade de tuítes a serem buscados em cada página.
    private static final int QUANTIDADE = 5;

    @Override
    public void initialize(URL url, ResourceBundle rb) {
        twitterUtil = new TwitterUtil();
    }

    /**
     * Chamado quando o usuário tecla Enter no TextField username,
     * este método busca a imagem de perfil do usuário digitado, limpa
     * a lista de tuítes e carrega a primeira página de tuítes.
     * 
     * @param event 
     */
    @FXML
    private void onUsername(ActionEvent event) {
        usuario = username.getText();
        pagina = 1;
        imagem.setImage(new Image(
            twitterUtil.getProfileImage(usuario)));
        nome.setText(twitterUtil.getScreenName(usuario));
        tweets.getItems().clear();
        carregar();
    }

    /**
     * Adiciona mais ítens à lista de tuítes.
     * 
     * @param event 
     */
    @FXML
    private void onMais(ActionEvent event) {
        pagina++;
        carregar();
    }

    /**
     * Carrega alguns tuítes do usuário e adiciona à lista de tuítes.
     */
    private void carregar() {
        // Obter os tuítes
        SimpleDateFormat sdf =
            new SimpleDateFormat("E HH:mm", Locale.getDefault());
        List status =
            twitterUtil.getTweets(usuario, pagina, QUANTIDADE);
        for(Status s : status){
            // Para cada tuíte, criar um texto com a largura do ListView
            Text t = new Text(
                    s.getText() +
                    " ("+sdf.format(s.getCreatedAt())+")"
            );
            t.wrappingWidthProperty().bind(tweets.widthProperty());
            tweets.getItems().add(t);
        }
    }
}

Repare que utilizamos um Text para adicionar o texto ao ListView. Fizemos isso para podermos redimencionar a célula com o texto de acordo com a largura do ListView.

Não se esqueça de voltar ao Scene Builder e adicionar os fx:id‘s username, nome, tweets e imagem aos componentes.

Execute o software para ver como ficou! Experimente também buscar os tuítes de outros usuários.

twitter8

5. Agora fica interessante

Agora só falta deixar a interface mais agradável. No método start, do TwitterFX.java, adicionei:

scene.getStylesheets().add("br/com/matruskan/twitterfx/twitterfx.css");

O arquivo twitterfx.css ficou assim:

.conteudo{
    -fx-padding: 10px; /*Nada grudando nas bordas*/
}

.topo {
    -fx-background-color: linear-gradient(to top right, #eeffee, #445566); /*Gradiente cinza*/
    -fx-padding: 10px; /*Espaçamento nas bordas internas, para nada ficar encostando*/
}

.imagem-de-perfil {
    -fx-rotate: -20; /*Tombar a imagem um tantinho para a esquerda*/
    -fx-effect: dropshadow(one-pass-box,rgba(0,0,0,0.6), 15, 0, 2, 2); /*com sombra*/
}

.list-view {
    -fx-background-color: transparent; /*Remove o contorno*/
}

.list-view .scroll-bar .increment-arrow,
.list-view .scroll-bar .decrement-arrow,
.list-view .scroll-bar .increment-button,
.list-view .scroll-bar .decrement-button {
    -fx-padding:0; /*Some com as barras de rolagem*/
}

.list-cell {
    -fx-padding: 10px 0px;
    -fx-font-family: sans-serif; /*fonte sem serifa*/
}
.list-cell:hover { /*célula com o mouse em cima*/
    -fx-background-color: linear-gradient(to bottom right,#d0e0ff,#eeefff);
}
.list-cell:selected { /*célula selecionada*/
    -fx-background-color: linear-gradient(to top,#99bbdd,#ddeeff);
}

#username {
    -fx-background-color: transparent; /*TextField sem cor de fundo*/
    -fx-border-color: rgba(255,255,255,0.2); /*borda discreta*/
    -fx-text-fill: white;
    -fx-font: large sans-serif;
    -fx-background-image: url('arroba.png'); /*colocar a imagem de arroba*/
    -fx-background-size: contain; /*...do tamanho do TextField*/
    -fx-background-repeat: no-repeat; /*...sem repetir*/
    -fx-background-position: -28px; /*...e à esquerda*/
}
#username:focused { /*engrossar a borda se estiver com foco*/
    -fx-border-width: 2px;
    -fx-border-color: white;
}

#nome { /*Label com nome bem grande*/
    -fx-text-fill: white;
    -fx-font: xx-large sans-serif;
}

.topo VBox {/*alinhar o username e o nome à direita*/
    -fx-alignment: BASELINE_RIGHT;
}

.mais {
    -fx-padding: 8px 15px; /*botão com margens maiores*/
    -fx-base: #445566; /*cor de base cinza azulado*/
    -fx-border-radius: 1px; /*um pouco mais quadrado*/
    -fx-background-radius: 1px; /*idem*/
    -fx-font-weight: bold; /*e com letra em negrito*/
}

No SceneBuilder, adicione as classes .conteudo ao BorderPane grande, .topo ao BorderPane do topo, e .mais ao botão.

Também adicionei algumas animações:

    /**
     * Carrega alguns tuítes do usuário e adiciona à lista de tuítes.
     */
    private void carregar() {
        // Threads executando as Tasks do JavaFX
        Thread thread; 
        thread = new Thread(new Task() { 
            @Override
            protected Void call() throws Exception {
            // Você pode retornar algo no fim, mas eu não quero

                // Obter os tuítes
                SimpleDateFormat sdf =
                    new SimpleDateFormat("E HH:mm", Locale.getDefault());
                List status =
                    twitterUtil.getTweets(usuario,pagina,QUANTIDADE);
                for(Status s : status){
                    if(isCancelled()){ //a task pode ser cancelada
                        System.out.println("Cancelada!");
                        break;
                    }
                    // Para cada tuíte, criar um texto com a largura do
                    // ListView
                    final Text t = new Text(
                            s.getText() +
                            " ("+sdf.format(s.getCreatedAt())+")"
                    );
                    t.wrappingWidthProperty().bind(
                        tweets.widthProperty());

                    // Fazer o tuíte surgir suavemente na tela.
                    // Como estamos em uma thread separada, temos que pedir
                    // para executar depois com o runLater()
                    Platform.runLater(new Runnable() {
                        @Override
                        public void run() {
                            tweets.getItems().add(t);
                            // Usando uma transicao legal
                            FadeTransition ft = new FadeTransition(
                                Duration.millis(1800), t);
                            ft.setFromValue(0.0);
                            ft.setToValue(1.0);
                            ft.play();
                        }
                    });

                    // Dormir um pouquinho entre a adição de cada tuíte,
                    // para ficar mais interessante
                    try{
                        Thread.sleep(700);
                    }catch(InterruptedException iex){
                        if(isCancelled()){
                        // A excessão também pode ser lançada
                        // quando a task é cancelada.
                            System.out.println("Cancelada!");
                            break;
                        }
                    }
                }

                return null;
            }
        });
        thread.setDaemon(true);
        // Se só sobrarem threads daemon, a JVM fecha
        // (ou seja, não queremos travar a JVM se estiver
        // executando este thread)

        thread.start();
    }

Veja como ficou:twitter12

6. Indo além: Twitter

Mostramos que é bem fácil obter dados do Twitter. Para saber mais, estude alguns exemplos do Twitter4J  e o JavaDoc para ver outras possibilidades de interação com o Twitter.

7. Indo além: JavaFX

Animações são coisas fáceis de se fazer no JavaFX. O FadeTransition (Transição de Desvanecer) faz parte de um conjunto de transições, entre as quais podemos encontrar também FillTransition (Transição de Preenchimento, altera a cor), ParallelTransition (Transição Paralela, composta de várias animações que são executadas em paralelo), PathTransition (Transição de Caminho, que move algo seguindo um caminho), PauseTransition (Transição de Pausa, não faz nada por determinado tempo), RotateTransition (Transição de Rotação), ScaleTransition (Transição de Redimensionamento), SequentialTransition (Transição Sequencial, que executa as animações em sequência) , StrokeTransition (Transição de Contorno), TranslateTransition (Transição de Translado).

Você também pode colocar animações com Timeline e Interpolators.

Para saber mais, veja Animation Basics.

Anúncios
Marcado com: , , , , , ,
Publicado em JavaFX

Deixe um comentário

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s

%d blogueiros gostam disto: