Índice
Treinamento
Da última vez acabamos sabendo que nosso servidor web recebe um nome de domínio e aprendemos a estabelecer uma conexão segura com o cliente. No entanto, ainda não temos absolutamente nada para mostrar ao nosso futuro usuário. Embora já possamos compartilhar a ideia de uma startup e anunciar a data de lançamento do MVP . Uma página da web informativa é adequada para essa tarefa. Vamos escrever no Dart usando a estrutura FlutterWeb. Todos os nossos aplicativos clientes do serviço se tornarão uma extensão desta página em particular. Tentaremos conduzir o desenvolvimento o mais adaptável e estruturado possível, para que o desenvolvimento e as montagens para as plataformas necessárias (web-android-iOS) se tornem apenas uma rotina.

Vamos começar instalando o Flutter:
- Instale o git
- Nós clonamos o repositório com a versão beta do Flutter usando o comando
git clone https://github.com/flutter/flutter.git -b beta
- Para executar comandos de flutter na linha de comando, você deve especificar o caminho para seus arquivos executáveis no sistema operacional. Vamos abrir as variáveis do SO, para isso começamos a inserir "alteração das variáveis de ambiente do usuário atual" na barra de pesquisa .Na
janela, selecione a variável Caminho e clique em Alterar . Na lista que é aberta, crie uma nova linha com o endereço dos arquivos executáveis do flutter no sistema de arquivos, por exemplo C: \ flutter \ bin - Instale a extensão VScode para flutter
- Reinicie o VScode (para que as novas variáveis do sistema operacional sejam aplicadas) e no terminal verifique o estado de flutter com o comando
flutter doctor
o mais importante aqui é que o flutter esteja instalado na versão beta (com suporte para desenvolvimento web) - Agora ativamos o desenvolvimento web com a equipe
flutter config --enable-web
Crie um novo projeto e comece a depurar
Criamos um novo projeto com uma equipe
flutter create < >
Vamos abri-lo imediatamente no VScode com o comando
code < >
Vamos abrir o arquivo main.dart na pasta lib e iniciar a depuração com o comando F5 :

Talvez quando você iniciar a depuração pela primeira vez, você precisará selecionar o Chrome como o dispositivo para depuração:

Exclua o conteúdo do arquivo main.dart . Adicione um método principal vazio e a classe raiz do aplicativo, que retorna uma instância de MaterialApp no método build () : Em seguida, crie o seguinte conjunto de subpastas do projeto: Descreva resumidamente a finalidade de cada uma delas:


- di é um mecanismo de comunicação entre os componentes do aplicativo. Todos os serviços, repositórios e clientes de rede necessários para que o aplicativo funcione serão criados e registrados aqui. Vou usar a biblioteca GetIt
- domínio - objetos de dados. Aulas de apresentação de dados
- res - cores, linhas, importações de caminhos para imagens e fontes. Qualquer coisa relacionada a recursos estáticos
- serviço - serviços para trabalhar com dados
- ui - interface
- utils - classes de utilitários
Adicione as dependências necessárias no arquivo pubspec.yaml:

Preparando para dimensionar os elementos da IU
Nossa página deve se adaptar dependendo do tamanho da tela do dispositivo cliente e localização (modo retrato ou paisagem).
Vamos começar com as fotos de fundo. A preparação deles está além do escopo do artigo, então deixarei apenas estes dois links aqui:
- Pixabay.com - repositório de fotos de conteúdo
- Paint.net - editor gráfico
Coloque as imagens finalizadas na pasta / assets / images, adicione este caminho aos recursos no arquivo pubspec.yaml:

Prefiro o acesso aos recursos na forma de uma árvore com parâmetros. Nesse caso, o caminho para a imagem de fundo do stub:
images.background(bool isPortrait).stub
Para fazer isso, na pasta res , crie o arquivo images.dart com as classes de endereço de imagem:

Para dimensionar a interface e os tamanhos de fonte, incluímos a biblioteca ScreenUtil . Sua funcionalidade se resume a duas coisas:
- Registro do tamanho da tela "base". Aqui você precisa definir a largura e a altura da tela para a qual o layout principal é executado e a necessidade de dimensionar as fontes.
- Um conjunto de extensões para aplicar um fator de escala a números (num). Por exemplo, 100.w significa que o resultado desta expressão será para uma tela de 1920 dp => 100 dp e para uma tela do iPhone8 com uma largura de 414 dp => 100x (414/1920) = 21,6 dp. Ou seja, cinco vezes menos. Existem também extensões para altura e tamanho da fonte.
Vamos criar um arquivo /utils/screen_util_ext.dart e um método de inicialização estático nele: Adicione uma

chamada ao método de inicialização de zoom para o método build () do widget raiz:

Estenda a funcionalidade da biblioteca de zoom com várias extensões adicionais no arquivo /utils/screen_util_ext.dart :



Injeção de dependência
É hora de implementar um mecanismo para criar e registrar componentes de aplicativos usando a biblioteca GetIt . Na pasta lib / DI / , crie o arquivo di_container.dart . Nele iremos escrever um método estático getItInit () e inicializar uma instância do contêiner GetIt . Vamos registrar o primeiro componente - uma instância da classe Images :

Adicione uma chamada ao método de inicialização para main () : O

acesso ao componente Images será assim:

Da mesma forma, vamos registrar uma classe com recursos com strings.
Página de esboço
Agora, na pasta UI , crie um arquivo stub.dart com a classe de página stub StubScreen , estenda a classe StatelessWidget básica e substitua seu método abstrato build () . Nossa página é uma imagem de fundo e dois blocos de informação na frente dela, colocados dependendo da orientação da tela.



Repositórios e serviço
Para exibir dinamicamente o tempo restante antes do lançamento, você deve:
- Obtenha as configurações do servidor com as datas de início do desenvolvimento e lançamento
- Criar fluxo de eventos para mudança de tempo restante
- Combine esses dados passando-os para o fluxo de saída para exibição na IU
Vamos descrever objetos de domínio (POJOs) para estes dados:


Repositórios para receber configurações e criar um fluxo de eventos:


Serviço para lógica de eventos:

Registre esses componentes em um contêiner DI:

Widget de tempo restante
O tempo restante antes do lançamento pode ser representado em 4 números: dias, horas, minutos, segundos. Vamos representar esses parâmetros como uma enumeração:

Vamos adicionar funcionalidade aos parâmetros usando a extensão: O

widget para exibir o dial, número e assinatura será animado, para isso vamos estender a classe StatefulWidget . Sua peculiaridade é que o Elemento (a visualização construída e exibida) não corresponde ao widget em si, mas ao seu estado ( Estado ). O estado, ao contrário do widget, é mutável. Ou seja, seus campos podem ser alterados sem recriar completamente a instância.


É necessário esclarecer aqui o que Animation , AnimationController e TickerProviderStateMixin são... Portanto, AnimationController é um wrapper sobre um parâmetro simples de valor duplo . O valor deste parâmetro muda linearmente no intervalo de 0,0 a 1,0 (ele também pode ser alterado na direção oposta ou redefinido para 0,0). No entanto, para alterar esse parâmetro, um objeto TickerProviderStateMixin especial é usado , que é um parâmetro obrigatório para o AnimationController e informa que o mecanismo gráfico está pronto para construir um novo quadro. Tendo recebido tal sinal, o AnimationController calcula quanto tempo se passou desde o quadro anterior e quanto tempo deve ser alterado o valor de seu valor . Objetos de animação assinam AnimationControllere contém alguma função de dependência do valor de saída na mudança linear (no tempo) do valor AnimationController .
O método de inicialização de estado initState () é chamado uma vez na criação:

Quando o estado do widget é destruído, o método dispose () é chamado :


O widget será representado por uma pilha ( Pilha ), com o AnimatedBuilder para o número e a escala colocados nele :

Resta implementar a primitiva gráfica na forma de um arco:

Adicione 4 esse widget na tela é um esboço:

Construir e lançar
Antes de construir o aplicativo, você deve substituir o nome e a descrição do aplicativo nos arquivos ./web/index.html ./web/manifest.json e pubspec.yaml .
Pare de depurar e crie a versão do aplicativo com o comando
flutter build web
O aplicativo concluído está localizado no diretório ./build/web/ . Observe que os arquivos .last_build_id e main.dart.js.map são arquivos de serviço e podem ser excluídos.
Vamos colocar o aplicativo no servidor preparado no artigo anterior. Para fazer isso, basta copiar o conteúdo do diretório ./build/web/ para / public / em nosso servidor:
scp -r ./* root@91.230.60.120:/public/
Resultado
Código fonte github
Perguntas e comentários são bem-vindos. Você pode bater um papo com o autor no canal do Telegram .
Em vez de uma conclusão
Nosso aplicativo cliente já está pronto para receber os primeiros dados do servidor - informações sobre a data de lançamento. Para fazer isso, no quarto artigo, criaremos um aplicativo de servidor esqueleto e o hospedaremos no servidor.