<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Ricardo da Silva Ogliari</title>
    <description>The latest articles on DEV Community by Ricardo da Silva Ogliari (@ricardoogliari).</description>
    <link>https://dev.to/ricardoogliari</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F555096%2Fa4764ef0-8f2c-437c-aa4b-2ab8597ef0e7.jpeg</url>
      <title>DEV Community: Ricardo da Silva Ogliari</title>
      <link>https://dev.to/ricardoogliari</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ricardoogliari"/>
    <language>en</language>
    <item>
      <title>Um jogo de matemática no Arduino - A math game on Arduino</title>
      <dc:creator>Ricardo da Silva Ogliari</dc:creator>
      <pubDate>Fri, 15 Apr 2022 14:56:49 +0000</pubDate>
      <link>https://dev.to/ricardoogliari/um-jogo-de-matematica-no-arduino-a-math-game-on-arduino-153</link>
      <guid>https://dev.to/ricardoogliari/um-jogo-de-matematica-no-arduino-a-math-game-on-arduino-153</guid>
      <description>&lt;p&gt;&lt;strong&gt;&amp;gt; I'm still learning the English language, so please, if you find any English mistakes, let me know in the comments. Thank you very much.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Quando começamos a estudar uma nova linguagem ou plataforma é comum termos alguns problemas. No meu entendimento, isso pode ser amenizado quando criamos algo que nos empolgue. E, geralmente, desenvolvedores têm uma relação de muito amor com jogos. Logo, por mais simples que possa ser, um jogo modesto pode acelerar o processo de aprendizado.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;When we start to study a new language or platform it is common to have some problems. In my understanding, this can be mitigated when we create something that excites us. And, generally, developers have a very loving relationship with games. So, as simple as it may be, a modest game can speed up the learning process.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Pensando nisso, propus a criação de um jogo matemático para aprimorarmos o conhecimento em IoT e, principalmente, no uso da plataforma de prototipagem Arduino. O objetivo é usar um display de 7 segmentos e a comunicação serial para mostrar dois operandos ao usuário, na sequência, o mesmo responde e receberá uma resposta de acerto ou erro. Sendo que esse processo se repete indefinidamente.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;With that in mind, I proposed the creation of a mathematical game to improve knowledge in IoT and, mainly, in the use of the prototyping platform Arduino. The objective is to use a 7-segment display and serial communication to show two operands to the user, then, the user responds and will receive a hit or miss response. This process is repeated indefinitely.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Para que o leitor possa recriar o jogo, deixo a imagem do thinkercad abaixo com o circuito montado. Estamos usando um Arduino Uno, uma protoboard, um display de sete segmentos, um led RGB e resistores.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;So that the reader can recreate the game, I leave the image of thinkercad below with the circuit assembled. We are using an Arduino Uno, a breadboard, seven-segment display, an RGB LED and resistors.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Os dois fios pretos estão ligando as portas terra do Arduino (GND) com as trilhas horizontais nas linhas indicadas com o símbolo “-”. Como boa prática, estamos usando a cor preta para indicar esses fios (em um circuito real seriam os jumpers).&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The two black wires are connecting the Arduino ground ports (GND) with the horizontal tracks on the lines indicated with the symbol “-”. As a good practice, we are using the color black to indicate these wires (in a real circuit it would be the jumpers).&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;O display de segmentos possui dois pinos na sua parte central, que são ligadas a portas terras através de um resistor de 500 ohms. As outras 8 entradas são para seus segmentos. Lembrando que sete deles são para formar os segmentos individuais que foram o número e, o oitavo é para (des)ligar o ponto localizado no canto inferior direito. Estamos usando as portas digitais 13, 12, 11, 10, 9, 8, 7 e 6.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The segment display has two pins in its central part, which are connected to ground ports through a 500 ohm resistor. The other 8 entries are for its segments. Remembering that seven of them are for built the individual segments that were the number, and the eighth is for (un)connecting the point located in the lower right corner. We are using digital ports 13, 12, 11, 10, 9, 8, 7 and 6.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Por fim, usamos um LED RGB para indicar o acerto ou erro da resposta. Da esquerda para direita ligamos seus conectores as seguintes portas: digital 4, terra, digital 3 e digital 2. &lt;/p&gt;

&lt;p&gt;&lt;em&gt;Finally, we use an RGB LED to indicate the success or error of the answer. From left to right we connect its connectors to the following ports: digital 4, ground, digital 3 and digital 2.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--7eL1in9h--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3zbxq46sz9kvwy5mg694.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--7eL1in9h--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3zbxq46sz9kvwy5mg694.png" alt="Image description" width="880" height="391"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Vamos explicar a codificação por partes. No inícios temos o conjunto de variáveis que indicam as portas onde o display e o LED estão ligados. Cada constante do tipo inteiro indica uma das portas digitais utilizadas. Na sequência teremos as variáveis do status atual e dos estados possíveis. Vamos utilizar a ideia de uma máquina de estados. Inicialmente, precisamos ler o primeiro operando, na sequência, ler o segundo operando e, finalmente, esperar a resposta do usuário. &lt;/p&gt;

&lt;p&gt;&lt;em&gt;Let's explain coding in parts. At the beginning we have the set of variables that indicate the ports where the display and the LED are connected. Each integer constant indicates one of the digital ports used. Next we will have the variables of the current status and the possible states. Let's use the idea of a state machine. Initially, we need to read the first operand, then read the second operand, and finally, wait for the user's response.&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const int A = 13;
const int B = 12;
const int C = 11;
const int D = 10;
const int E = 9;
const int F = 8;
const int G = 7;
const int H = 6;

const int ledR = 4;
const int ledB = 3;
const int ledG = 2;

// máquina de estados
int STATE_READING_OP1 = 1;
int STATE_READING_OP2 = 2;
int STATE_WAITING_ANSWER = 3;
int status = STATE_READING_OP1;

int op1;
int op2;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Na função setup, que será chamada apenas uma vez, usamos a função pinMode para definir o modo de uso das portas digitais, sendo de saída. Nesta função, o primeiro parâmetro é a porta e o segundo justamente este modo. Além disso, usamos o Serial.begin para inicializar a comunicação serial, com uma taxa de 9600 bits por segundos. Por fim, usamos o randomSeed para criar números randômicos posteriormente. &lt;/p&gt;

&lt;p&gt;&lt;em&gt;In the setup function, which will be called only once, we use the pinMode function to define the mode of use of the digital ports, being output. In this function, the first parameter is the port and the second is just this mode. Also, we use Serial.begin to initialize serial communication, with a rate of 9600 bits per second. Finally, we use randomSeed to create random numbers later.&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;void setup(void)
{
  Serial.begin(9600);

  pinMode(A, OUTPUT);
  pinMode(B, OUTPUT);
  pinMode(C, OUTPUT);
  pinMode(D, OUTPUT);
  pinMode(E, OUTPUT);
  pinMode(F, OUTPUT);
  pinMode(G, OUTPUT);
  pinMode(H, OUTPUT);

  pinMode(ledR, OUTPUT);
  pinMode(ledG, OUTPUT);
  pinMode(ledB, OUTPUT);

  randomSeed(analogRead(0));
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Na sequência teremos todos os métodos que formam os números possíveis, além da função clear, que limpa o display e não mostra nenhum número. A função digitalWrite foi usada. Ela recebe dois parâmetros, a porta e o que será escrito na mesma. Arduino tem duas constantes que representam o 1 e 0, respectivamente, sendo elas HIGH e LOW. Em uma visão mais baixo nível, enviar HIGH para um porta digital, faz com que a mesma emita 5V na sua saída, e, quando mandamos LOW, a mesma envia 0V. Por isso que um segmento será ligado ou desligado, por ter ou não, uma corrente elétrica. &lt;/p&gt;

&lt;p&gt;&lt;em&gt;In the sequence we will have all the methods that form the possible numbers, in addition to the clear function, which clears the display and does not show any numbers. The digitalWrite function was used. It takes two parameters, the port and what will be written to it. Arduino has two constants that represent 1 and 0, respectively, being HIGH and LOW. In a lower level view, sending HIGH to a digital port causes it to emit 5V at its output, and when we send LOW, it sends 0V. That's why a segment will be turned on or off, whether or not it has an electric current.&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;void clear(){
  digitalWrite(A, LOW);
  digitalWrite(B, LOW);
  digitalWrite(C, LOW);
  digitalWrite(D, LOW);
  digitalWrite(E, LOW);
  digitalWrite(F, LOW);
  digitalWrite(G, LOW);
  digitalWrite(H, LOW);
}

void zero(void) {
  digitalWrite(A, LOW);
  digitalWrite(B, HIGH);
  digitalWrite(C, HIGH);
  digitalWrite(D, HIGH);
  digitalWrite(E, HIGH);
  digitalWrite(F, HIGH);
  digitalWrite(G, HIGH);
  digitalWrite(H, HIGH);
}

void one(void) {
  digitalWrite(A, LOW);
  digitalWrite(B, LOW);
  digitalWrite(C, LOW);
  digitalWrite(D, HIGH);
  digitalWrite(E, LOW);
  digitalWrite(F, LOW);
  digitalWrite(G, HIGH);
  digitalWrite(H, LOW);
}

void two(void) {
  digitalWrite(A, HIGH);
  digitalWrite(B, LOW);
  digitalWrite(C, HIGH);
  digitalWrite(D, HIGH);
  digitalWrite(E, HIGH);
  digitalWrite(F, HIGH);
  digitalWrite(G, LOW);
  digitalWrite(H, LOW);
}

void three(void) {
  digitalWrite(A, HIGH);
  digitalWrite(B, LOW);
  digitalWrite(C, HIGH);
  digitalWrite(D, HIGH);
  digitalWrite(E, LOW);
  digitalWrite(F, HIGH);
  digitalWrite(G, HIGH);
  digitalWrite(H, LOW);
}

void four(void) {
  digitalWrite(A, HIGH);
  digitalWrite(B, HIGH);
  digitalWrite(C, LOW);
  digitalWrite(D, HIGH);
  digitalWrite(E, LOW);
  digitalWrite(F, LOW);
  digitalWrite(G, HIGH);
  digitalWrite(H, LOW);
}

void five(void) {
  digitalWrite(A, HIGH);
  digitalWrite(B, HIGH);
  digitalWrite(C, HIGH);
  digitalWrite(D, LOW);
  digitalWrite(E, LOW);
  digitalWrite(F, HIGH);
  digitalWrite(G, HIGH);
  digitalWrite(H, LOW);
}

void six(void) {
  digitalWrite(A, HIGH);
  digitalWrite(B, HIGH);
  digitalWrite(C, HIGH);
  digitalWrite(D, LOW);
  digitalWrite(E, HIGH);
  digitalWrite(F, HIGH);
  digitalWrite(G, HIGH);
  digitalWrite(H, LOW);
}

void seven(void) {
  digitalWrite(A, LOW);
  digitalWrite(B, LOW);
  digitalWrite(C, HIGH);
  digitalWrite(D, HIGH);
  digitalWrite(E, LOW);
  digitalWrite(F, LOW);
  digitalWrite(G, HIGH);
  digitalWrite(H, LOW);
}

void eight(void) {
  digitalWrite(A, HIGH);
  digitalWrite(B, HIGH);
  digitalWrite(C, HIGH);
  digitalWrite(D, HIGH);
  digitalWrite(E, HIGH);
  digitalWrite(F, HIGH);
  digitalWrite(G, HIGH);
  digitalWrite(H, LOW);
}

void nine(void) {
  digitalWrite(A, HIGH);
  digitalWrite(B, HIGH);
  digitalWrite(C, HIGH);
  digitalWrite(D, HIGH);
  digitalWrite(E, LOW);
  digitalWrite(F, HIGH);
  digitalWrite(G, HIGH);
  digitalWrite(H, LOW);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No código Arduino, a função loop será repetida indefinidamente enquanto a placa estiver recebendo energia. Logo no início temos um teste lógico, verificando se o estado corrente não é esperar a resposta do usuário. Nesse caso, precisamos gerar um número aleatório, que poderá ser o operando 1 ou o operando 2.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;In Arduino code, the loop function will repeat indefinitely while the board is receiving power. At the beginning we have a logical test, verifying that the current state is not waiting for the user's response. In this case, we need to generate a random number, which can be operand 1 or operand 2.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;A variável randNumber guarda o número aleatório gerado. O switch-case verificará o valor criado e chama a função correspondente para mostrar o número no display de sete segmentos. &lt;/p&gt;

&lt;p&gt;&lt;em&gt;The randNumber variable stores the generated random number. The switch-case will check the created value and call the corresponding function to show the number on the seven-segment display.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;No último if-else precisamos saber se o estado corrente é ler o primeiro ou o segundo operando. Depois disso levando a máquina de estados para o passo seguinte, além de ter uma espera (função delay) de dois segundos (2000 milisegundos). Se o número lido for o primeiro operando, depois dessa pausa nos limpamos o display e temos uma nova espera de meio segundo. Dessa forma o usuário perceberá claramente que um novo número será apresentado. Já, se o número gerado foi o segundo operando, depois do intervalo de 2 segundos nós limpamos o display, porque, nesse caso, aguardaremos a resposta do jogador.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;In the last if-else we need to know if the current state is reading the first or second operand. After that taking the state machine to the next step, besides having a wait (delay function) of two seconds (2000 milliseconds). If the number read is the first operand, after this pause we clear the display and have a new half-second wait. In this way the user will clearly perceive that a new number will be presented. On the other hand, if the number generated was the second operand, after the 2-second interval we clear the display, because in this case, we will wait for the player's response.&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;void loop(void)
{
  if (status != STATE_WAITING_ANSWER){
    int randNumber = random(0, 10);
    switch (randNumber) {
      case 0:
        zero();
        break;
      case 1:
        one();
        break;
      case 2:
        two();
        break;
      case 3:
        three();
        break;
      case 4:
        four();
        break;
      case 5:
        five();
        break;
      case 6:
        six();
        break;
      case 7:
        seven();
        break;
      case 8:
        eight();
        break;
      default:
        nine();
    }

    if (status == STATE_READING_OP1){
      op1 = randNumber;
      status = STATE_READING_OP2;
      delay(2000);
      clear();
      delay(500);
    } else {
      op2 = randNumber;
      status = STATE_WAITING_ANSWER;
      delay(2000);
      clear();
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finalmente, precisamos ouvir os dados que chegam via porta seral. Usaremos a função serialEvent, acionada quando dados estão disponíveis no buffer serial. Enquanto (while) dados seriais estiverem disponíveis (Serial.available()) nós leremos o próximo número inteiro. Na sequência verificamos se o status corrente já é de checagem da resposta. Caso afirmativo, verificamos se a multiplicação dos dois operandos é igual a resposta informada.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Finally, we need to listen for data arriving via the seral port. We will use the serialEvent function, triggered when data is available in the serial buffer. While (while) serial data is available (Serial.available()) we will read the next integer. Next, we check if the current status is already checking the response. If so, we check if the multiplication of the two operands is equal to the given answer.&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Por fim, se a resposta estiver correta vamos mandar um valor de 255 somente para o pino digital que corresponde a esta cor, no LED RGB. Caso a resposta esteja errada a lógica é a mesma, mas com a cor vermelha. Depois do if-else temos uma nova pausa de dois segundos, na sequência, resetamos o LED para deixar sem cor e o ciclo reinicia.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Finally, if the answer is correct, we will send a value of 255 only to the digital pin that corresponds to this color, in the RGB LED. If the answer is wrong, the logic is the same, but with the color red. After the if-else we have a new two-second pause, then we reset the LED to no color and the cycle restarts.&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;void serialEvent() {
  while (Serial.available()) {
    int answer = Serial.parseInt();

    if (status == STATE_WAITING_ANSWER){
      if (answer == op1 * op2){
        digitalWrite(ledR, 0);
        digitalWrite(ledG, 255);
        digitalWrite(ledB, 0);
      } else {
        digitalWrite(ledR, 255);
        digitalWrite(ledG, 0);
        digitalWrite(ledB, 0);
      }

      delay(2000);
      digitalWrite(ledR, 0);
      digitalWrite(ledG, 0);
      digitalWrite(ledB, 0);
      status = STATE_READING_OP1;
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Importante - Important: recebi ajuda e bons pitacos dos meus alunos. I received help and good tips from my students:&lt;br&gt;&lt;br&gt;
Alexandre Akira Enjiu&lt;br&gt;
Ana Paula Soler Dos Santos&lt;br&gt;
Anderson Fábio da Silva&lt;br&gt;
Carlos Evandro Higa&lt;br&gt;
Douglas Pereira Mateus&lt;br&gt;
Erica Okamura&lt;br&gt;
Gabriel Dargas&lt;br&gt;
Gabriela Pinheiro da Silva&lt;br&gt;
Giovana Rocha Santos&lt;br&gt;
Guilherme Antonio de Souza Mauricio&lt;br&gt;
Guilherme Cristiano da Silva Costa&lt;br&gt;
Jackson dos Santos Roque da Silva&lt;br&gt;
João Rafael Iasorli Rodrigues&lt;br&gt;
Julia Assunção Silva&lt;br&gt;
Lucas Goiana Malicia&lt;br&gt;
Mariana Sayuri Kuchida&lt;br&gt;
Michael dos Santos Silva&lt;br&gt;
Vinicius Bezerra Lima&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Flutter + PubNub + NodeRED + Arduino + Raspberry + IoT + Smart House (Parte 2 - Mobile)</title>
      <dc:creator>Ricardo da Silva Ogliari</dc:creator>
      <pubDate>Sun, 04 Apr 2021 01:39:55 +0000</pubDate>
      <link>https://dev.to/ricardoogliari/flutter-pubnub-nodered-arduino-raspberry-iot-smart-house-parte-2-mobile-4343</link>
      <guid>https://dev.to/ricardoogliari/flutter-pubnub-nodered-arduino-raspberry-iot-smart-house-parte-2-mobile-4343</guid>
      <description>&lt;p&gt;Aviso 1: Antes de ler este texto, indico a leitura da &lt;a href="https://dev.to/ricardoogliari/flutter-pubnub-nodered-arduino-raspberry-iot-smart-house-parte-1-159l"&gt;primeira parte&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Aviso 2: O código fonte da aplicação mobile está disponível &lt;a href="https://github.com/ricardoogliari/Smart-Party-House"&gt;aqui&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Notice 1: Before reading this text, I recommend reading the &lt;a href="https://dev.to/ricardoogliari/flutter-pubnub-nodered-arduino-raspberry-iot-smart-house-parte-1-159l"&gt;first part&lt;/a&gt; .&lt;/p&gt;

&lt;p&gt;Notice 2: The source code of the mobile application is available &lt;a href="https://github.com/ricardoogliari/Smart-Party-House"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Aplicação Flutter. Flutter Application.&lt;/strong&gt;&lt;br&gt;
A aplicação mobile foi feita com o &lt;a href="https://flutter.dev/"&gt;Flutter framework&lt;/a&gt;. A feature de controle de mídia for fortemente baseada no artigo &lt;a href="https://medium.com/@pongpiraupra/a-comprehensive-guide-to-playing-local-mp3-files-with-seek-functionality-in-flutter-7730a453bb1a"&gt;A Comprehensive Guide to Playing Local mp3 Files (With Seek Functionality) in Flutter&lt;/a&gt;. The mobile application was made with the &lt;a href="https://flutter.dev/"&gt;Flutter framework&lt;/a&gt;. The media control feature is heavily based on the article &lt;a href="https://medium.com/@pongpiraupra/a-comprehensive-guide-to-playing-%20local-mp3-files-with-seek-functionality-in-flutter-7730a453bb1a"&gt;A Comprehensive Guide to Playing Local mp3 Files (With Seek Functionality) in Flutter&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Como a interface é bem simples, podemos usar uma classe &lt;em&gt;StatelessWidget&lt;/em&gt;, com seu ciclo de vida mais simples e sem necessidade de controle de status. The interface is very simple, then, we can use a &lt;em&gt;StatelessWidget&lt;/em&gt; class, with its simplest life cycle and without the need for status control.&lt;/p&gt;

&lt;p&gt;A construção da interface acontece na sobrescrita do &lt;em&gt;build&lt;/em&gt;, usando o par &lt;em&gt;MaterialApp -&amp;gt; Scaffold&lt;/em&gt;, com um &lt;em&gt;AppBar&lt;/em&gt; e um &lt;em&gt;body&lt;/em&gt;. O corpo é construído no método &lt;em&gt;_body&lt;/em&gt;. Temos apenas um &lt;em&gt;Center -&amp;gt; Container -&amp;gt; Column&lt;/em&gt;, contendo dois botões (criados no método &lt;em&gt;_btn&lt;/em&gt;). Além das funções normais da mídia, fazemos uma chamada ao &lt;em&gt;publishToPubnub&lt;/em&gt;, enviando por parâmetro a ação necessário. 1 indica que a lâmpada deve ser ligada e 0 que deve ser desligada. The interface construction takes place in the &lt;em&gt;build&lt;/em&gt; method, using the pair &lt;em&gt;MaterialApp -&amp;gt; Scaffold&lt;/em&gt;, with an &lt;em&gt;AppBar&lt;/em&gt; and a &lt;em&gt;body&lt;/em&gt;. The body is built using the &lt;em&gt;_body&lt;/em&gt; method. We have only one &lt;em&gt;Center -&amp;gt; Container -&amp;gt; Column&lt;/em&gt;, containing two buttons (created in the &lt;em&gt;_btn&lt;/em&gt; method). In addition to the normal functions of the media, we make a call to &lt;em&gt;publishToPubnub&lt;/em&gt;, sending the required action by parameter. 1 indicates that the lamp should be turned on and 0 that it should be turned off.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Widget _body() =&amp;gt; Center(
      child: Container(
        padding: EdgeInsets.all(16.0),
        child: Column(
          children: [
            _btn('Play', () {
              audioCache.play('one_horse_town.mp3');
              publishToPubNub(1);
            }),
            _btn('Stop', () {
              advancedPlayer.stop();
              publishToPubNub(0);
            }),
          ]
        ),
      ),
    );

  Widget _btn(String txt, VoidCallback onPressed) {
    return ButtonTheme(
        minWidth: 48.0,
        child: ElevatedButton(
            child: Text(txt),
            onPressed: onPressed
        )
    );
  }

  @override
  Widget build(BuildContext context) {
    initPlayer();
    pubnub = PubNub(defaultKeyset: myKeyset);
    myChannel = pubnub.channel('node-red');

    return Scaffold(
        appBar: AppBar(
          title: Text('Smart Party House'),
        ),
        body: _body()
      );
  }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O leitor deve ter visto que no &lt;em&gt;build&lt;/em&gt;, criamos a instância de &lt;em&gt;PubNub&lt;/em&gt; e &lt;em&gt;Channel&lt;/em&gt;. O &lt;em&gt;PubNub&lt;/em&gt; é um sistema de mensageria que segue o padrão &lt;em&gt;Publisher-Subscriber&lt;/em&gt;. Sendo que, atuamos como &lt;em&gt;publisher&lt;/em&gt; ou como &lt;em&gt;subscriber&lt;/em&gt; em um dado canal. Neste caso, chamamos o mesmo de &lt;em&gt;node-red&lt;/em&gt;. The reader must have seen that in &lt;em&gt;build&lt;/em&gt; we created the instance of &lt;em&gt;PubNub&lt;/em&gt; and &lt;em&gt;Channel&lt;/em&gt;. &lt;em&gt;PubNub&lt;/em&gt; is a messaging system that follows the &lt;em&gt;Publisher-Subscriber&lt;/em&gt; pattern. Being that, we act as &lt;em&gt;publisher&lt;/em&gt; or as &lt;em&gt;subscriber&lt;/em&gt; in a given channel. In this case, we call it &lt;em&gt;node-red&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Na instância de &lt;em&gt;PubNub&lt;/em&gt; passamos uma instância de &lt;em&gt;Keyset&lt;/em&gt;, que foi criada como uma constante da própria classe &lt;em&gt;MainWidget&lt;/em&gt;. As chaves de publisher e subscriber são criadas no console do PubNub na aplicação criada neste mesmo local. &lt;em&gt;IMPORTANTE&lt;/em&gt;: não confunda. Temos a aplicação Flutter e uma aplicação criada no console do PubNub, para termos acesso ao par de chaves pub-sub. In the instance of &lt;em&gt;PubNub&lt;/em&gt; we pass an instance of &lt;em&gt;Keyset&lt;/em&gt;, which was created as a constant of the &lt;em&gt;MainWidget&lt;/em&gt; class itself. The publisher and subscriber keys are created in the PubNub console in the application created in that same location. &lt;em&gt;IMPORTANT&lt;/em&gt;: do not confuse. We have the Flutter application and an application created on the PubNub console, to have access to the pub-sub key pair.&lt;/p&gt;

&lt;p&gt;O método &lt;em&gt;publishToPubNub&lt;/em&gt; é bem simples. Ele somente publica um dado no formato JSON para o canal criado previamente. The &lt;em&gt;publishToPubNub&lt;/em&gt; method is quite simple. It only publishes data in JSON format for the previously created channel.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;publishToPubNub(int action){
    myChannel.publish({ 'action': action });
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finalmente, faltou falar somente do método &lt;em&gt;initPlayer&lt;/em&gt;. Neste local estamos apenas criando as instâncias de &lt;em&gt;AudioPlayer&lt;/em&gt; e &lt;em&gt;AudioCache&lt;/em&gt;. Também, criamos um &lt;em&gt;listener&lt;/em&gt; para quando o áudio tocar completamente. Neste momento, apenas mandamos a ação de parar a música via PubNub. Finally, we only needed to talk about the &lt;em&gt;initPlayer&lt;/em&gt; method. In this place we are just creating the instances of &lt;em&gt;AudioPlayer&lt;/em&gt; and &lt;em&gt;AudioCache&lt;/em&gt;. Also, we created a &lt;em&gt;listener&lt;/em&gt; for when the audio plays completely. At this point, we just send the action to stop the music via PubNub.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;void initPlayer(){
    advancedPlayer = AudioPlayer();
    audioCache = AudioCache(fixedPlayer: advancedPlayer);

    advancedPlayer.onPlayerCompletion.every((element) {
      publishToPubNub(0);
      return true;
    });
  }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>flutter</category>
      <category>mobile</category>
      <category>pubnub</category>
      <category>iot</category>
    </item>
    <item>
      <title>Flutter + PubNub + NodeRED + Arduino + Raspberry + IoT + Smart House (Parte 1)</title>
      <dc:creator>Ricardo da Silva Ogliari</dc:creator>
      <pubDate>Fri, 26 Mar 2021 19:30:35 +0000</pubDate>
      <link>https://dev.to/ricardoogliari/flutter-pubnub-nodered-arduino-raspberry-iot-smart-house-parte-1-159l</link>
      <guid>https://dev.to/ricardoogliari/flutter-pubnub-nodered-arduino-raspberry-iot-smart-house-parte-1-159l</guid>
      <description>&lt;p&gt;Olá pessoal. Hey guys.&lt;/p&gt;

&lt;p&gt;Nesta série de artigos vou explicar detalhadamente um estudo de caso que implementei para mostrar aos meus alunos da graduação e MBA na IMED e FIAP, respectivamente. In this series of articles I will explain in detail a case study that I implemented to show to my students in IMED and FIAP.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A Idéia. The Idea.&lt;/strong&gt;&lt;br&gt;
Uma aplicação mobile com uma opção de tocar e parar uma música específica. Essa ação de início e paralisação do som causará uma ação de ligar e desligar uma lâmpada física na "casa inteligente". A mobile application with an option to play and stop a specific song. This action of starting and stopping the sound will cause an action to turn on or turn off a physical lamp in the "smart home".&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;O que usei no mobile?. What did I use in the mobile?&lt;/strong&gt;&lt;br&gt;
A aplicação no mobile foi criada com o Flutter. Além dos pacotes padrões que já vem com o SDK da plataforma, usei também um pacote específico para interagir com o PubNub (link &lt;a href="https://pub.dev/packages/pubnub/"&gt;aqui&lt;/a&gt;). he mobile application was created with Flutter. In addition to the standard packages that come with the platform SDK, I also used a specific package to interact with PubNub.&lt;/p&gt;

&lt;p&gt;Além disso, a parte de integração com a mídia e as ações de tocar e parar o arquivo mp3, foi fortemente baseada no artigo &lt;a href="https://medium.com/@pongpiraupra/a-comprehensive-guide-to-playing-local-mp3-files-with-seek-functionality-in-flutter-7730a453bb1a"&gt;A Comprehensive Guide to Playing Local mp3 Files (With Seek Functionality) in Flutter&lt;/a&gt;. The part of integration with the media and the actions of playing and stopping the mp3 file, was strongly based on the article [A complete guide to playing local mp3 files (with search functionality) on Flutter.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;O que usei no Cloud? What did I use in the Cloud?&lt;/strong&gt;&lt;br&gt;
Foi necessário um ponto central para integrar o aplicativo mobile com o Node-RED rodando no Raspberry Pi. A solução encontrada foi usar o &lt;a href="https://www.pubnub.com/"&gt;PubNub&lt;/a&gt;. O PubNub é um serviço de mensageria com suporte para mais de 70 SDK´s. Incluindo suporte para DART e nodes para o Node-RED. Ou seja, perfeito para meu objetivo. A central point was needed to integrate the mobile application with Node-RED running on the Raspberry Pi. The solution was found using PubNub. PubNub is a messaging service with support for more than 70 SDKs. Including support for DART and nodes for Node-RED. That is, perfect for my goal.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Você falou Node-RED? Did you say Node-RED?&lt;/strong&gt;&lt;br&gt;
Sim, correto! Usei o &lt;a href="https://nodered.org/"&gt;Node-RED&lt;/a&gt; para uma prototipagem rápida e upload do serviço no Raspberry Pi. Yes correct! I used Node-RED for quick prototyping and uploading the service to the Raspberry Pi.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;E no Hardware, o que foi usado? And no hardware, what was used?&lt;/strong&gt;&lt;br&gt;
Foi usado um Raspberry Pi 3 Model B conectado via porta serial a um Arduino Uno. No Uno, por sua vez, liguei um relê de apenas um canal que liga ou desliga a lâmpada. A Raspberry Pi 3 Model B connected via serial port on an Arduino Uno was used. In Uno, I connected a relay that turn on or turn off the lamp.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;E agora? And Now?&lt;/strong&gt;&lt;br&gt;
Nos próximos artigos desta série vamos reconstruir passo a passo o desenvolvimento do caso de uso. In the next articles in this series we will reconstruct the use case development step by step. &lt;/p&gt;

&lt;p&gt;Aguardem.... :)&lt;/p&gt;

</description>
      <category>flutter</category>
      <category>pubnub</category>
      <category>nodered</category>
      <category>iot</category>
    </item>
    <item>
      <title>Uma Idéia para Arquitetura de Aplicativos Flutter</title>
      <dc:creator>Ricardo da Silva Ogliari</dc:creator>
      <pubDate>Wed, 17 Feb 2021 02:22:28 +0000</pubDate>
      <link>https://dev.to/ricardoogliari/uma-ideia-para-arquitetura-de-aplicativos-flutter-32cn</link>
      <guid>https://dev.to/ricardoogliari/uma-ideia-para-arquitetura-de-aplicativos-flutter-32cn</guid>
      <description>&lt;p&gt;Como este texto tem como ponto central uma idéia de arquitetura para aplicações Flutter, deixe-me explicar o que uma imagem de uma espécie de casa está fazendo aqui. Ela é uma das igrejas de madeiras encontradas na Noruega. Para ser mais específico, na foto estamos vendo a Borgund Stave church. Para saber mais sobre estas igrejas impressionantes visite esta &lt;a href="https://www.visitnorway.com/typically-norwegian/stave-churches/" rel="noopener noreferrer"&gt;página&lt;/a&gt;. Devido a sua arquitetura ímpar, ela estampou a capa deste texto :).&lt;/p&gt;

&lt;h3&gt;
  
  
  Arquitetura base
&lt;/h3&gt;

&lt;p&gt;Estudando possíveis arquiteturas já existentes para desenvolvimento Flutter, encontrei o artigo "A importância da Clean Architecture no Flutter", escrito por Fabio Maia e disponível &lt;a href="https://www.objective.com.br/insights/a-importancia-da-clean-architecture-no-flutter/" rel="noopener noreferrer"&gt;aqui&lt;/a&gt;. O principal motivo por esta arquitetura chamar a minha atenção foi a semelhança com o JetPack Architecture Componentes, sendo assim, seria de fácil entendimento pelos desenvolvedores oriundos do nativo, principalmente do Android nativo. Abaixo, a imagem encontrada no artigo do Maia:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.objective.com.br%2Fwp-content%2Fuploads%2F2020%2F03%2FImagem3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.objective.com.br%2Fwp-content%2Fuploads%2F2020%2F03%2FImagem3.png"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;E abaixo você encontra um resumo alto nível das pastas que criei no projeto Flutter seguindo a estrutura proposta por Maia. Porém, não utilizei exatamente o mesmo fluxo de dados. Usei um pacote gerenciador de estados para não precisar ter o fluxo partindo dos dados até os Widgets.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fzicctq56zvivg6b03uso.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fzicctq56zvivg6b03uso.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Para ficar mais claro, veja como fica a estrutura de pastas do projeto base:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fye6ljqe8coz0fuxl7eu3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fye6ljqe8coz0fuxl7eu3.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Aplicativo Base
&lt;/h3&gt;

&lt;p&gt;O aplicativo aqui proposto é algo bem simples. Uma tela de login que leva para uma lista dos filmes preferidos, lendo os dados de um serviço web.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr9mc190603u2ad6qmaac.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr9mc190603u2ad6qmaac.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgmpd9zf70scalwt0xos6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgmpd9zf70scalwt0xos6.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  i18n no projeto
&lt;/h3&gt;

&lt;p&gt;Começamos explicando o padrão usado para internacionalização. Seguimos a documentação entitulado como "Internationalizing Flutter apps", disponível no site de desenvolvedores Flutter. Link &lt;a href="https://flutter.dev/docs/development/accessibility-and-localization/internationalization" rel="noopener noreferrer"&gt;aqui&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Devido ao uso deste guia, temos uma pasta no diretório lib chamada l10n. Dentro desta, podemos encontrar 3 arquivos extensão &lt;strong&gt;.arb&lt;/strong&gt;, definindo o conteúdo dos textos internacionalizados na aplicação. Sendo eles: &lt;strong&gt;app_en.arb&lt;/strong&gt;, &lt;strong&gt;app_es.arb&lt;/strong&gt; e &lt;strong&gt;app_pt.arb&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F1x4oxjztu7etb9doxe4i.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F1x4oxjztu7etb9doxe4i.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Abaixo, veja o conteúdo do app_en.arb:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "login": "Log in",
  "@login": {},

  "user": "User",
  "@user": {},
  "enterUser": "Enter your user",
  "@enterUser": {},
  "pleaseEnterUser": "Please, enter your user",
  "@pleaseEnterUser": {},

  "password": "Password",
  "@password": {},
  "enterPassword": "Enter your password",
  "@enterPassword": {},
  "pleaseEnterPassword": "Please, enter your password",
  "@pleaseEnterPassword": {}
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O uso do arroba no nome do recurso de texto serve para adição de uma possível descrição do que é este recurso de texto. Aqui não foi usado, porém, é perfeitamente possível sua utilização. Outro ponto. Estas descrições só são exigidas no template do arquivo de internacionalização (vamos falar sobre isso na sequência). Ou seja, o conteúdo do arquivo &lt;strong&gt;app_es.arb&lt;/strong&gt; não contém os recursos precedidos pelo arroba:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "login": "Iniciar Sessión",

  "user": "Usuario",
  "enterUser": "Ingrese su  usuario",
  "pleaseEnterUser": "Por favor, ingrese su usuario!",

  "password": "Contraseña",
  "enterPassword": "Ingressa tu contraseña",
  "pleaseEnterPassword": "Por favor, introduzca su contraseña!"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Na pasta raiz do projeto, também temos um arquivo &lt;strong&gt;l10n.yaml&lt;/strong&gt;, crucial para a internacionalização. Seu conteúdo clarifica algumas coisas que mostramos anteriormente:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;arb-dir: lib/l10n
template-arb-file: app_en.arb
output-localization-file: app_localizations.dart
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Falta pouco. Outra alteração é necessária no &lt;strong&gt;pubspec.yaml&lt;/strong&gt;. Na sub-seção de &lt;strong&gt;dependencies&lt;/strong&gt; adicionamos o &lt;strong&gt;flutter_localizations&lt;/strong&gt;. Na sub-seção &lt;strong&gt;flutter&lt;/strong&gt;, colocamos a propriedade &lt;strong&gt;generate&lt;/strong&gt; com valor &lt;strong&gt;true&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;...

dependencies:
  flutter_localizations: # Add this line
    sdk: flutter

...

# The following section is specific to Flutter.
flutter:
  generate: true
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;E para completar a configuração de i18n é necessário a configuração de alguns &lt;strong&gt;delegates&lt;/strong&gt; na MaterialApp. Os três pontos indicam parte do código que será visto na sequência e não importância neste momento.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;...

class MyApp extends StatelessWidget {

  @override
  Widget build(BuildContext context) {
    return GetMaterialApp(
      localizationsDelegates: AppLocalizations.localizationsDelegates,
      supportedLocales: AppLocalizations.supportedLocales,
      ...
    );
  }

}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Configurações Globais
&lt;/h3&gt;

&lt;p&gt;Neste projeto também tomei o cuidado de encontrar um pacote que facilitasse a criação de configurações globais, como definição de url´s, pensando da divisão do projeto em flavors, ou ainda, alguma chave de api usada na aplicação, como Google Maps ou alguma chave de web service, por exemplo.&lt;/p&gt;

&lt;p&gt;O primeiro passo é criar uma pasta &lt;strong&gt;assets-&amp;gt;cgf&lt;/strong&gt; com um arquivo &lt;strong&gt;app_settings.json&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fyzbpcayuch3sg4bme0cf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fyzbpcayuch3sg4bme0cf.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;O conteúdo deste arquivo pode ser visto aqui:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "api_key": "ae5319efd54af97f99f70e5******"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No momento só temos a chave de api para consumir um serviço web, que veremos na sequência. Porém, qualquer outra configuração global pode ser inserida aqui respeitando a estrutura do arquivo json.&lt;/p&gt;

&lt;p&gt;Algumas alterações também são necessárias no &lt;strong&gt;pubspec.yaml&lt;/strong&gt;. Na parte de dependências, adicione o pacote &lt;strong&gt;global_configuration&lt;/strong&gt; seguido pela sua última versão. Na sub-seção &lt;strong&gt;flutter&lt;/strong&gt; -&amp;gt; &lt;strong&gt;assets&lt;/strong&gt; adicione o caminho do arquivo de configurações json.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;dependencies:
  ...
  global_configuration: ^1.6.0

flutter:
  ...
  assets:
    - assets/cfg/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Por fim, precisamos apenas carregar essas configurações em algum momento na nossa árvore de widgets. Eu preferi fazer isso logo na inicialização da aplicação:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;void main() async{
  WidgetsFlutterBinding.ensureInitialized();
  await GlobalConfiguration().loadFromAsset("app_settings");
  runApp(MyApp());
}

class MyApp extends StatelessWidget {

  ...

}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Link para o pacote &lt;strong&gt;global_configuration&lt;/strong&gt; &lt;a href="https://pub.dev/packages/global_configuration" rel="noopener noreferrer"&gt;aqui&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Posteriormente, vamos usar os valores destas configurações na aplicação.&lt;/p&gt;

&lt;h3&gt;
  
  
  Menção honrosa: Get
&lt;/h3&gt;

&lt;p&gt;Usamos diversos pacotes nesse modelo de arquitetura, porém, um deles merece destaque, porque foi usado em diversos momentos da aplicação. Estamos falando do &lt;em&gt;Get&lt;/em&gt;. Sua documentação pode ser encontrada &lt;a href="https://pub.dev/packages/get" rel="noopener noreferrer"&gt;aqui&lt;/a&gt;. Usamos este pacote para gerenciamento de estados, controle de rotas e controle de dependências.&lt;/p&gt;

&lt;h3&gt;
  
  
  Rotas e Injeção de Dependência com Get
&lt;/h3&gt;

&lt;p&gt;No arquivo &lt;em&gt;main.dart&lt;/em&gt;, veremos o uso do Widget GetMaterialApp, um pouco incomum, visto que, o “normal” seria o MaterialApp. Isso foi necessário para a configuração de rotas com o &lt;em&gt;Get&lt;/em&gt;. Perceba as propriedades &lt;em&gt;initialRoute&lt;/em&gt; e &lt;em&gt;getPages&lt;/em&gt;. Este último, por sua vez, recebeu o valor routes, que está definido no arquivo &lt;em&gt;routesDefinitions&lt;/em&gt;, na pasta &lt;em&gt;lib -&amp;gt; core&lt;/em&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class MyApp extends StatelessWidget {

 @override
 Widget build(BuildContext context) {

   return GetMaterialApp(
     ...
     initialRoute: loginPageName,
     getPages: routes,
   );
 }

}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O &lt;em&gt;routesDefinitions.dart&lt;/em&gt; possui a definição de rotas, que no pacote Get é chamado de &lt;em&gt;page&lt;/em&gt;. Perceba dois pontos importantes aqui. Um deles é a definição de constantes para o nome das páginas. No momento temos apenas duas. O segundo ponto é a propriedade &lt;em&gt;binding&lt;/em&gt; na primeira página. Desta forma, criamos uma vinculação e uma dependência automática entre esta página e uma instância de &lt;em&gt;CoreBinding&lt;/em&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const String loginPageName = "/login";
const String listPageName = "/list";

final routes = [
 GetPage(
     name: loginPageName,
     page: () =&amp;gt; LoginScreen(),
     binding: CoreBinding()
 ),
 GetPage(
   name: listPageName,
   page: () =&amp;gt; ListScreen.initialize(),
 )
];
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finalmente, o &lt;em&gt;CoreBinding&lt;/em&gt; tem um código um pouco mais simples. Mas, perceba a herança com &lt;em&gt;Bindings&lt;/em&gt;. E também, a sobrescrita do &lt;em&gt;dependencies&lt;/em&gt;. Desta forma, vinculamos este método como dependência neste binding. Dentro do método estamos usando o &lt;em&gt;lazyPut&lt;/em&gt; do &lt;em&gt;Get&lt;/em&gt;, para que, quando necessário, uma instância de &lt;em&gt;RestClient&lt;/em&gt; seja fornecida, já usando o design pattern &lt;em&gt;Singleton&lt;/em&gt;. Assim, na primeira tela da aplicação já teremos criado uma instância da classe que é o ponto de conexão da aplicação com o mundo do webservice.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class CoreBinding extends Bindings{

 @override
 void dependencies() {
   Get.lazyPut&amp;lt;RestClient&amp;gt;(() =&amp;gt; RestClient(Dio()));
 }

}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Camada de Dados
&lt;/h3&gt;

&lt;p&gt;Agora que falamos sobre alguns tópicos mais gerais, podemos entrar nas camadas que fazem parte da espinha dorsal da arquitetura, e, que foi mostrada nas figuras iniciais deste texto. Na pasta lib temos uma pasta filha, chamada &lt;em&gt;dataSources&lt;/em&gt;. Dentro desta, por sua vez, temos uma pasta database para dados locais, salvos no banco de dados &lt;em&gt;NoSQL&lt;/em&gt; com um &lt;em&gt;ORM&lt;/em&gt;. E, uma pasta &lt;em&gt;webServices&lt;/em&gt; para acesso a dados de um serviço REST. &lt;/p&gt;

&lt;p&gt;No &lt;em&gt;webServices&lt;/em&gt;, usei o pacote &lt;em&gt;retrofit&lt;/em&gt;, documentação &lt;a href="https://pub.dev/packages/retrofit" rel="noopener noreferrer"&gt;aqui&lt;/a&gt;. A principal razão foi pela similaridade com uma biblioteca homônima, disponível para desenvolvimento nativo Android.&lt;/p&gt;

&lt;p&gt;Veja o conteúdo do arquivo &lt;em&gt;restClient.dart&lt;/em&gt;, que está na pasta &lt;em&gt;lib -&amp;gt; dataSources -&amp;gt; webServices&lt;/em&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;part 'restClient.g.dart';

@RestApi(baseUrl: "https://api.themoviedb.org/3")
abstract class RestClient {
 factory RestClient(Dio dio, {String baseUrl}) = _RestClient;

 @GET("/movie/top_rated")
 Future&amp;lt;ResultGroup&amp;gt; getTopRated();

}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O pacote &lt;em&gt;retrofit&lt;/em&gt; usa o &lt;em&gt;build_runner&lt;/em&gt; para geração de código automático. No &lt;em&gt;restClient.g.dart&lt;/em&gt; tem um detalhe muito importante. Estou colocando a &lt;em&gt;apikey&lt;/em&gt; do webservice &lt;em&gt;themoviedb&lt;/em&gt;, lendo esta informação do pacote de configurações globais. Veja o trecho do qual estou me referindo.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@override
Future&amp;lt;ResultGroup&amp;gt; getTopRated() async {
 const _extra = &amp;lt;String, dynamic&amp;gt;{};
 final queryParameters = &amp;lt;String, dynamic&amp;gt;{};
 final _data = &amp;lt;String, dynamic&amp;gt;{};
 final _result = await _dio.request&amp;lt;Map&amp;lt;String, dynamic&amp;gt;&amp;gt;(
     '/movie/top_rated?api_key=${GlobalConfiguration().getValue("api_key")}',
     queryParameters: queryParameters,
     options: RequestOptions(
         method: 'GET',
         headers: &amp;lt;String, dynamic&amp;gt;{},
         extra: _extra,
         baseUrl: baseUrl),
     data: _data);
 final value = ResultGroup.fromJson(_result.data);
 return value;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Já na camada de dados local, estamos usando o &lt;em&gt;Floor&lt;/em&gt;. Sendo assim, precisamos criar uma entidade, o objeto de acesso aos dados (DAO) e o banco de dados propriamente dito. &lt;/p&gt;

&lt;p&gt;A entidade está na pasta &lt;em&gt;useCases -&amp;gt; models&lt;/em&gt;, no arquivo &lt;em&gt;topRatedResponse.dart&lt;/em&gt;, na classe Result. Veja o uso da anotação &lt;em&gt;@entity&lt;/em&gt;. Também, a anotação &lt;em&gt;@JsonSerializable&lt;/em&gt;, porque estamos usando o pacote &lt;em&gt;json_serializable&lt;/em&gt; documentação está disponível &lt;a href="https://pub.dev/packages/json_serializable" rel="noopener noreferrer"&gt;aqui&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;part 'topRatedResponse.g.dart';

@entity
@JsonSerializable()
class Result {
 bool adult;
 String backdrop_path;

 @primaryKey
 int id;

 String original_language;
 String original_title;
 String overview;
 double popularity;
 String poster_path;
 String release_date;
 String title;
 bool video;
 double vote_average;
 int vote_count;

 Result({
   this.adult,
   this.backdrop_path,
   this.id,
   this.original_language,
   this.original_title,
   this.overview,
   this.popularity,
   this.poster_path,
   this.release_date,
   this.title,
   this.video,
   this.vote_average,
   this.vote_count
 });

 factory Result.fromJson(Map&amp;lt;String, dynamic&amp;gt; json) =&amp;gt; _$ResultFromJson(json);
 Map&amp;lt;String, dynamic&amp;gt; toJson() =&amp;gt; _$ResultToJson(this);
}

@JsonSerializable()
class ResultGroup {
 int page;
 int total_pages;
 int total_results;
 List&amp;lt;Result&amp;gt; results;

 ResultGroup({this.page, this.total_pages, this.total_results, this.results});

 factory ResultGroup.fromJson(Map&amp;lt;String, dynamic&amp;gt; json) =&amp;gt;
     _$ResultGroupFromJson(json);
 Map&amp;lt;String, dynamic&amp;gt; toJson() =&amp;gt; _$ResultGroupToJson(this);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O &lt;em&gt;DAO (Data Access Object)&lt;/em&gt; está na pasta &lt;em&gt;lib -&amp;gt; dataSources&lt;/em&gt;, no arquivo &lt;em&gt;topRatedDAO.dart&lt;/em&gt;. No Floor usamos exaustivamente as anotações, prova disso é o uso do &lt;em&gt;&lt;a class="mentioned-user" href="https://dev.to/dao"&gt;@dao&lt;/a&gt;&lt;/em&gt;, &lt;em&gt;@Query&lt;/em&gt; e &lt;em&gt;@insert&lt;/em&gt;. Além disso, todas são auto-expicativas.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@dao
abstract class TopRatedDao {
 @Query('SELECT * FROM Result')
 Future&amp;lt;List&amp;lt;Result&amp;gt;&amp;gt; findAllResults();

 @insert
 Future&amp;lt;List&amp;lt;int&amp;gt;&amp;gt; insertResults(List&amp;lt;Result&amp;gt; results);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Por fim, na mesma pasta referida anteriormente, encontramos o &lt;em&gt;appDatabase.dart&lt;/em&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;part 'appDatabase.g.dart'; 

@Database(version: 1, entities: [Result])
abstract class AppDatabase extends FloorDatabase {
 TopRatedDao get topRatedDAO;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;h2&gt;
  
  
  Repositórios
&lt;/h2&gt;

&lt;p&gt;Acima da camada de dados, temos os repositórios. Como nosso aplicativo ainda é muito simples, temos apenas o arquivo &lt;em&gt;moviesRepository.dart&lt;/em&gt;, na pasta &lt;em&gt;repositories&lt;/em&gt;. Nesta classes temos dois métodos, uma para chamadas remotas, ou seja, para o web service, nominado como &lt;em&gt;getRemoteTopRated&lt;/em&gt;. E, um método que busca as informações salvas no banco local, no método nomeado como &lt;em&gt;getLocalTopRated&lt;/em&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class MoviesRepository {

 void getRemoteTopRated() {
   Get.find&amp;lt;RestClient&amp;gt;().getTopRated().then((response) {
     ListScreenController controller = Get.find();
     Get.find&amp;lt;AppDatabase&amp;gt;().topRatedDAO.insertResults(response.results);
     controller.setResultGroup(response.results);
   });
 }

 void getLocalTopRated() {
   Get.find&amp;lt;AppDatabase&amp;gt;().topRatedDAO.findAllResults().then((response) {
       ListScreenController controller = Get.find();
       controller.setResultGroup(response);
     }
   );
 }

}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Aqui usamos o pacote Get para injeção de dependências. Sendo assim, apenas usamos o método estático find da classe Get para requisitar as instâncias das classes desejadas. Em ambos os casos teremos um mesmo retorno de dados, que é passado para o controller da aplicação, que veremos logo na sequência. &lt;/p&gt;

&lt;p&gt;Mas e aonde essas dependências são configuradas? Já vimos isso parcialmente, mas é um conceito importante que vale a pena ser revisto. Quanto ao &lt;em&gt;RestClient&lt;/em&gt;, isso foi feito no &lt;em&gt;CoreBinding&lt;/em&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class CoreBinding extends Bindings{

 @override
 void dependencies() {
   Get.lazyPut&amp;lt;RestClient&amp;gt;(() =&amp;gt; RestClient(Dio()));
 }

}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Quem assumir a dependência de &lt;em&gt;binding&lt;/em&gt; com esta classe recebe o método &lt;em&gt;dependencies&lt;/em&gt; por herança. Sendo assim, quando a página ligada ao &lt;em&gt;CoreBinding&lt;/em&gt; for chamada, teremos o &lt;em&gt;lazyPut&lt;/em&gt; do &lt;em&gt;Get&lt;/em&gt; chamado. E isso podemos ver no &lt;em&gt;routesDefinitions&lt;/em&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;final routes = [
 GetPage(
     name: loginPageName,
     page: () =&amp;gt; LoginScreen(),
     binding: CoreBinding()
 ),
 GetPage(
   name: listPageName,
   page: () =&amp;gt; ListScreen.initialize(),
 )
];
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Em relação ao &lt;em&gt;AppDatabase&lt;/em&gt;, sua instância foi criada no &lt;em&gt;main.dart&lt;/em&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;...

class MyApp extends StatelessWidget {

 @override
 Widget build(BuildContext context) {
   $FloorAppDatabase.databaseBuilder('app_database.db').build().then((appDb) =&amp;gt; Get.lazyPut&amp;lt;AppDatabase&amp;gt;(() =&amp;gt; appDb));

   ...
 }


}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Casos de Uso
&lt;/h3&gt;

&lt;p&gt;Neste aplicativo de exemplo, temos apenas um caso de uso. Ele está no arquivo &lt;em&gt;moviesUseCase.dart&lt;/em&gt;, dentro da pasta &lt;em&gt;useCases&lt;/em&gt;. Devido ao projeto ainda ser simples, o use cases também está simples. Ele é apenas uma camada de ligação para o repositório e a chamada ao método local ou remoto de busca de dados.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class MoviesUseCase {

 final MoviesRepository repository = MoviesRepository();

 void getRemoteTopRated() {
   return repository.getRemoteTopRated();
 }

 void getLocalTopRated() {
   return repository.getLocalTopRated();
 }

}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Camada LogicHolders
&lt;/h3&gt;

&lt;p&gt;Acima da camada de casos de uso, temos a &lt;em&gt;logicHolders&lt;/em&gt;. Dentro dela temos os bindings, já discutidos anteriormente e, os &lt;em&gt;controllers&lt;/em&gt;. Dentro do mundo Flutter, os controllers geralmente tem uma relação forte com pacotes de gerenciamento de estados, como &lt;em&gt;Provider&lt;/em&gt;, &lt;em&gt;BLoC&lt;/em&gt; ou &lt;em&gt;MobX&lt;/em&gt;, por exemplo. Aqui, vamos usar o pacote Get também para esta função.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc60xr21lwqcqwn5gr9qq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc60xr21lwqcqwn5gr9qq.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Dentro da pasta &lt;em&gt;logicHolders -&amp;gt; controllers&lt;/em&gt;, encontramos o arquivo &lt;em&gt;ListScreenControllers.dart&lt;/em&gt;. O principal ponto aqui é a variável &lt;em&gt;resultGroup&lt;/em&gt;, que é apenas um observável de uma lista comum. Desta forma, ao atualizar essa lista, como acontece no método &lt;em&gt;setResultGroup&lt;/em&gt;, chamamos o update do &lt;em&gt;GetxController&lt;/em&gt; para avisar os observadores que a lista foi alterada. Por fim, o método &lt;em&gt;getTopRated&lt;/em&gt; faz uma chamada direta ao repositório. Perceba que no momento não estamos tratando a conectividade para chamar o remote ou o local.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class ListScreenController extends GetxController{

 final moviesRepositories = MoviesRepository();

 var resultGroup = List&amp;lt;Result&amp;gt;().obs;  //observável.. programação reativa

 setResultGroup(List&amp;lt;Result&amp;gt; results) {
   resultGroup.assignAll(results);
   update();
 }

 getTopRated() =&amp;gt; moviesRepositories.getRemoteTopRated();

}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Camada de Widgets
&lt;/h3&gt;

&lt;p&gt;E a última camada na nossa arquitetura é a de &lt;em&gt;widgets&lt;/em&gt;. Na pasta screens temos uma sub-pasta &lt;em&gt;customWidgets&lt;/em&gt;, onde ficam os widgets customizados no projeto. No nosso caso temos um &lt;em&gt;TextFormField&lt;/em&gt; próprio. &lt;/p&gt;

&lt;p&gt;No &lt;em&gt;listScreen&lt;/em&gt; temos a definição do widget que mostra o formulário de login. Alguns detalhes merecem destaque:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A aquisição da instância de AppLocalizations logo no início do método build. A variável é usada em diversos momentos onde precisamos dos textos internacionalizados. &lt;br&gt;
O uso do componente customizado em diversos momentos: customTextFormField.&lt;br&gt;
A mudança para uma nova tela (na verdade outro Widget) foi feita também fazendo uso do Get. Veja o na linha &lt;em&gt;Get.offNamed(listPageName)&lt;/em&gt;. O nome da rota está no arquivo de definição de rotas: &lt;em&gt;routesDefinitions.dart&lt;/em&gt;.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class LoginScreen extends StatelessWidget {

 TextEditingController _userController = TextEditingController();
 TextEditingController _passwordController = TextEditingController();

 final _formKey = GlobalKey&amp;lt;FormState&amp;gt;();

 @override
 Widget build(BuildContext context) {
   AppLocalizations appLocalizations = AppLocalizations.of(context);

   return Scaffold(
     appBar: AppBar(
       title: Text(appLocalizations.login),
     ),
     body: Padding(
       padding: EdgeInsets.all(12),
       child: Form(
         key: _formKey,
         child: Column(
           children: &amp;lt;Widget&amp;gt;[
             customTextFormField(
               appLocalizations.enterUser,
               appLocalizations.user,
               appLocalizations.pleaseEnterUser,
               _userController
             ),
             customTextFormField(
                 appLocalizations.enterPassword,
                 appLocalizations.password,
                 appLocalizations.pleaseEnterPassword,
                 _passwordController
             ),
             Padding(
               padding: EdgeInsets.symmetric(vertical: 16.0),
               child: ElevatedButton(
                 onPressed: () {
                   if (_formKey.currentState.validate()) {
                     Get.offNamed(listPageName);
                   }
                 },
                 child: Text(appLocalizations.login),
               ),
             ),
           ],
         ),
       ),
     ),
   );
 }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Já no &lt;em&gt;listScreen&lt;/em&gt; usamos o Get de forma mais ampla. Temos um método de inicialização, apenas para inserir a instância do controlador nesta tela. Já no build, esta mesma instância singleton é recuperada. &lt;/p&gt;

&lt;p&gt;No corpo deste Widget usamos o &lt;em&gt;GetBuilder&lt;/em&gt;. Passamos a chamada ao &lt;em&gt;getTopRated&lt;/em&gt; no &lt;em&gt;initState&lt;/em&gt;. No &lt;em&gt;dispose&lt;/em&gt; também chamamos o &lt;em&gt;dispose&lt;/em&gt; do &lt;em&gt;controller&lt;/em&gt;, para não usar recursos de forma desnecessária. E, por fim, no builder chamamos o método &lt;em&gt;buildBodyWithController&lt;/em&gt;. Este método vai mostrar um loading circular ou, uma lista com os filmes mais bem ranqueados, dependendo do retorno das camadas inferiores ao widget dentro da nossa arquitetura.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class ListScreen extends StatelessWidget{

 ListScreen.initialize() {
   Get.put(ListScreenController(), permanent: true);
 }

 @override
 Widget build(BuildContext context) {
   ListScreenController controller = Get.find&amp;lt;ListScreenController&amp;gt;();

   return Scaffold(
     appBar: AppBar(
       title: Text("Top Rated"),
     ),
     body: GetBuilder&amp;lt;ListScreenController&amp;gt;(
       initState: (_) =&amp;gt; controller.getTopRated(),
       dispose: (_) =&amp;gt; controller.dispose(),
       builder: (controller) =&amp;gt; buildBodyWithController(controller),
     ),
     //Obx(() =&amp;gt; buildBody())
   );
 }

 Widget buildBodyWithController(ListScreenController controller){
   return controller.resultGroup.value == null ?
       CircularProgressIndicator() :
       ListView.builder(
           itemCount: controller.resultGroup.value.length,
           itemBuilder: (context, index) =&amp;gt; buildItemList(controller.resultGroup.value[index])
       );
 }

 Widget buildItemList(Result result) =&amp;gt; Card(
     child: ListTile(
       title: Text(result.title),
       subtitle: Text(result.overview),
     ),
 );

}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>flutter</category>
      <category>architecture</category>
      <category>mobile</category>
    </item>
  </channel>
</rss>
