ILOH 9 5HVWULWR 5HYLVWDV 5HYLVWD UHYL DVS[ · iloh 9 5hvwulwr 5hylvwdv 5hylvwd uhyl dvs[ )ljxud...

20
Page 1 of 20 Artigos 02/06/2017 file:///V:/Restrito/Revistas/201612/Revista/revi1612.aspx

Transcript of ILOH 9 5HVWULWR 5HYLVWDV 5HYLVWD UHYL DVS[ · iloh 9 5hvwulwr 5hylvwdv 5hylvwd uhyl dvs[ )ljxud...

Page 1 of 20Artigos

02/06/2017file:///V:/Restrito/Revistas/201612/Revista/revi1612.aspx

Android - Utilizando a câmera – parte 2

Caro amigo leitor, neste mês irei continuar escrevendo sobre a utilização de câmeras em dispositivos móveis, tendo como plataforma de desenvolvimento o Android Studio. No mês de Novembro, no artigo “Android – Utilizando a Câmera”, foi desenvolvido a classe base “CameraVisualizacao” a qual agrega alguns métodos e algumas funcionalidades básicas. Para este mês teremos como base o artigo do mês anterior com algumas mudanças na classe “CameraVisualizacao” e na Activity principal. A maior funcionalidade implementada será a capacidade de salvarmos a foto tirada pelo aplicativo. Então, mãos a obra.

Para isto separei este artigo com os seguintes tópicos:

- Modificação do arquivo “AndroidManifest.xml”- Modificação do lay-out principal.- Alteração e criação de novos métodos na classe “CameraVisualizacao”- Implementação de novas rotinas na atividade principal “MainActivity”.

Criando o ExemploSeguindo como base o exemplo criado no mês passado, o primeiro passo seria a alteração do arquivo de configuração

“AnroidManifest.xml”. Iremos inserir duas linhas conforme código destacado abaixo:

<?xml version="1.0" encoding="utf-8"?><manifest xmlns:android="http://schemas.android.com/apk/res/android"

package="com.example.thiago.appcamera">

<uses-permission android:name="android.permission.CAMERA" /> <uses-feature android:name="android.hardware.camera" /> <uses-feature android:name="android.hardware.camera.autofocus" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

A funcionalidade “android.hardware.camera.autofocus”, irá nos possibilitar recuperar automaticamente o foco da imagem. Já o “android.permission.WRITE_EXTERNAL_STORAGE” irá permitir a gravação da foto em nosso dispositivo no formato em que desejarmos.

Modificação do lay-out principalNo nosso lay-out principal adicionaremos um “Button” para fotografar. Ver Imagem 01.

Figura 01. Layout Principal.

Page 2 of 20Artigos

02/06/2017file:///V:/Restrito/Revistas/201612/Revista/revi1612.aspx

O XML correspondente poderemos conferir abaixo.

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

android:orientation="vertical"android:layout_width="fill_parent"android:layout_height="fill_parent"android:padding="15sp">

<SurfaceView android:id="@+id/area_view"android:layout_width="300sp"android:layout_height="0dp"android:layout_gravity="center_horizontal"android:layout_weight="1"/>

<Button android:id="@+id/bt_fotografar"android:layout_width="match_parent"android:layout_height="wrap_content"android:text="Fotografar"/>

</LinearLayout>

Alteração e criação de novos métodos na classe “CameraVisualizacao”

Implementaremos alguns novos métodos, como por exemplo o “TirarFoto” e declaramos algumas novas propriedades: a “visualizacao” e a “surfaceView”.

public class CameraVisualizacao implements SurfaceHolder.Callback{

private SurfaceHolder mHolder;private Camera mCamera;private SurfaceView surfaceView;private boolean visualizacao = false;

public CameraVisualizacao(Activity atividade, int surfaceView) {

this.surfaceView = (SurfaceView) atividade.findViewById(surfaceView);mHolder = this.surfaceView.getHolder();mHolder.addCallback(this);

}

Inicializaremos a variável “surfaceview” para logo em seguida invocarmos o método “getHolder”. O “surfaceCreated” é chamado imediatamente após o “SurfaceHolder” ser criado.

/**     * @param holder

*/@Overridepublic void surfaceCreated(SurfaceHolder holder)

{mCamera = android.hardware.Camera.open();mCamera.setDisplayOrientation(90);

}

Usaremos o método “Open” e o “setDisplayOrientation” para iniciar e definir uma orientação para a câmera.

Page 3 of 20Artigos

02/06/2017file:///V:/Restrito/Revistas/201612/Revista/revi1612.aspx

public void iniciarVisualizacao() {visualizacao = true;mCamera.startPreview();

}

Inicia o Preview da Câmera.

public void pararVisualizacao() {mCamera.stopPreview();visualizacao = false;

}

Para o Preview da Câmera.

public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {if (visualizacao) {

pararVisualizacao(); }

if (mCamera != null) {try {

mCamera.setPreviewDisplay(mHolder); iniciarVisualizacao(); } catch (IOException e) { e.printStackTrace(); } } }

Chamaremos o método “surfaceChanged” imediatamente após as alterações estruturais. Com o auxílio dos métodos “pararVisualizacao” e “iniciarVisualizacao” conseguimos parar e iniciar o preview da Câmera.

*     * @param holder

*/@Overridepublic void surfaceDestroyed(SurfaceHolder holder) {

pararVisualizacao();mCamera.release();mCamera = null;

}

Usaremos este método para liberarmos o objeto “mCamera” da memória e pararmos o preview. Importante salientar que é chamado imediatamente antes do SurfaceHolder ser destruído.

public void tirarFoto(Camera.ShutterCallback shutter, Camera.PictureCallback raw, Camera.PictureCallback jpeg) {

mCamera.takePicture(shutter, raw, jpeg); }

}

Page 4 of 20Artigos

02/06/2017file:///V:/Restrito/Revistas/201612/Revista/revi1612.aspx

Deveremos tratar a ação de tirar foto, como notamos, o método “tirarFoto()” recebe três parâmetros, sendo:

Camera.ShutterCallback shutter, Camera.PictureCallback raw, Camera.PictureCallback jpeg

O primeiro é referente a ação de tirar foto. Já o segundo e o terceiro é o retorno da imagem. Podemos recebê-la no formato RAW (segundo parâmetro) ou em JPEG (terceiro parâmetro), normalmente o modo RAW não é utilizado, por isso podemos passar o valor como null.

Implementação de novas rotinas na atividade principal “MainActivity”

O nosso controle será realizado por um “Button” e um “SurfaceView” conforme mencionado anteriormente.

import android.app.Activity;import android.os.Environment;import android.os.Bundle;import android.view.View;import android.widget.Button;import android.graphics.Bitmap;import android.graphics.BitmapFactory;import android.hardware.Camera;

import java.io.File;import java.io.FileOutputStream;

Usaremos algumas bibliotecas para trabalhar com Imagens, Câmeras e Arquivos. (Conforme Seleção acima)

public class CameraActivity extends Activity implements View.OnClickListener, Camera.ShutterCallback, Camera.PictureCallback {

Precisaremos da implementação de alguns métodos específicos da Câmera, conforme mencionado anteriormente.

private CameraVisualizacao mCameraView;private boolean emCamera;private Button botaoCamera;

@Overridepublic void onCreate(Bundle savedInstanceState)

{super.onCreate(savedInstanceState);

setContentView(R.layout.activity_camera);emCamera = true;mCameraView = new CameraVisualizacao(this, R.id.area_view);botaoCamera = (Button) findViewById(R.id.bt_fotografar);botaoCamera.setOnClickListener(this);

}

“No evento OnCreate” inicializaremos a classe “CameraVisualizacao” passando os parâmetros “Activity” e a “SurfaceView“. Faremos o uso do evento “Onclick” do “Button”.

public void onClick(View view) {

switch (view.getId()) {

case R.id.bt_fotografar:if (emCamera)

{mCameraView.tirarFoto(this, null, this);

}else{

emCamera = true;botaoCamera.setText("Fotografar");mCameraView.iniciarVisualizacao();

}break;

Page 5 of 20Artigos

02/06/2017file:///V:/Restrito/Revistas/201612/Revista/revi1612.aspx

} }

No evento “onClick” analizaremos a variável booleana “emCamera” para Tirar Foto e Parar o Preview da Câmera.

public void onShutter() {botaoCamera.setText("Câmera");emCamera = false;

}

Este é o evento responsável pela ação do clique ao tirar a foto.

/*     * @param bytes

* @param camera*/public void onPictureTaken(byte[] bytes, Camera camera) {

Bitmap foto = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);

String arquivo = "theclub.png"; File sd = Environment.getExternalStorageDirectory(); File dest = new File(sd, arquivo);

try { FileOutputStream out = new FileOutputStream(dest); foto.compress(Bitmap.CompressFormat.PNG, 90, out); out.flush(); out.close(); } catch (Exception e) { e.printStackTrace(); }

mCameraView.pararVisualizacao(); }}

Já o evento “onPictureTaken” receberá como parâmetro uma variável do tipo “byte[]” e outra do tipo “Camera”. Criaremos um objeto “Bitmap” a qual armazenaremos em memória o conteúdo fotografado. Definiremos um nome para nossa foto (Ex: theclub.png) e com o comando “getExternalStorageDirectory” recuperaremos o diretório de nosso cartão “SD”. A classe “FileOutputStream” e a “File” fará o trabalho de gravar tudo que está na memória no diretório de nosso dispositivo móvel.

Podemos conferir o aplicativo funcionando na Imagem 02.

Page 6 of 20Artigos

02/06/2017file:///V:/Restrito/Revistas/201612/Revista/revi1612.aspx

Figura 02: Aplicativo funcionando.

Conclusões

Além de implementar mais alguns recursos na classe “CameraVisualizacao”, pudemos aprender como fotografar e armazenar arquivos do tipo imagens em dispositivos móveis. Acredito que este exemplo servirá de base para quem desejar implantar este tipo de funcionalidade em seus sistemas.Vou ficando por aqui. Um forte abraço e até o ano que vem!

Sobre o autor

Thiago Cavalheiro Montebugnoli adora aprender novas tecnologias. Formado pela Faculdade de Tecnologia de Botucatu –SP (FATEC), já desenvolveu softwares utilizando a plataforma .NET, Delphi junto com Banco de Dados SQL Server e Firebird. Como experiências profissionais mais recentes, possui em seu currículo sua atuação no Centro de Processamento de Dados da Prefeitura Municipal de Itaí-SP e atualmente compõe a equipe da Coordenadoria Tecnologia da Informação no IFSP – Instituto Federal do Estado de São Paulo em Avaré. Além disso, é colunista mensal da Revista The Club Megazine e é consultor Técnico do The Club. Possui as seguintes certificações: MCP - Microsoft Certified Professional, MCTS - Microsoft Certified Technology Specialist, MCAD -Microsoft Certified Application Developer e  MCSD - Microsoft Certified Solution Developer.

Page 7 of 20Artigos

02/06/2017file:///V:/Restrito/Revistas/201612/Revista/revi1612.aspx

TPostGresConnection – Conexão com o PostgreSQL – parte II

Vamos continuar com esta parte sobre manipulação de conteúdo HTML e inserção e recuperação de arquivos via banco de dados postgresql, sendo executados a partir do nosso próprio framework, utilizando também os componentes open-source Zeos, registrando logs, comunicando com um XML (config.xml) pra acessar o banco e interagindo graficamente com o nosso usuário –vamos então discorrer gradativamente sobre a evolução da classe TConnection!

Figura 01 – Seleção principal, contendo uma lista com artigos cadastrados no banco postgresql.

A ideia desta continuação é explorar um pouco mais o funcionamento do cadastro de artigos, e sua implementação com a nossa infraestrutura baseada na classe TConnection estendida pela interface IConnection. O arcabouço desta infraestrutura foi discutida no artigo anterior, desta forma vamos partir para a continuação com outras explicações, evoluindo nosso projeto com esta nova versão implementada aqui – chamando o método getVersionedArticles da classe de artigos populará um objeto da classe TClientDataSet que carregará os dados dos artigos cadastrados e suas respectivas versões (chamando a classe TArticle e chamando o método GetDataSet da classe TConnection), fazendo isso de forma automática e transparente pro desenvolvedor. Vamos exemplificar o processo da nossa estrutura:

1. É criado um objeto de TClientDataSet no form a ser visualizado estes dados;2. É criado um objeto da classe TArticle;3. A classe é instanciada e atribuída à sua instância o método pra recuperar os artigos cadastrados na tabela de

artigos (tabelas tb01_articles e tb02_articles_version) – método Article.GetVersionedArticles(ClientDataSet1);4. Esse método por sua vez chamará uma função que retorna um objeto do tipo TDataSet, que é a VersionedArticles;5. Essa função se conectará com o banco de forma abstrata, onde instanciará encapsuladamente um objeto do tipo

TZQuery (Zeos) e a executará.

Desta forma, as funções se comunicarão com o banco sem que seja visível a comunicação em si, pois não haverá um objeto do tipo TConnection nas classes negociais (no caso a nossa TArticle) para que seja feita uma relação de comunicação com o banco. Tudo isso será feita pela nossa infraestrutura internamente, gerenciada pelo padrão de projetos singleton baseado no padrão de desenvolvimento de inversão de controle, onde os controles de chamada dos métodos são delegados ao nosso framework em vez de ser delegado ao programador, ou seja, o nosso framework tomará o controle sobre a execução do programa, gerenciando a sua comunicação com o banco postgresql.

Page 8 of 20Artigos

02/06/2017file:///V:/Restrito/Revistas/201612/Revista/revi1612.aspx

Figura 02 – Obtendo o HTML de um artigo cadastrado.

Figura 03 – Inserindo um arquivo, que será um fonte a ser inserido na tabela de fontes (tb03_sources)

Figura 04 – Informação de que os fontes foram inseridos com sucesso.

Page 9 of 20Artigos

02/06/2017file:///V:/Restrito/Revistas/201612/Revista/revi1612.aspx

Figura 05 – Confirmação (do pgAdmin/Postgresql) de que os fontes do artigo foram inseridos com sucesso.

Vamos explicar como o postgresql permitirá o “anexo” de arquivos, que serão os nossos artefatos, no nosso caso os “fontes” que cada artigo poderá ter – foi criada uma tabela de fontes, para ser associada aos artigos (cardinalidade 1 – n -> um artigo pode ter um ou mais fontes). Isso é importante, pois além de conter o html dos artigos (isso poderá ser renderizado em um site através do PHP/ASP/.NET, por exemplo) o programa também conterá os fontes relacionados a eles, podendo também serem baixados (download) tanto pelo nosso aplicativo ou aplicando a mesma ideia em um site. Para armazenamento de arquivos externos, o postgresql funciona assim:

1. É criada uma coluna do tipo OID (Object Identifier) que armazenará um código, que é a referência do anexo que foi inserido. O PostgreSQL quando vai armazenar tipos de dados grandes, como vídeos, mp3´s, etc, ele vai armazenar em duas tabelas e devolver um código, que é justamente pra referenciar estas duas tabelas. Um valor OID  não é um tipo de dado, então ele é inserido em uma tabela interna chamada pg_largeobject. O comando “select oid,* FROM pg_largeobject_metadata;” retornará todos os valores OID que foram cadastrados, isto é, todos os anexos que foram cadastrados e que deverão ser acessados através deste OID. Já o comando ”select loid,* FROM pg_largeobject;” retornará os valores OID “em partes”, pois quando um anexo é salvo no banco ele é armazenado binariamente “aos pedaços”, em vez de ser tudo de uma vez. Aí quando se quer recuperar, o banco juntará todas as partes do OID (da tabela própria do postgreschamada pg_largeobject) e permitirá a exportação “download” do arquivo;

2. O comando lo_import é pra importar os anexos pro banco e consequentemente (automaticamente) gerar os OIDsrespectivos, enquanto que a função lo_export é pra exportar (fazer download) do banco pra um diretório qualquer do computador o anexo de volta, enquanto que a função lo_unlink é pra remover o OID das tabelas pg_largeobject_metadata  e pg_largeobject, tornando inacessível, ou seja, eliminando de vez do banco.

Basicamente é isso; é simples o funcionamento; basta entender que toda vez que for inserir um arquivo (pode ser qualquer tipo: mp3, rar, zip, etc) o postgresql vai gerar um valor OID pra cada um deles, porque senão ele não vai conseguir referenciar seu anexo de dentro de si, ficando perdido. Considere abaixo um pequeno e simples exemplo pra entendimento:

CREATE TABLE tb03_sources( id_source serial NOT NULL UNIQUE, ds_source VARCHAR(1000) NOT NULL, id_article INTEGER NOT NULL, ds_local oid NULL, dt_creation TIMESTAMP NOT NULL, ds_description VARCHAR(1000) NULL, id_filetype INTEGER NOT NULL);

Page 10 of 20Artigos

02/06/2017file:///V:/Restrito/Revistas/201612/Revista/revi1612.aspx

Figura 06 – Tabela pra armazenar os valores OID.

Basicamente é isso; é simples o funcionamento; basta entender que toda vez que for inserir um arquivo (pode ser qualquer tipo: mp3, rar, zip, etc) o postgresql vai gerar um valor OID pra cada um deles, porque senão ele não vai conseguir referenciar seu anexo de dentro de si, ficando perdido. Considere abaixo um pequeno e simples exemplo pra entendimento:

procedure TForm1.SpeedButton2Click(Sender: TObject);var i: integer; strFileType: string; bFound: Boolean; idxFileType: integer;const arFileTypes: array[0..2] of array[0..1] of string = ( ('.zip','1'), ('.rar','2'), ('.7z','3'));begin OpenDialog2.InitialDir := ExtractFilePath(Application.ExeName); bFound := False;

if not OpenDialog2.Execute then Exit; try strFileType := SysUtils.ExtractFileExt(OpenDialog2.FileName); Article.Source := Biblioteca.ExtractName(OpenDialog2.FileName); Article.Id := ClientDataSet1id_article.AsInteger; Article.LocalFile := Biblioteca.GetShortFileName(OpenDialog2.FileName); Article.Name := ClientDataSet1ds_title.AsString;

for i := 0 to high(arFileTypes) do if (strFileType = arFileTypes[i, 0]) then begin

insert into tb03_sources(ds_source, id_article, ds_local, dt_creation, id_filetype)values('Classe THTMLReader', 1, lo_import('F:\Hamden\Artigos\EDIO26~1\Fontes\LerHTML.rar'),CURRENT_DATE, 2);

Comando insert pra inserir um anexo –observar o comando lo_import.

select oid,* FROM pg_largeobject_metadata; Comando select pra recuperar o valor OIDdo insert acima. Assim pode referenciar o anexo sempre que possível, para principalmente recuperar este anexo fazendo o download através do comando da linha abaixo.

select loid,* FROM pg_largeobject; Comando select pra visualizar todos os valores OID divididos temporariamente. É utilizado internamente pelo postgresql.

select lo_export(37222, 'F:/Downloads/aqui.rar');

Comando select pra recuperar (fazer download), através de um valor OID (no caso o valor OID gerado pelo insert acima foi o 37222). Então o banco vai “baixar” o anexo dele mesmo pro diretório fornecido pelo segundo parâmetro desta função lo_export.

SELECT lo_unlink(37222); Comando select pra remover o anexo de dentro do banco, utilizando como parâmetro o seu valor OID de referência.

Page 11 of 20Artigos

02/06/2017file:///V:/Restrito/Revistas/201612/Revista/revi1612.aspx

bFound := True; idxFileType := StrToIntDef(arFileTypes[i, 1], 0); Break; end;

if (bFound) then begin Article.FileType := idxFileType;

if Article.AddDocHTMLArticle then Application.MessageBox(PChar(Format('Compressed Sources of Article %s was inserted with success', [Article.Name])), 'Information', MB_OK + MB_ICONINFORMATION); end else Application.MessageBox('File Type not supported.','Information',MB_OK + MB_ICONINFORMATION);

except on E:Exception do raise Exception.Create(E.Message); end;end;

{ ... }

function TArticle.AddDocHTMLArticle: Boolean;begin Result := Connection.RunPersistenceCommand(Format(plpgsqlAddDocHTMLArticle, [Source,Id,LocalFile,FileType]));end;

{ ... }

plpgsqlAddDocHTMLArticle: string = 'temaster.add_doc_html_article (''%s'', %d, ''%s'', %d)';

{ … }

function TConnection.RunPersistenceCommand( const fCommand: string): Boolean;begin if Self is TPostGresConnection then Result := TPostGresConnection(self).RunPersistenceCommand(fCommand);end;

{ … }

function TPostGresConnection.RunPersistenceCommand( const fCommand: string): Boolean;begin fZQuery.SQL.Text := Format('select %s;', [fCommand]); try fZquery.Active := True; Result := True; FunctionResult := fZQuery.Fields[0].AsString; //returns and stores the output from called function from postgres except on E:Exception do begin Result := False; raise Exception.Create(E.Message); end; end;end;

Figura 07 – Alguns trechos de código-fonte relacionados a função de submeter fontes (função AddDocHTMLArticle).

Page 12 of 20Artigos

02/06/2017file:///V:/Restrito/Revistas/201612/Revista/revi1612.aspx

ConclusãoNesta parte compreendemos principalmente o processo de anexar e extrair arquivos vinculados ao postgresql, bem como

uma rotina para inserção de conteúdo HTML, manipulando seu conteúdo para formatar caracteres especiais e visualizando em uma grid seus dados inseridos e formatados, obtidas por uma função genérica que popula um objeto do tipo TClientDataSet e assim mostrando disponível em um componente de TDBGrid.Este processo de inserir arquivos é importante pois teoricamente permite seu armazenamento de até 4 TB por cada registro (a partir da versão 9.3 do postgresql) e 4 bilhões de registros por banco de dados. Mas é crucial que seja utilizado um bom-senso para não onerar o banco de dados, ficando muito lento sem necessidade. Uma boa dica é compactar os fontes antes de importar pro banco pra economizar espaço.

Utilizando uma tabela que guarde o OID dos fontes inseridos bem como a data de suas inserções possibilita nosso aplicativo a várias coisas bem interessantes, como gerar histórico dos fontes, logs, versionamento e download dos mesmos. É possível gerar qualquer tipo de sistema que necessite guardar anexos para sua posterior visualização, e isso poderá ser feito sempre que necessário bastando chamar a função do postgresql lo_export pra exportar estes anexos.Portanto, fica para o leitor aplicar estes conhecimentos, baseado nos fontes também entregues, para implementar soluções baseadas na manipulação de HTML e de anexos distribuídos juntamente a suas aplicações, disponíveis nas tabelas pg_largeobject e pg_largeobject_metadata.

Bons estudos a todos os desenvolvedores Delphi !!

Criando aplicações com o Ionic e o PochDB

Introdução

Nos artigos anteriores nós aprendemos como criar uma lista de contatos para celular utilizando o Ionic, uma plataforma open-source que cria aplicativos nativos através de códigos HTML e JavaScript. Agora nós iremos aprender como integrar essa lista ao banco de dados utilizando como gerenciador o PouchDB.

PouchDB

O site oficial do PouchDB (http://pouchdb.com)  o descreve como um banco de dados open-source escrito em JavaScript e inspirado no Apache CouchDB que foi desenhado para funcionar dentro do navegador. O PouchDB foi criado para ajudar os desenvolvedores a criarem aplicações que funcionem tanto off-line quanto on-line.

Instalando as Bibliotecas

Para que o Ionic funcione com o PouchDB será necessário instalar algumas bibliotecas. Primeiramente vamos adicionar o plugin SQLite Plugin 2 do Ionic, para isso abra seu terminal na pasta do nosso projeto e entre com o comando abaixo:

ionic plugin add cordova-plugin-sqlite-2

A instalação pode levar algum tempo dependendo da velocidade da sua conexão com a internet.O próximo passo é a instalação do PouchDB que também será feita através do terminal com o comando:

Page 13 of 20Artigos

02/06/2017file:///V:/Restrito/Revistas/201612/Revista/revi1612.aspx

npm install pouchdb –save

Assim como o plugin do SQLite esse comando pode demorar um tempo para executar, então não se assuste! Se um erro semelhante à Figura 1 acontecer basta executar o comando npm rebuild node-sass. Esse é um erro muito comum (principalmente se você baixou o código já pronto do site da The Club) e deve acontecer sempre que você efetuar alguma alteração no seu ambiente, como atualizar o NodeJS ou copiar o código de uma outra máquina.

Figura 1. Erro de ambiente

Como nossa aplicação é desenvolvida utilizando o TypeScript (linguagem criada encima do JavaScript que contém alguns avanços que o JavaScript não tem suporte), ela irá precisar das definições do PouchDB para compilar o código JavaScript final (que será utilizado pelo Ionic). As definições em TypeScript são instaladas normalmente através do gerenciado chamado Typings (https://github.com/typings/typings) e para utilizá-lo precisaremos instalar com o seguinte comando:

npm install typings -–global

O processo é igual a instalação do PouchDB. Com o Typings instalado vamos instalar agora as definições para que o nosso código possa ser compilado:

typings install dt~require --global –-save

Simples, não é mesmo? Agora nós podemos iniciar o desenvolvimento!

Criando um Provider

O primeiro passo será criar um serviço que será o responsável pelo encapsulamento das nossas chamadas ao PouchDB. Existem duas formas de criar um serviço, a primeira e mais difícil é criar um arquivo manualmente dentro da pasta app/providers ou criar através da linha de comando com o comando generate:

Page 14 of 20Artigos

02/06/2017file:///V:/Restrito/Revistas/201612/Revista/revi1612.aspx

ionic generate provider ContatosProvider

Nós iremos inicializar uma conexão com o banco de dados, e se caso ele ainda não exista, um novo será criado. Outro ponto que você deve observar no código abaixo é que nós passamos como adaptador o websql, desse modo o PouchDB utilizará o plugin do SQLite se ele estiver instalado, caso contrário ele irá retornar ao padrão que é o WebSQL.

import { Injectable } from '@angular/core';

import 'rxjs/add/operator/map';

let PouchDB = require('pouchdb');

/* Generated class for the Contatos provider.

See https://angular.io/docs/ts/latest/guide/dependency-injection.html for more info on providers and Angular 2 DI.*/@Injectable()

export class ContatosProvider {

private _database;

private _contatos;

initDB() {

this._database = new PouchDB('contatos', { adapter: 'websql' });

}

}

Adicionando um contato

Antes de explicar como será feito a inclusão de um novo contato, vamos criar o método dentro de nosso ContatosProvider:

add(contato) {

return this._database.post(contato);

}

Page 15 of 20Artigos

02/06/2017file:///V:/Restrito/Revistas/201612/Revista/revi1612.aspx

Você deve estar se perguntando, é tudo isso? Sim, isso é tudo que temos que fazer!Com o PouchDB você não precisa se preocupar com a escrita de nenhum INSERT ou como armazenar as informações em um banco de dados SQL, pois com o PouchDB o contato é apenas um objeto serializado no formato JSON armazenado no banco de dados.

Criando o botão adicionar contato

Antes de chamarmos o método criado anteriormente será necessário criar um botão para adicionar um novo contato. Ele será posicionado no topo direito da tela inicial do aplicativo conforme ilustra a Figura 2.

Figura 2. O botão “adicionar contato”

Edite o arquivo app/home/home.html e adicione o botão:

<ion-header>

<ion-navbar>

<ion-title>

Lista de Contatos

</ion-title>

<ion-buttons start>

<button ion-button (click)="new()">

<ion-icon ios="ios-add" md="md-add"></ion-icon>

Page 16 of 20Artigos

02/06/2017file:///V:/Restrito/Revistas/201612/Revista/revi1612.aspx

</button>

</ion-buttons>

</ion-navbar>

</ion-header>

Note que o botão irá chamar o método new() quando for clicado e que ele também possui um ícone do Ionicons igual mostrei no artigo da edição mês de novembro da The Club.O método new() é bastante simples, primeiro nós criamos um contato vazio e chamamos o método showDetalhe(). Isso mesmo, ele não irá salvar o contato no banco, ainda.

new() {

let contatoVazio = {

nome: '',

sobrenome: '',

telefone: ''

}

this.showDetalhe(contatoVazio);

}

Atenção: os atributos nome, sobrenome e telefone estão declarados como uma string vazia, portanto no código acima são duas aspas simples (‘) e não uma aspa comum (“).

Utilizando o nosso provider

Antes de realizar qualquer alteração no banco de dados será necessário ligar o nosso provider à nossa home.Você notou que a sintaxe do provider é um pouco diferente de a de uma página? A principal diferença é o tipo que é @Injectable, isso significa que a classe é injetada dentro da classe que for utilizá-la para que haja sempre uma única classe, imagina se cada página que utiliza nosso provider necessitar de uma nova conexão? Seria uma mistura dos padrões de projeto singleton e dependency injection.Chega de conversa e vamos injetar nosso provider alterando o arquivo home.ts.

import { Component } from '@angular/core';

import { NavController, ModalController } from 'ionic-angular';

Page 17 of 20Artigos

02/06/2017file:///V:/Restrito/Revistas/201612/Revista/revi1612.aspx

import { DetalhesPage } from '../detalhes/detalhes';

import { ContatosProvider } from '../../providers/contatos-provider';

@Component({

templateUrl: 'build/pages/home/home.html',

providers: [ContatosProvider]

})

export class HomePage {

private contatos = [];

constructor(

public navCtrl: NavController,

private modalCtrl: ModalController,

public contatosProvider: ContatosProvider

) {

Com a ligação pronta, é hora de utilizar o provider:

changeContato(contato) {

if(contato._id === undefined) { // novo contato

this.contatosProvider.add(contato);

} else {

//@TODO: update

}

}

Altere o changeContato() para o código acima, ele é chamado sempre que a página de detalhes é fechada e algum contato é retornado, assim ele é quem verifica que o contato deve ser alterado ou criado através do atributo _id.Atenção: diferente de nosso código anterior o identificador único do PouchDB é o _id e não id. Isso serve para que o desenvolvedor não tenha nenhuma incompatibilidade e possa usar o atributo em sua própria lógica.

Page 18 of 20Artigos

02/06/2017file:///V:/Restrito/Revistas/201612/Revista/revi1612.aspx

Atualizando o contato

Para atualizar o contato será necessário criar o método update() no provider. Se você disse que para atualizar um objeto do banco vamos utilizar somente uma linha, você acertou! Assim como o método add() o update() será assim:

update(contato) {

return this._database.put(contato);

}

E atualizando no nosso changeContato():

changeContato(contato) {

if(contato._id === undefined) { // novo contato

this.contatosProvider.add(contato);

} else {

this.contatosProvider.update(contato);

}

}

Otimizando o código

Quando chamamos o método update() do PouchDB ele verifica se o código possui o indentificador (contato._id) e atualiza o contato, se o identificador estiver vazio ou for indefinido ele automaticamente adiciona o elemento e gera um identificador, então podemos alterar o código novamente para:

changeContato(contato) {

this.contatosProvider.update(contato);

}

Conclusão

Agora nossa aplicação está começando a se tornar mais útil, pois os registros não serão perdidos ao fechar o aplicativo e como diz o ditado junto com grandes poderes vem grandes erros, portanto é importante atentar-se sempre ao utilizar um provider de injetá-lo na classe.

Page 19 of 20Artigos

02/06/2017file:///V:/Restrito/Revistas/201612/Revista/revi1612.aspx

Na próxima edição nós iremos aprender como listar todos os contatos e como excluí-los.Um ótimo natal e um feliz ano novo! Nos vemos em 2017!

Sobre o autor

Ricardo Barbosa Crivelli, mais conhecido como Rico Crivelli, é formado como Bacharel em Sistemas de Informação e Licenciado em Computação pela Universidade Estadual do Norte do Paraná, atualmente é Técnico em TI no Instituto Federal de São Paulo – Câmpus Avaré. Tem como especialidade a linguagem PHP e o framework Symfony, apesar de adorar trabalhar com front-end e desenvolvimento mobile e possuir as certificações COBiT 4.1 Foundation e Delphi 2006 Developer.

E-mail para contato: [email protected]

Caro leitor

Estamos finalizando mais um ano da revista The Club Megazine e aproveito para deixar aqui minha felicidade e gratidão por contar sempre com o seu apoio. Aproveito também para desejar um Feliz Natal e um próspero Ano Novo.Nosso colaborador Hamden Vogel continua abordando assuntos sobre o banco de dados PostgreSQL. No artigo "TPostGresConnection – Conexão com o PostgreSQL – parte II" ele demonstra como validar, inserir e recuperar os arquivos HTML em um banco de dados PostGreSQL, gerenciando a classe TPostGresConnection, reportando erros em classes de log multithread com um suporte melhorado de exceções. Nosso outro colaborador Ricardo Barbosa Crivelli redigiu o artigo “Criando aplicações com o Ionic e o PochDB”, nos ensinando a integrar uma lista ao banco de dados, utilizando como gerenciador o PouchDB. Nesta edição ele instalada todas as bibliotecas necessárias e implementa um pequeno exemplo de como devemos persistir os dados ao banco de dados. Para encerrar o ano, nosso consultor Thiago Cavalheiro Montebugnoli desenvolve a segunda parte do artigo “Android - Utilizando a câmera”, o qual implementa alguns métodos e propriedades responsáveis por tirar e armazenar fotos nos dispositivos Android.Deixo meus sinceros votos de amor, saúde e paz e que continuemos juntos o ano que vem. Um grande abraço!

Sobre o Autor

Hamden Vogel , Consultor TheClub

E-mail: [email protected]

Page 20 of 20Artigos

02/06/2017file:///V:/Restrito/Revistas/201612/Revista/revi1612.aspx