27 de febrer del 2018

Ionic: aplicació per saber l'hora de sortida/posta del sol (III)

Part III: Versió amb Geolocalització

Aquest article ens mostrarà com afegir geolocalització a l'aplicació per saber l'hora de sortida i posta de sol justament del lloc on ens trobem.

Fins ara hem vist:

Ara afegirem geolocalització per obtenir la posició actual del mòbil. La precisió variarà depenent de si està el GPS actiu, o si el posicionament és per les antenes de ràdio, wifi, etc... Però pel que necessitem nosaltres, serà més que suficient.

Afegim el mòdul de Geolocalització del Ionic al projecte:
$ ionic cordova plugin add cordova-plugin-geolocation \\
        --variable GEOLOCATION_USAGE_DESCRIPTION="Per posicionar-te"
$ npm install --save @ionic-native/geolocation
Ja veieu que es tracta d'un mòdul que requereix Cordova. Molts d'aquest mòduls només estan disponibles en un dispositiu físic (mòbil o tablet) i no en el navegador d'un PC. És important comprovar sempre la compatibilitat, per no tenir sorpreses.

En el cas que ens ocupa, Browser apareix llistat com a compatible, pel que sí podem utilitzar-lo en el navegador d'un PC (això sí, ens demanarà permís abans de permetre la localització).

Comprovem la documentació del propi mòdul per veure com utilitzar-lo:


Aquest codi l'afegirem a la pàgina home.ts. Però no ens hem d'oblidar d'afegir també el proveïdor Geolocation en el fitxer app.module.ts. Ens cas contrari, generaria un error de l'estil:


Ja que hi estem posats, organitzarem el codi separant la crida a l'API en una funció separada. Ens anirà bé, ja que la cridarem en un parell de situacions diferents.

També aprofitarem per generar un missatge indicant si la posició en la que es calcula és l'actual o la que hi ha per defecte (en cas de no poder usar la geolocalització). En aquest cas, donarem també un avís en la pantalla, en forma d'error o advertiment.

Bé, el codi quedaria com segueix:
import { Component } from '@angular/core';
import { NavController } from 'ionic-angular';

import { HttpClient, HttpHeaders, HttpParams } from '@angular/common/http';
import { Geolocation } from '@ionic-native/geolocation';

@Component({
  selector: 'page-home',
  templateUrl: 'home.html'
})
export class HomePage {
  API: string = "https://api.sunrise-sunset.org/json";
  
  // Estany de Sant Maurici
  lat: number = 42.582104;
  lon: number = 1.0008419;

  sunrise : string;
  sunset : string;

  posMsg : string;
  posError : boolean = false;

  constructor(  public navCtrl: NavController,
                public http: HttpClient,
                private geolocation: Geolocation
  )
  {  }

  ionViewDidLoad() {
    this.geolocation.getCurrentPosition().then((answer) => {
      //console.log(answer);
      this.lat = answer.coords.latitude;
      this.lon = answer.coords.longitude;
      this.posMsg = "Posició actual";
      this.getSunriseSunsetFromApi();

    }).catch((error) => {
       console.log('Error getting location', error);
       this.posMsg = "Per defecte";
       this.posError = true;
       this.getSunriseSunsetFromApi();
     });
  }

  getSunriseSunsetFromApi() {
    console.log("Calling API...");

    let data = {  lat: this.lat.toString(), 
                  lng: this.lon.toString(),
                  formatted: "0"
                };

    const params = new HttpParams({fromObject: data});
    const headers = new HttpHeaders().set("Accept", "application/json");
    let options = {headers: headers, params: params, withCredentials: false};

    this.http.get(this.API, options).subscribe(answer => {
      console.log(answer);

      if (answer['status']=="OK") {
        let date_options = {hour: "2-digit", minute: "2-digit"};

        this.sunrise = new Date(answer['results'].sunrise)
                            .toLocaleTimeString("ca-ES", date_options);
        this.sunset = new Date(answer['results'].sunset)
                            .toLocaleTimeString("ca-ES", date_options);

        console.log(this.sunrise);
        console.log(this.sunset);
      }
    },
    err => console.log(err)
    );    
  }
}

Observem els canvis:
  • [5] Importem el nou mòdul de geolocalització.
  • [21-22] Declarem les noves variables pel missatge del lloc i el possible error.
  • [26] Afegim el nou proveïdor de geolocalització.
  • [30-44] Ara, en carregar la pàgina provem d'obtenir la posició actual tal com en indica la documentació del mòdul. Si tot és correcte, obtenim la posició; en cas contrari, utilitzem la que tenim per defecte. En tot cas, actualitzem un missatge per l'usuari i una senyal d'error.
  • [46-75] La crida a l'API que calcula la sortida/posta de sol l'hem separat en una funció pròpia. A part d'això, no hi hem fet canvis.

També cal modificar el fitxer home.html per mostrar el nou missatge i el possible error:
 ...
<ion-content padding>
  <ion-list>
    <ion-item-divider color="light">Lloc: {{ posMsg }}</ion-item-divider>
    <ion-item color="light" *ngIf="posError">
      <h2>No s'ha pogut obtenir la posició actual</h2>
      <p>Verifica els permisos</p>
      <ion-icon name="warning" color="danger" item-left></ion-icon>
    </ion-item>
    ...

Només hi hem afegit un ion-item per mostrar un error en cas que no es pugui utilitzar la geolocalització. Fixem-nos en l'ús de l'operador *ngIf d'Angular. Amb ell, només es mostrarà l'element (i tot el seu contingut) si es compleix la condició indicada (en aquest cas, si la variable posError s'avalua com a certa [línia 41, quan salta un error en provar de geolocalitzar]).

El resultat, quan salta l'error, es pot veure a continuació:

Si mirem els missatges en la consola, podem veure que l'error que es produeix és un 403 (intent d'accedir a un recurs sense permisos adients).

En canvi, si li donem els permisos adequats, el resultat que obtenim és:

Noteu com el codi corresponent a l'error ja no es mostra ! En canvi, en la consola podem veure l'objecte que ens retorna el mòdul de geolocalització.

I d'aquesta manera tant senzilla hem aconseguit geolocalitzar l'aplicació. Com sempre, teniu tot el codi a la vostre disposició en el Github: v0.2 (amb geolocalització).

En la propera modificació, podríem afegir un calendari per escollir la data que volem, enlloc d'utilitzar l'actual.

Seguiu l'evolució de l'aplicació:

Cap comentari:

Publica un comentari a l'entrada