Cuenta Atrás en Windows 8


Descarga el código del ejemplo en codeplex.

El pasado día 22 de Marzo se realizó en el ParcBit, organizado por el grupo de usuarios Netsaimada, un gran evento sobre ALM donde participaban Luis Fraile y Rodrigo Corral. Aproveché el evento, ya que me dejaron “colarme”, para explicar el desarrollo de aplicaciones Metro en Windows 8.
En los eventos suele ocurrir que el ponente tiene más cosas que contar que tiempo en una sesión. Para evitar que las sesiones se vayan comiendo el tiempo de las siguientes, suele haber alguien de la organización que avisa al ponente cuando está agotando el tiempo.
Si esa persona soy yo es un desastre, porque se me olvida mirar el reloj, pierdo el papel con el horario de las sesiones y otras cosas por el estilo. Así que Darío me propuso hacer un cronómetro para una tableta Acer Iconia que traía con Windows 8 y pensé que no me costaría mucho desarrollar una aplicación sencilla con una cuenta atrás y un botón de iniciar y parar.




Es una aplicación hecha en pocos minutos y sin muchas pretensiones, pero nos servirá para demostrar unas cuantas características interesantes del Windows 8.

¿Qué características vamos a usar?

Para desarrollar una aplicación así tenemos que tener en cuenta unas cuantas cosas:

  • Las aplicaciones metro sólo se están ejecutando mientras están en primer plano
  • Cuando una aplicación metro pasa a segundo plano puede ocurrir que se cierre completamente
  • Las aplicaciones metro no pueden instalar nada en el sistema, todo lo que utilice la aplicación debe desplegarse con la misma. Si queremos usar una fuente de letras personalizada la debemos distribuir con la aplicación
  • Para mejorar la usabilidad de nuestra aplicación, esta debe adaptarse a los diferentes tamaños de pantalla. Añadiendo una vista acoplada podremos conseguir que nuestra aplicación sea utilizada durante más tiempo

El desarrollo

Como es una aplicación muy sencilla y queremos comprobar cómo de fácil es crear una aplicación en HTML5/Javascript, vamos a crear una aplicación con la plantilla más sencilla, la Blank Application:



Una vez creado el proyecto, vamos a programar todo en los ficheros default.html, default.js y default.css. Lo primero vamos a crear el contenedor para los dígitos, el cuadro para introducir el tiempo y los botones de start y stop dentro del body:

<body>
    <div id="timer">
        <p class="timer-time" id="time">00:00:00</p>
        <div class="timer-config" style="height: 228px;">
            <label for="length">Minutes:</label>
            <input type="number" id="length" min="1" value="60" />
            <button>Start</button>
            <button>Stop</button>
        </div>
    </div>
</body>

Y ahora podemos programar nuestro reloj, primero nos creamos una clase que nos permita inicializar un timer a una hora en concreto y saber cuánto tiempo ha pasado desde entonces. Como no tengo demasiada experiencia con JavaScript, he buscado un poco por allí y por allá y con algunos retazos de lo que me he encontrado me he creado mi propio objeto:

var downTimer = {
    time: 0,
    length: 0,
    now: function () { return (new Date()).getTime(); },
    start: function (length) { this.time = this.now(); this.length = length*1000; },
    since: function () { return this.now() - this.time; },
    last: function () {
        var l = this.length - this.since();
        if (l < 0) return this.msToTime(0);
        else
            return this.msToTime(l);
    },
    stop: function () { this.time = this.length = 0; },
    msToTime: function (s) {
            var ms = s % 1000;
            s = (s - ms) / 1000;
            var secs = s % 60;
            s = (s - secs) / 60;
            var mins = s % 60;
            var hrs = (s - mins) / 60;
            return (hrs<10?'0':'')+ hrs + ':' + (mins<10?'0':'') + mins + ':' + (secs<10?'0':'') + secs;
        }
}

Como en Javascript no tenemos clases, pero es un lenguaje dinámico, podemos crear objetos complejos sin complicarnos demasiado. En el caso anterior es un objeto singleton donde declaramos directamente las variables y funciones que vamos a utilizar. Las importantes en este objeto son las funciones start, stop y last que son las que harán todo el trabajo.

Ahora, dentro del evento app.onactivated, llamaremos a un timeout de javascript para que ejecute de manera cíclica un método de refresco para nuestro contador, cada 33 milisegundos para simular un ciclo de 30 frames por segundo, aunque con 12 o incluso 3 frames nos bastaría:

//execute at 30fps (enough)
setInterval(refresh, 33);

Definiremos la función refresh para que refresque el elemento time con el contenido de nuestra clase downtimer:

function refresh() {
    var element = document.getElementById("time");
    element.textContent = downTimer.last();
}

Para que nuestra cuenta atrás funcione sólo nos falta que los botones de start y stop tengan funcionalidad. Para hacerlo más elegante definiremos dos métodos en un espacio de nombres y así los podremos llamar bien desde la página:

WinJS.Namespace.define("defaultPage",{
    startClick: function () {
        var length = document.getElementById("length").value;
        downTimer.start(length * 60);
    },
    stopClick: function () {
        downTimer.stop();
    }
});

Una vez tenemos las funciones dentro de un espacio de nombres modificamos los botones en el default.html para que al pulsarlos se llame a las funciones que hemos definido:

<button onclick="defaultPage.startClick()">Start</button>
<button onclick="defaultPage.stopClick()">Stop</button>

Probamos la aplicación así y ya tenemos una cuenta atrás funcionado:



Aunque la pantalla nos queda algo vacía, vamos a darle un poco de estilo.

Cambiar el UI con CSS

Hasta ahora nos hemos preocupado sólo por la funcionalidad, vamos a cambiar el aspecto con unos pocos trucos de css.
Vamos primero a por el contador, me gustaría más una fuente estilo reloj digital, pero no podemos asegurarnos que el Windows 8 donde se instale la aplicación vaya a tenerla instalada, así que tendremos que encontrar una fuente que podamos distribuir con nuestra aplicación. Como estamos haciendo una aplicación HTML, lo más fácil es encontrar alguna fuente gratuita, convertirla en formato woff y distribuirla con la aplicación. Para ello añadimos la fuente a una carpeta del proyecto:

Y una vez allí, la configuramos en el default.css:

@font-face {
    font-family: 'dsdigital';
    src: url('/fonts/dsdigital.woff') format('woff');
    font-weight: normal;
    font-style: normal;
}

#timer .timer-time {
        font-family: 'dsdigital';
        font-size: 190px;        
        text-align: center;
    }

Ahora ya empieza a parecer algo más serio:



Sólo nos queda darle algo más de estilo al cuadro de texto y a los botones para que sean más adecuados para utilizar de forma táctil. Un poco más de CSS, utilizar el id de los elementos dentro del CSS no es muy adecuado, pero para hacer una demo rápida nos valdrá:

#timer .timer-config {
    position: relative;
    width: 580px;
    margin-left: auto;
    margin-right: auto;
    display: block;        
}
#timer label {
            font-size: 1.45em;
}
#timer input {
    border: #000 1px;
    height: 2em;
    font-size: 2.45em;
    text-align: right;
}
#timer button {
        width: 2em;
        background: #000;
        color: #eee8d2;
        border: #fff 1px;
        height: 2em;
            font-size: 2.45em;
            font-weight: 300;
    }

 #timer button:active {
            background: #00f;
        }

Otra cosa que me gustaría es que los botones tengan un glyph en lugar de un texto, para que se entienda en cualquier idioma. Una primera idea sería poner una imagen, pero para no tener problemas con el escalado podemos usar algunos caracteres Unicode como el Black Rectangle (25A0) y el Black Right-Pointing Pointer (25B6):

<button onclick="defaultPage.startClick()">▶</button>
<button onclick="defaultPage.stopClick()">■</button>

Y así ya tendremos la aplicación básica.

Vista Acoplada

Una de las características de las aplicaciones Metro en Windows 8 es que son a pantalla completa, pero en los dispositivos que tengan la resolución suficiente el usuario puede tener una vista acoplada a un lado de la aplicación. Esto nos ayudará a que los usuarios utilicen nuestra aplicación durante más tiempo.
En nuestro caso, crear la vista acoplada no necesitará de código javascript, nos bastará con adaptar la hoja de estilos para la que la vista quede más compacta. En la misma hoja de estilos de la página tenemos unas reglas para las diferentes vistas, editamos la vista snapped así:

@media screen and (-ms-view-state: snapped) {
    body {
        font-size: 10px;
    }
    #timer .timer-time {
        font-size: 50px;
    }
    #timer .timer-config {
        height: 230px;
        width: 315px;
        margin: 5px;
        padding: 5px;
        text-align: center;
    }
}

Y ya tenemos una vista ajustada a la ventana acoplada:


Itinerancia de datos

Ahora que nuestra aplicación ya tiene el contador, funciona y se ve bonita, le podemos añadir muy fácilmente una pequeña funcionalidad que nos vendrá bien cuando paremos nuestra aplicación o utilicemos la aplicación en varios dispositivos. Podemos guardar la información importante de nuestro temporizador en la configuración de itinerancia, que se copiará automáticamente entre los diferentes dispositivos que tengamos con Windows 8 y utilicemos con la misma cuenta LiveID.

var appdata = Windows.Storage.ApplicationData;

WinJS.Namespace.define("defaultPage",{
    startClick: function () {
        var length = document.getElementById("length").value;
        downTimer.start(length * 60);
        //store roaming
        appdata.current.roamingSettings.values["time"] = downTimer.time;
        appdata.current.roamingSettings.values["length"] = downTimer.length;
    },
    stopClick: function () {
        downTimer.stop();
        //clear roaming
        appdata.current.roamingSettings.values["time"] = null;
        appdata.current.roamingSettings.values["length"] = null;
    }
});

Ahora sólo nos queda leer el dato al arrancar la aplicación en el evento app.onactivated:

app.onactivated = function (eventObject) {
    if (eventObject.detail.kind === Windows.ApplicationModel.Activation.ActivationKind.launch) {
        var time = appdata.current.roamingSettings.values["time"];
        if (time) {
            downTimer.time = time;
            downTimer.length = appdata.current.roamingSettings.values["length"];
        }
...

Al activar la aplicación leemos la configuración, si existe, y así nuestro contador seguirá como si nada hubiera pasado.
Este ejemplo costó menos de media hora de desarrollo, me ha costado muchísimo más describirlo que hacerlo 🙂

¿Qué hemos visto?

  • Algunas características que nos proporciona Windows 8, como la vista acoplada y la configuración de itinerancia, para dar un punto de calidad a nuestra aplicación, de manera muy sencilla pues Windows 8 nos proporciona la mayor parte de la funcionalidad “out of the box”.
  • La creación de espacios de nombres (namespaces) nos ayuda a organizar el código de nuestra aplicación, y nos facilita la escritura de código gracias al intellisense.
  • La integración del código HTML5/JavaScript estándar con el código específico de la plataforma Windows 8
  • Cómo incorporar fuentes de letras con nuestra aplicación
  • Uso de caracteres especiales Unicode para tener glyphs escalables
  • La separación del diseño y la lógica del interfaz
  • Las media queries de css para adaptar la interfaz a los diferentes tamaños y orientaciones del dispositivo

Y todo esto sólo con un cronómetro, imaginad lo que podéis llegar a hacer con vuestras aplicaciones.

Descarga el código del ejemplo en codeplex.

Anuncios

  1. Pingback: Algunos ejemplos de HTML y JavaScript para aplicaciones Windows Store « Mouseless Me

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s