Apache Cordova | Añadir logo a nuestra App

Square150x150Logo.scale-240 Algo muy importante de una App es el logo, ¿por qué? Porque es algo que debe diferenciar nuestra aplicación del resto entre una maraña de logos en la pantalla de inicio de nuestro dispositivo o peor aún, entre la mayor maraña aún de aplicaciónes instaladas. Es por eso que debemos usar un logotipo que cumpla estos criterios a ser posible (salvo excepciones):

  • Simple: Fácilmente identificable y recordable.
  • Relacionado con la aplicación: Debe indicar de qué tipo de aplicación se trata
  • Original: No copiéis logos de otras aplicaciones

Una vez hayamos seleccionado el logotipo, toca crear todos los formatos para las plataformas para las que estamos desarrollando nuestra aplicación por lo que es muy importante que hayamos creado nuestro logo de forma vectorial para que no pierda calidad en cada una de las resoluciones y, como son tantas, puede ser muy útil guiarse por los que se han creado con la plantilla del proyecto y que se encuentran en la carpeta /res/icons/PLATAFORMA tal y como se muestra en la imagen a continuación.

logos-folder

Una vez creados los logotipos, sólo nos queda indicar a la plataforma que los use tal y como se indica en la documentación de Cordova aunque, si no tocamos nada… ¡Magia! El sistema directamente reconoce los logotipos de las rutas por defecto y hace su trabajo 🙂

 

windows-phone-logoandroid-logo 

Espero que os sirva.

Have fun & enjoy coding!

HTML + JavaScript | Mostrar preview de imagen o cómo mostrarlas en base64

Estos días he tenido la necesidad de trabajar con un formulario de subida de imágenes y he tenido que montar una zona para mostrar la preview de las imágenes antes de subirlas al servidor para que el usuario pueda comprobar si todo es correcto antes de completar la operación. Hace algún tiempo (algunos años) creo recordar que vi alguna respuesta del gran Pedro Hurtado en los foros de MSDN acerca de esta cuestión pero no he podido encontrar dónde lo vi. Así que lo posteo para intentar ayudar a quien se encuentre en este caso y no sepa cómo alcanzar la solución.

Bien, como os iba contando, necesitamos que antes de subir las imágenes al servidor, el usuario pueda ver qué es lo que va a subir. Entre otras muchas soluciones, creo que una de las más adecuadas es usar la cadena en base64 que forma la imagen. ¿Qué? ¿Aún no sabías que se podía hacer? Es probablemente lo que oirías de muchas personas que tienen mucha experiencia, pero como no nacemos con un manual sobre desarrollo web en la cabeza, algún día tendréis que aprender al igual que yo lo aprendí del mencionado foro con la respuesta de Pedro, así que vamos a ver cómo se muestra una imagen:

  • Desde una url pública –> <img src=”http://DOMINIO/IMAGEN.XXX” />
  • Desde una url absoluta del proyecto –> <img src=”/DIRECTORIO/IMAGEN.XXX” />
  • Desde una url relativa del proyecto –> <img src=”../DIRECTORIO/IMAGEN.XXX” />
  • Usando base64 –> <img src=»data:image/jpeg;base64{binary data}» />

Hasta aquí todo perfecto y fácil de entender. Esto se ha usado por ejemplo cuando se guardaban imágenes en un campo de una tabla en la base de datos y se querían mostrar en pantalla. Pero bien, ahora ¿cómo lo aprovecho para hacerlo desde el navegador del usuario para poder mostrar una preview de una imagen? Bueno, para esto entre otras tantas soluciones, podremos aprovechar las capacidades con JavaScript de nuestros navegadores modernos (espero que los tengáis actualizados y no me valen excusas), así que vamos a usar la api de ficheros (File) y en concreto vamos a trabajar con FileReader.

Ejemplo:

HTML

<div id="divInputLoad">

    <h1>Test it uploading your own image</h1>

    <div id="divFileUpload">

        <input id="file-upload" type="file" accept="image/*" />

    </div>

    <div id="file-preview-zone">

    </div>

</div>

 

JavaScript

<script>

    function readFile(input) {

        if (input.files && input.files[0]) {

            var reader = new FileReader();

 

            reader.onload = function (e) {

                var filePreview = document.createElement('img');

                filePreview.id = 'file-preview';

                //e.target.result contents the base64 data from the image uploaded

                filePreview.src = e.target.result;

                console.log(e.target.result);

 

                var previewZone = document.getElementById('file-preview-zone');

                previewZone.appendChild(filePreview);

            }

 

            reader.readAsDataURL(input.files[0]);

        }

    }

 

    var fileUpload = document.getElementById('file-upload');

    fileUpload.onchange = function (e) {

        readFile(e.srcElement);

    }

 

</script>

 

Como podéis observar, lo que hago es conectarme al evento “onchange” del control de selección de ficheros (al que he puesto que sólo por defecto busque imágenes) y, en cuanto reciba un cambio, se ejecuta la función readFile que recoge como parámetro el control. Se comprueba si tiene un fichero y, en caso de tenerlo (el ejemplo es para un único fichero), se crea una nueva instancia de FileReader y ejecuta la función “readAsDataURL” que leerá el fichero desde la ruta en disco.

Una vez leído el fichero, se ejecutará la función suscrita al evento “onload” de la instancia de FileReader. Entonces, se crea el DOM del elemento img donde se va a mostrar la preview y se le asigna como source “src” el resultado de la lectura del fichero que, por supuesto, está en base64. E voilà! Ya tenemos la preview de la imagen sin haberla subido al servidor.

image

Aquí tienes el código de ejemplo

download-code

Apache Cordova | Conectar una aplicación con Azure Mobile Services

posterDespués de empezar una aplicación con Apache Cordova en un artículo anterior, no sin bastantes problemas con los emuladores, habrá que darle algo de funcionalidad a esa aplicación para poder decir que sirver para algo. En este caso, lo que quiero hacer es obtener una lista de elementos de un servicio Azure Mobile Services que tengo creado para otras demos, y no es otro que mi servicio de Superhéroes (geek mode on). Así que si no habéis creado aún vuestro servicio, podéis empezar por ese paso antes de continuar con la aplicación.

Tened en cuenta que, aunque debería funcionar la forma de usarlo Azure Mobile Services que está especificada en la página de MSDN referente a Azure Mobile Services desde HTML, al menos en mi caso ha sido un problema ya que no me ha funcionado y he tenido que depurar durante un buen rato junto al gran maestre de Windows Platform Josue Yeray. ¿Por qué? Pues básicamente el plugin devuelve los datos ya formateados en objetos y no en Json.

 

Crear el servicio Azure Mobile Services

No me detendré en explicar esta parte porque creo que está más que repasada, en millones de artículos, es muy muy sencillo y siguiendo la documentación de MSDN no se tarda más de 1 minuto. Así que una vez tengáis el servicio Azure Mobile Service, ya sólo necesitáis enlazarlo con la aplicación realizada con Apache Cordova. Manos a la obra.

Configurar el servicio

Voy a hacer un pequeño inciso porque es necesario que sepamos que debemos configurar el servicio para que admita CORS (Cross-Origin Resource Sharing). ¿Que por qué? Pues es sencillo, tengamos que cuenta que estamos desarrollando con HTML+JavaScript+CSS, y que el emulador Ripple por ejemplo se ejecuta en un navegador, así que será un acceso al servicio desde un supuesto website. Esto quiere decir, que se regirá por las reglas de acceso desde un sitio web a nuestro servicio móvil en Azure.

  1. Vamos al portal de Azure (voy a hacerlo desde el portal antiguo)
  2. Seleccionar Azure Mobile Services
  3. Seleccionar el servicio
  4. Del menú, escoger la opción “Configurar”
  5. Buscar la sección “uso compartido de recursos entre orígenes (cors)
  6. En los orígenes permitidos, poner la URL de un sitio web desde el que vayamos a acceder, o de la url desde la que estemos depurando (http://localhost:XXXX), o, si queremos arriesgarnos, podemos permitir cualquier lugar de acceso poniendo “*”

azure-mobile-service

 

Instalación del plugin de Azure Mobile Services

El primer paso que debemos dar es instalar el plugin de Azure Mobile Services, para ello abrimos el archivo config.xml (si se nos abre en XML, seleccionarlo con el botón derecho del ratón y escoger “Ver diseñador” o “View designer”). Una vez se nos abra el diseñador del archivo de configuración, vamos a la pestaña “Plugins” como se puede apreciar en la imagen y seleccionamos el plugin Windows Azure Mobile Services que como podemos comprobar nos habilita su uso en iOS, Android y plataforma Windows.

select-plugin

Ahora instalamos el plugin seleccionando el botón “Add” y automáticamente se añadirá la carpeta correspondiente en “plugins” como se puede ver en la imagen.

plugin-installed

 

Obtener datos de Azure Mobile Services y mostrarlos en pantalla

Ya tenemos el plugin en nuestra aplicación, así que ya podemos hacer uso de él. Para ello, vamos al fichero “index.js” y comenzamos a hacer la “magia”.

Yo me creado una función, getSuperHeros que me devolverá los héroes de la base de datos, y otra función “displaySuperHeros” que será la encargada de generar el DOM a partir de los elementos devueltos y los muestra en pantalla. Veamos el código.

HTML “index.html”

<!DOCTYPE html>

<html>

<head>

    <meta charset="utf-8" />

    <title>SuperHero.Cordova</title>

 

    <!-- SuperHero.Cordova references -->

    <link href="css/index.css" rel="stylesheet" />

</head>

<body>

    <section id="sectionMain">

        <header><h1>SuperHero App</h1></header>

        <section id="listSuperHeros">

        </section>

    </section>

 

    <!-- Cordova reference, this is added to your app when it's built. -->

    <script src="cordova.js"></script>

    <script src="scripts/platformOverrides.js"></script>

 

    <script src="scripts/index.js"></script>

 

</body>

</html>

JavaScript “scripts/index.js”

...

...

 

var amscontext;

 

function onDeviceReady() {

    // Handle the Cordova pause and resume events

    document.addEventListener('pause', onPause.bind(this), false);

    document.addEventListener('resume', onResume.bind(this), false);

 

    // TODO: Cordova has been loaded. Perform any initialization that requires Cordova here.

    //checkConnection();

 

    amscontext = new WindowsAzure.MobileServiceClient(

            "https://NOMBRE-DEL-SERVICIO.azure-mobile.net/",

            "CLAVE-DE-APLICACIÓN-DEL-SERVICIO");

 

    getSuperHeros();

};

 

...

...

 

function getSuperHeros() {

    var superHeroTable = amscontext.getTable('superhero');

 

    superHeroTable.read().then(function (items) {

        displaySuperHeros(items);

    });

}

 

function displaySuperHeros(superHeros) {

    var superHerosContainer = document.getElementById('listSuperHeros');

    for (var i = 0; i < superHeros.length; i++) {

        var superHero = superHeros[i];

 

        var article = document.createElement('article');

        var picture = document.createElement('div');

        picture.setAttribute('class', 'hero-picture');

        picture.style.background = 'url(' + superHero.picture + ') no-repeat';

        picture.style.backgroundPosition = 'center';

        picture.style.backgroundSize = 'cover';

        article.appendChild(picture);

 

        var header = document.createElement('header');

        var title = document.createElement('h2');

        title.innerText = superHero.title;

        header.appendChild(title);

        article.appendChild(header);

 

        superHerosContainer.appendChild(article);

    }

    var a = 1;

}

Estilos “css/index.css”

body {

    background: #32004b;

    font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;

    color: #fff;

}

 

    body > section#sectionMain > header > h1 {

        font-size: 27pt;

        font-weight: 100;

        color: #ffde00;

    }

 

    #listSuperHeros > article {

        display: inline-block;

        margin: 5px 1%;

        box-sizing: border-box;

        width: 48%;

        height: 150px;

        vertical-align: top;

    }

 

        #listSuperHeros > article .hero-picture {

            width: 100%;

            height: 120px;

        }

 

        #listSuperHeros > article header h2 {

            height: 30px;

            line-height: 30px;

            white-space: nowrap;

            overflow: hidden;

            margin: 0;

            font-size: 15pt;

            font-weight: 300;

            color: #ffde00;

        }

 

Una vez tengamos todo listo, ejecutamos la aplicación y… atentos que aquí tenemos que poner una “Nota al margen”, tenemos que configurar Ripple para que haga uso del “CORS” que establece el servicio. Para ello, expandimos la sección “settings” que se encuentra en el lado derecho del navegador con Ripple y, en “Cross Domain Proxy” hay que seleccionar “Remote” tal y como se muestra en la imagen. ¡¡Hecho!! Ahora ya vemos los datos en el simulador.

ripple-result

Otro apunte más, si ejecutamos la aplicación en el emulador “nativo” de una plataforma o en nuestros dispositivos, no tendremos el problema de tener que configurar el proxi para el Cross Domain puesto que no sólo es necesario en el navegador.

Have fun & enjoy coding!!

Windows 10 | Cómo actualizar a la última versión hoy mismo

windows_10_0 Ya ha sido presentado Windows 10 con grandes novedades tanto para usuarios estándar como para empresas y la verdad es que me parece una auténtica pasada lo que se han currado en Redmond en todos los aspectos y todo lo que viene alrededor de esta nueva versión del Sistema Operativo más popular.

Ahora bien, a los que ya nos habíamos subido al carro de Windows 10 instalando la preview para poder probarlo y enviar feedback a Microsoft, nos apuraba la posibilidad de tener una actualización de dicha preview ya que hacía bastantes semanas que no veíamos ningún cambio. En la presentación, se anunció que en unos días comenzaría a llegar la actualización pero al menos en mi sistema aún no pasaba nada. Pero la clave me la dio Alberto Díaz y no es más que seguir estos pasos:

  1. Ir a la pantalla de actualizaciónes de Windows en Configuración –> Actualización y recuperación o Settings –> Update & recovery para los que lo tengamos en inglés.
  2. Seleccionar la opción del panel de la izquierda que pone “Preview updates”.
  3. Seleccionar la opción “comprobar actualizaciones” o “check updates”.

E voilà, nos aparecerá que hay una nueva actualización.

 

cortana

Una vez se descargue, le damos a instalar y tras varios reinicios tendremos por fin la ansiada actualización de Windows 10 con la versión 9926 (al menos en Enterprise).

Novedades que he apreciado a simple vista:

  • Integración con Cortana
  • Rediseño de la barra de las ventanas
  • Rediseño de los iconos de escritorio
  • Rediseño de los iconos de la barra de tareas que cuando tenemos una aplicación abierta nos pone una barrita en la parte izquierda
  • Ya vuelve a funcionar compartir escritorio con Lync
  • Cambios sutiles en el menú de inicio

image

Lamentablemente ahora hay algunas cosas que no funcionan como cabe de esperar en una preview y, por ejemplo, no podremos buscar aplicaciones directamente escribiendo tras abrir el menú de inicio, cosa que supongo que se resolverá en próximas actualizaciones 🙂 Tampoco funciona Cortana con la región que tengo especificada, así que tendré que esperar para ver todo lo que nos ofrece.

 

Enjoy Windows 10!

Fantasmas del código | ¿Problemas con Metro UI CSS 2.0 en un sitio ASP.NET MVC al publicar en Azure?

posterAunque no soy muy amigo de los elemento de ayuda a nuestros estilos porque a veces nos causan más problemas que beneficios y, sobre todo porque muchas veces podemos hacerlo mejor por nuestra cuenta, estos días he estado probando Metro UI CSS 2.0 en una aplicación web que va a ser alojada en Azure Web Sites y la verdad es que es un “plugin” muy bueno si queremos que nuestras aplicaciones tengan un look&feel con los estilos Modern UI de Microsoft.

Metro UI CSS 2.0 dispone de una gran cantidad de estilos que pueden convertir nuestro sitio en algo realmente atractivo, diferente y moderno. Entre otras muchas cosas, podemos tener lo siguiente:

  • Controles básicos: Botones, Títulos, Input, Textarea,…
  • Menús de navegación
  • Caminos de hormigas (breadcrumbs)
  • Controles avanzados: Slider, Switch, Carrusel, Listas, TreeViews, …
  • Tiles
  • Wizards
  • Calendarios y controles de fecha
  • Más controles avanzados como Rating, Progress Bar, Scroll Bar,…
  • Tablas con Datatable
  • Y mucho más

Todo ello seguro que le servirá a más de uno para construir sitios muy buenos y ganarse el “respeto” de sus clientes y, si ya sabemos hacer algunas personalizaciones, podremos construir aplicaciones complejas con un Branding adecuado para cada cliente y que nos hagan valer nuestro peso en oro. Muy muy recomendable, así que para sus creadores, mis más sinceros respetos 😛

respect

Problema

Después de la entrada que parecía publicitaria, entremos en materia y pasemos a la acción. Metro UI CSS 2.0 usa una fuente “icónica” para representar los iconos que usa en algunos de sus elementos como por ejemplo el botón de configuración con esa rueda dentada o engranaje que seguro que muchos de vosotros usaréis en vuestros sitios web. En concreto, hablaré del menú que propone este “plugin” y que como podréis observar dispone del botón de configuración en su parte derecha.

menú

Si hacemos las cosas como Microsoft nos propone, agregaremos los estilos de este plugin usando el fichero BundleConfig y creando ese “conjunto” de estilos con su alias para poder integrarlo en nuestras páginas HTML.

bundles.Add(new StyleBundle("~/Content/vendor/metroui").Include(

          "~/Content/vendor/metroui/css/metro-bootstrap.min.css",

          "~/Content/vendor/metroui/css/metro-bootstrap-responsive.min.css",

          "~/Content/vendor/metroui/css/iconFont.min.css"));

 

Ahora  implementamos el menú tal y como se nos indica en la página y lo probamos en local, voilà, todo perfecto y tendremos nuestro bonito menú Modern UI funcionando de forma perfecta, así que procedemos a publicar en Azure nuestro sitio y WTF! en Microsoft Azure no se ven los iconos de Metro UI CSS 2.0 basados en la fuente “icónica”.

Es en este momento en el que me pongo a indagar el problema y una solución al mismo y tras mucho googlear y ver posibles soluciones como cambiar el alias del “Bundle” para que no sea el prefijo de la ruta (que no me funcionó), decidí abrir el fiddler y ver qué ocurría con las peticiones que hacía el sitio web y… aquí el problema, recibimos el error 103 por algún motivo (que aún no alcanzo a entender)

fiddler 

Solución

Como ya os comenté, hay muchas personas que hablan de cambiar el alias al Bundle pero eso no funciona o al menos no funcionó en mi caso, así que busqué un poco mejor y entre artículo y artículo, se me ocurrió que hubiera algún problema entre la compresión que realiza el Bundle a la hora de y la ruta de los archivos de las fuentes dentro de las hojas de estilo (por pensar cosas absurdas), así que decidí pasar del Bundle y poner de forma explícita la instancia a las hojas de estilo de Metro UI CSS 2.0.

@Styles.Render("~/Content/vendor/metroui/css/metro-bootstrap.css")

@Styles.Render("~/Content/vendor/metroui/css/metro-bootstrap-responsive.css")

@Styles.Render("~/Content/vendor/metroui/css/iconFont.min.css")

Nuevamente probamos la publicación del sitio y… ¡Perfecto! Problema solucionado (aunque no sea de la mejor forma)

 

Enjoy coding!

Apache Cordova | Primeros pasos con mi primera App Multiplataforma

poster Desde hace ya algún tiempo Microsoft ha acogido Apache Cordova entre las tecnologías con las que podemos desarrollar en Visual Studio. Esto nos permitirá hacer uso del mejor IDE de nuestros días para poder desarrollar aplicaciones multiplataforma con HTML y JavaScript sin muchos los dolores de cabeza que nos puede generar tener que usar varios IDEs diferentes y poder conseguir desarrollar nuestras aplicaciones para todas las plataformas que deseemos de una forma muy fácil.

Preparando el entorno de desarrollo

Para empezar, lo primero que debemos tener es Visual Studio en sus versiones 2013 o 2015, preferiblemente este último ya que nos facilita mucho las cosas como veremos más adelante. El siguiente paso, será instalar Visual Studio Tools for Apache Cordova, que nos permitirá disponer de herramientas que agilizarán los desarrollos, así como una amplia gama de emuladores.

Una vez ya tengamos preparado el sistema, podemos comenzar a desarrollar nuestra aplicación.

Creando el proyecto

Comenzamos creando el proyecto desde las plantillas que nos proporcionará Visual Studio gracias a las herramientas que le hemos instalado. Para ello, seleccionamos JavaScript como lenguaje y ya podremos acceder a la plantilla de aplicación en blanco para Apache Cordova.

cordova-project-template

 

Una vez establecido el nombre del proyecto, la localización donde lo crearemos y el nombre de la solución, presionamos OK y podremos ver la estructura que ha creado la plantilla.

cordova-project-structure

 

Como se puede apreciar, es una plantilla compleja que contiene personalizaciones para la diferentes plataformas que en este caso son iOS, Android, Windows Phone y Windows, lo que nos permitirá una gran facilidad de adaptar nuestras aplicaciones sea cual sea el caso. Es muy importante tener en cuenta los ficheros index.html e index.js.

Primera ejecución del proyecto

En este punto, la aplicación ya es funcional y podemos ejecutar el proyecto para cualquiera de las plataformas y en cualquiera de los emuladores provistos

cordova-targets

cordova-emulators

 

Por ejemplo, si seleccionamos Android y VS Emulator Android Phone obtendremos el siguiente resultado

cordova-android-emulator

 

Esto se corresponde con lo que se establece en el fichero index.html que viene por defecto en la plantilla

image

 

Añadiendo plugins

Una de las virtudes de usar Visual Studio 2015 es que nos facilitará esta tarea, gracias a que dispone de una interfaz visual para gestionar la configuración del proyecto. Así pues, si abrimos el archivo config.xml, nos aparecerá una ventana que nos permitirá controlar los aspectos de nuestra aplicación en lugar de tener que estar editando a mano el fichero xml con los consiguientes riesgos de equivocarnos o simplemente con el problema de no saber qué poner.

Lo que podemos realizar desde esta interfaz será gestionar información común de la aplicación, los plugins que vamos a usar y que vienen predefinidos y por último configuración específica de Windows, Android e iOS, pero centrémonos en los plugins. Aquí podemos encontrar una serie de plugins muy usados, como el que nos permite acceder a la cámara, que ya nos proveen del código necesario para poder trabajar en las diferentes plataformas, con lo que nos olvidaremos de tener que reescribir el código una y otra vez y aprovecharemos esta abstracción para sólo tener que escribir qué queremos hacer que el plugin ya se encarga de ejecutar el código específico de cada plataforma.

cordova-plugins

 

Como se puede apreciar en la imagen, al seleccionar un plugin se muestra información de las plataformas para las que está preparado y sólo necesitaremos instalarlo para poder hacer uso de él de una forma muy sencilla. Por ejemplo, voy a instalar el plugin Network Information

cordova-plugin-network

 

Una vez instalado, podremos ver que se ha añadido a la carpeta “plugins” y ya podremos comenzar a utilizarlo sin tener que hacer mucho más.

cordova-plugins-installed

 

Ahora sólo tenemos que abrir el fichero index.js y ya podremos empezar a escribir nuestro código. Valga como ejemplo la muestra que nos dan en la página de GitHug del plugin y que es el siguiente:

function checkConnection() {

    var networkState = navigator.connection.type;

 

    var states = {};

    states[Connection.UNKNOWN] = 'Unknown connection';

    states[Connection.ETHERNET] = 'Ethernet connection';

    states[Connection.WIFI] = 'WiFi connection';

    states[Connection.CELL_2G] = 'Cell 2G connection';

    states[Connection.CELL_3G] = 'Cell 3G connection';

    states[Connection.CELL_4G] = 'Cell 4G connection';

    states[Connection.CELL] = 'Cell generic connection';

    states[Connection.NONE] = 'No network connection';

 

    alert('Connection type: ' + states[networkState]);

}

 

checkConnection();

 

NOTA: Para mostrar el popup tendremos que instalar el plugin “Notification”.

 

Esto dejaría el fichero de esta forma

image 

Podemos ejecutar de nuevo la aplicación, en esta ocasión lo haré en Ripple para Nexus (Galaxy), en Ripple para iPhone y en el emulador de Windows Phone y veremos como resultado que nos sale un popup mostrando el estado de la conexión.

windows-phone

Windows Phone

 

ripple-android Ripple Android – Nexus (Galaxy)

ripple-iphone

Ripple iPhone

 

NOTA IMPORTANTE: Si al ejecutar tenemos problemas con que no puede abrir Ripple, o el emulador de Android porque no puede ejecutar el fichero adb.exe o incluso tampoco nos abre el emulador de Windows Phone, podemos probar una de estas soluciones:

Solución 1: Eliminar la caché de Cordova en Herramientas –> Opciones –> Tools for Apache Cordova y seleccionamos Clear Cordova Cache.

Solución 2: Ir a la carpeta del proyecto eliminar el fichero .suo , mostrar elementos ocultos y eliminar también el fichero .suo que se encuentra en .vsNOMBRE_PROYECTOv14

 

Espero que este artículo os anime a usar Apache Cordova y hagáis buenas aplicaciones CrossPlatform

 

Enjoy coding!

Pinta y colorea | Cuando el cliente quiere diseñar un sitio web o una aplicación

niños-pintando-arboles-navideños Esto es un artículo de “crítica” hacia aquellos clientes que creen ser diseñadores, aquellos que ven un color (o varios), un dibujo (o varios), una maquetación (o varias) y lo quiere todo en su site. Es muy común entre los que desarrollamos aplicaciones para clientes encontrarnos con que los mismos quieren “dirigir” cómo se diseña su página y, me parece bien que nos cuenten sus ideas generales pero no que las quieren imponer. Os preguntaréis “¿Por qué? ¿Pero si así me ahorro romperme los sesos pensando en una buena experiencia de usuario y en la usabilidad?” y diréis “pero si me está pagando y está haciendo él el trabajo”. Desde mi punto de vista es un error grave tanto por parte del cliente como por nuestra parte permitírselo y os explicaré por qué.

Conocimiento

Auto conocimientoGeneralmente (por no decir siempre) dichos clientes tienen los mismos conocimientos que yo de ingeniería aeroespacial, es decir, ninguno y se basan en cosas “bonitas” que han visto en algún lugar o cosas que ven en otros lugares y que les parecen que son “estándares”. Bajo mi experiencia y por lo que he podido estudiar, no hay “estándares” en cuanto a diseño, UX y maquetación se trata sino que tenemos unas reglas básicas que seguir y que muy pocas veces vemos en práctica en aplicaciones y sitios web bastante más comunes de lo que me gustaría. Por ejemplo, hay muchas tiendas online populares que han sacrificado la usabilidad y la experiencia de usuario para aumentar la funcionalidad en cada página y a menudo me encuentro en alguna de estas tiendas buscando algún elemento como “¿dónde están los artículos que he comprado (ebay)?”. Quizás la razón no sea ni siquiera esa, sino que más allá de querer tener más funcionalidad, dichos sitios nunca hayan pasado por la mano de alguien con algún criterio de diseño, experiencia de usuario, usabilidad,… Entonces, ¿por qué si sabemos que dichos sites hacen las cosas mal dejamos que el cliente nos obligue a copiarlo? ¿Acaso valoramos tan poco nuestro trabajo, nuestro criterio y por tanto a nosotros mismos?

Confianza

confianza.jpg_2033098437Los clientes, que son los que nos pagan, a menudo tienen un cambio de confianza en cuanto empezamos el proyecto, por un lado se toman mayor confianza y nos tratan como si fuéramos sus empleados exigiendo a veces cosas sin sentido y, por otro lado, en cuanto hemos empezado es como si perdieran la confianza en que nosotros somos los “expertos” en lo que nos han coontratado y dejan de guiarse por nuestro criterio tratando de imponer el suyo porque, claro… es el acertado y nosotros no sabemos de nuestro trabajo. Es como si lleváramos nuestros coche al taller y en cuanto el mecánico empieza a trabajar le decimos cómo lo tiene que arreglar… Si fuera así, creo que los desguaces estarían desbordados y sería el negocio en auge.

 

Calidad de trabajo

calidad¿Alguna vez habéis intentado pintar un cuadro? ¿Habéis visto a un pintor trabajar? ¿Notáis alguna diferencia? La diferencia es la calidad del trabajo (amén de que el pintor tarda menos si trabaja tranquilo) y será mucho más creativo. Como una imagen vale más que mil palabras… aquí va un ejemplo muy famoso y que plasma muy bien la diferencia entre un profesional y un “algo”, así que aquí tenéis el Cristo de Borja que una señora sin más conocimientos de pintura que los de una “aficionada” le hizo un “cristo” al Cristo…

 

cristo-de-borja

Conclusión

¿Qué tipo de profesional eres y cuál quieres ser? ¿Le das valor a tu nombre que es tu marca personal? ¿Quieres que te conozcan por chapuzas o por profesional? Al final el trabajo, sea con tu diseño o sea con el que te diga el cliente, llevará tu nombre y eso te dará valor o te lo restará. Con esta premisa, desde un primer momento debemos dejar claro a nuestro clientes que nosotros somos los profesionales, que sus ideas aportan valor en cuanto nos permiten conocer qué espera de la aplicación pero como norma general, esas mismas ideas no serán plasmadas como originalmente las pensó sino que se estudiará la forma de que la funcionalidad sea la que quiera el cliente con un diseño acorde a lo que realmente necesita y, sobre todo, que no se debe atar a lo que ha visto, si no, aún iríamos con una hoja para tapar nuestras zonas íntimas…

Así que, “Cliente, deja diseñar al diseñador y deja programar al desarrollador que para eso le has pagado un caché”.

jQuery | Versión Alpha de mi propio plugin de jQuery, sliderFS

poster Hace algunas semanas estuve buscando un plugin jQuery con el que poner un “slider” a pantalla completa con imágenes de background para un sitio web que estoy diseñando. Tras una larga búsqueda en la que me centraba en bastantes criterios (ligero, sencillo, actualizado, html, responsive, touchable) encontré varios candidatos para ser incluídos pero ninguno de ellos llegó a convencerme.

Probé más de una decena de sliders sin suerte ya que encontré algunos que no parecen estar muy testeados y otros que no parecen haber sido pensados para usar fácilmente y requerían de una cantidad de parámetros exagerada (debe ser que no se conocen los valores por defecto) o una estructura HTML que no viene a cuento y que parece de la época de FrontPage, pero el mayor problema era la funcionalidad que yo quería encontrar y que no encontré nadie que la implementara, es decir, tener la posibilidad de que el indicador de posición (las bolitas que todos tienen) que marca la slide que se muestra en cada momento en pantalla, pudiera ser sustituido por un bloque de contenido y que además, al seleccionarla navegara al contenido y no a la slide relacionada.

Por lo tanto, hice una evaluación del tiempo que había perdido en buscar y probar y… no me había salido rentable así que, aunque no me gusta reinventar la rueda, me apliqué el lema “do it yourself” y empecé a crear mi propio plugin con las premisas de que debe ser LIGERO, SIMPLE, MODIFICABLE, SIN ESTILOS y MUY FÁCIL DE USAR, para que cualquiera lo pueda integrar en sus sitios web. Además, también quiero que tenga otras características que lo acerquen a la realidad actual, RESPONSIVE y TOUCHABLE.

Así pues, tras 3 horitas de desarrollo/investigación conseguí tener una versión “Alpha” que pueda servir para integrar en nuestros sites y la he publicado en GitHub bajo la licencia GNU GPL 2 con el fin de que esté accesible a todos.

example

Lo que sí me gustaría pediros es:

  • Si lo utilizáis en algún caso, decídmelo para poder promocionar vuestro site desde la página de plugin.
  • Conocer vuestra impresión sobre el plugin.
  • Proponed mejoras y nuevas features que se puedan incluir y, si son aceptables las incluiré 🙂

 

download-code watch-github got-to-website

OffTopic | Resumen de 2014 y objetivos de 2015

Este 2014 que dejamos atrás ha sido un año muy especial para mi porque ha habido cambios muy importantes tanto en mi vida laboral como en mi vida personal.

Empezando el año

Comencé el año trabajando en SolidQ, empresa en la que dejo grandes amigos y en la que pude crecer un poco más aún ya que, el hecho de trabajar en remoto para una multinacional como SolidQ representaba un reto y había que estar a la altura.

Primeros viajes del 2014

Nada más comenzar el año, empecé una rutina de viajes mezclando los eventos de comunidad con los de trabajo y así, pude estar presente en el Global Azure Bootcamp de 2014 donde di una sesión junto al gran Rafa Serna sobre Azure Mobile Services.

Twitter8e9e4cc_jpg

Los viajes laborales me llevaron a estar inmerso en un gran equipo de consultores de varias empresas (que no nombraré porque no viene al caso) donde pude conocer más a fondo a auténticos maeses tan conocidos como Unai Zorrilla, Luis Ruiz Pavón y Jorge Serrano, aparte de mis ex-compañeros, auténticos libros de conocimiento, Rubén Garrigós, Miguel López y Enrique Catalá. (Me falta foto de alguno de esos momentos)

Mobile World Congress Barcelona 2014

De la mano de Nokia, asistí al Mobile World Congress Barcelona 2014. Fueron unos días inolvidables junto a Guillermo Bas, Javier Suárez, Rafa Serna y Josué Yeray durante los que conocí a otro monstruo como Quique Martínez y al no menos monstruo Stephen Elop… jejejeje (hay prueba de ello)

compose2

Viaje a San Francisco

Todos arrastramos sueños desde nuestra época de pequeños y, viajar a los Estados Unidos es uno de los míos. Así, en marzo-abril tuve la gran fortuna de culminar este sueño gracias a Miguel López y a SolidQ que me permitieron viajar a San Francisco a unas sesiones sobre Microsoft Azure que se daban justo unos días antes del //build/ y gracias a eso pude encontrarme con otro chicharrero, el grandísimo Josué Yeray.

compose DSC01364 (2)

 

Nombramiento como MVP

Precisamente durante la estancia en San Francisco, tuve la grata, gratísima, infinita sorpresa de ser nombrado MVP Client Development Windows Platform Development. Sin duda un premio que siempre agradeceré y que se lo debo sobre todo al gran maestre Alberto Díaz que ha sido el referente que necesitaba para centrarme en lo que me gusta, y también han influido otros compañeros como Josue Yeray y David Rodríguez, ambos compañeros en TenerifeDev y MVP y Jose Fortes también compañero de TenerifeDev pero en el área de negocios. A todos los nombrados y al resto que ha aportado un granito de arena a mi vida laboral y a este MVP, os doy mis más sinceras GRACIAS y un fuerte abrazo!.

MVP_Logo_Horizontal_Preferred_Cyan300_RGB_300ppi 

Fichaje por ENCAMINA

Tras unos meses algo agotado por los viajes a cliente, decidí dar un nuevo vuelco a mi vida laboral y, tras una gran oferta de ENCAMINA y tras ver que podría aportarme todo lo que me satisfacía en mi vida laboral e incluso también en lo personal, di el salto a una nueva familia muy dinámica, muy cercana, muy acogedora y sobre todo con unas enormes ganas de crecer, aprender y hacer las cosas con un plus de excelencia. Así que, aquí estoy, nuevamente junto a Alberto Díaz y con un gran equipo de trabajo en el que se incluye Adrián Díaz, un departamento de diseño, unos directores con mucha ilusión y pasión por su trabajo y unos compañeros que rebosan pasión y hambre por comerse el mundo. Así que… creo que finalmente tomé un buen “camino”.

8519_foto

Viaje a Seattle – MVP Summit 2014

Este año ha estado sembrado de viajes y pude repetir en Estados Unidos,  pero esta vez en Seattle para asistir al MVP Summit de Microsoft. Sin duda fue la experiencia más enriquedora de mi vida en cuanto a conocimientos, tecnología y networking se refiere. Además, poder compartir esta experiencia con Alberto Díaz, David Rodríguez y Carmen, Rafa Serna, Juan Carlos González, Gustavo Vélez, etc etc… ha sido increíble. Nos faltó Josué Yeray para ser los 4 canarios del apocalípsis en Seattle 🙂 Maybe next year??

compose3

Segunda participación en Codemotion Madrid

Por segundo año, he participado en Codemotion Madrid. En esta ocasión he estado junto a Rubén Pertusa hablando sobre la conjunción entre Datos y Frontend con un ejemplo basado en una aplicación y un conector a cubos analíticos. Fue toda una sorpresa ver la sala completamente llena habiendo incluso gente de pie que aguantaron así hasta el final.

WP_20141121_12_17_09_Pro

Además, incluso me grabaron una entrevista (shhhh no le digáis a nadie que es la primera entrevista de mi vida jjjjj)

 

TenerifeDev – Eventos durante todo el año

He esperado al final por ser algo “transversal”. La labor de TenerifeDev no para en todo el año, ya sea colaborando con Microsoft en la organización de eventos y con los ponentes o realizando nuestros propios eventos. Así, hemos participado en la Tenerife Lan Party 2014 como todos los años, hemos estado en Madrid en Global Azure Bootcamp 2014, en FEULL y en la escuela de informática de la Universidad de la Laguna ETSII con sesiones que creemos interesantes para todos los asistentes y, sobre todo, para alumnos que aún no tienen un rumbo prefijado o preconcebido.

sessions

 

Christmas Mobile Apps Sessions

Un año más estuve enrolado en esta serie de sesiones sobre desarrollo de aplicaciones móviles (Apps) para cerrar el año, gracias a la labor de Alejandro Campos Magencio, Evangelista de Microsoft Ibérica. ¿El próximo año repetimos? Espero que sí 😛

Christmas-Windows-Phone-Sessions

Objetivos para 2015

Bueno, para el 2015 sólo pido poder aprender más cosas, poder participar en algún proyecto que incluya las últimas tecnologías de desarrollo móvil, seguir pudiendo influir en alguien cuando de tecnología se trate y, sobre todo, seguir divirtiéndome con mi trabajo y con los eventos en los que participo.

Agradecimientos

No hay hueco para tanta gente, así que lo reduciré a mis compañeros de TenerifeDev, con los que comparto las batallas del día a día y con los que no paro de pensar eventos en los que participar u organizar. Pero sobre todo, a mi pequeña gran familia por apoyarme y darme los ánimos necesarios para seguir creciendo, mejorando y aprendiendo. Para mis chicas, mi mayor abrazo y mi mayor beso.

10718852_10202858364568660_1250056913_o

HTML + CSS | Eliminar espacio entre los elementos en línea “inline-block”

poster Desde hace ya algunos años, una de las técnicas más usadas en las Hojas de Estilo en Cascada (CSS) para maquetar en sitios web que deban mostrar elementos de tipo bloque en línea es la de establecer su regla “display” con el valor “inline-block”. El uso de “display: inline-block;” nos permite realizar menús, muestras de elementos, etc, sin necesidad de recurrir a elementos flotantes con la regla “float” que ya se encuentra desaconsejada salvo necesidad expresa o la muy mala práctica de maquetación consistente en usar tablas para distribuir el contenido. Así pues, en este artículo os expongo el problema y varias soluciones en mayor o menos medida recomendadas puesto que algunas las considero malas prácticas y otras son algo “raras”, pero sin duda, al final del artículo encontraréis la que a mi parecer es la forma correcta de realizar este tipo de maquetado. Podéis descargaros el website de ejemplo para seguir el artículo desde este enlace.

Bien, veamos un ejemplo en el que queremos mostrar un menú de elementos en línea

<nav class="mainNav">

    <div class="navItem">Item 1</div>

    <div class="navItem">Item 2</div>

    <div class="navItem">Item 3</div>

    <div class="navItem">Item 4</div>

</nav>

 

Y añadimos un poco de estilos CSS

nav.mainNav {

    display: inline-block;

    margin: 20px;

    padding: 20px;

    border: 1px solid #4800ff;

}

 

nav.mainNav > .navItem {

    display: inline-block;

    padding: 20px;

    background: #4800ff;

    color: #fff;

}

 

Esto nos producirá la siguiente salida

menu-inicial

Como se puede apreciar, existe un espacio entre los elementos que realmente no existe ni en HTML, ni en CSS, “ni por el propio navegador”… lo que puede producirnos un problema si queremos que los elementos aparezcan completamente juntos. ¿Cómo lo solucionamos?

Solución 1: Minimizando el HTML

Si minimizamos el HTML eliminando el espacio entre los elementos que queremos mostrar en línea “inline-block”, es decir, si los mostramos en una línea sin espacio o salto de línea entre ellos… misteriosamente se soluciona el problema. Aquí tenemos el ejemplo y su resultado

<nav class="mainNav">

    <div class="navItem">Item 1</div><div class="navItem">Item 2</div><div class="navItem">Item 3</div><div class="navItem">Item 4</div>

</nav>

menu-minimized-html

También podemos usar algunos trucos muy feos como cerrar el elemento en la siguiente línea o usar comentarios en los saltos de línea tal y como os muestro más abajo

<nav class="mainNav">

    <div class="navItem">Item 1</div

    ><div class="navItem">Item 2</div

    ><div class="navItem">Item 3</div

    ><div class="navItem">Item 4</div>

</nav>

<nav class="mainNav">

    <div class="navItem">Item 1</div><!--

    --><div class="navItem">Item 2</div><!--

    --><div class="navItem">Item 3</div><!--

    --><div class="navItem">Item 4</div>

</nav>

menu-closing-tag-next-line menu-using-comments

Estos trucos nos funcionarán sin problemas aunque, para ser sinceros me quedo con el tercero por ser menos “raro”.

Solución 2: Ajustar márgenes (negativos)

La siguiente solución pasa por ajustar los márgenes entre los elementos. Después de indagar y probar, resulta que el margen que se añade en los lados de los elementos es de 4px y sólo necesitaríamos restarlos. En el ejemplo, añadiré una nueva clase a los elementos sobre la que aplicaré el arreglo.

<nav id="mainNav">

    <div class="navItem navItemSolution2">Item 1</div>

    <div class="navItem navItemSolution2">Item 2</div>

    <div class="navItem navItemSolution2">Item 3</div>

    <div class="navItem navItemSolution2">Item 4</div>

</nav>

nav#mainNav {

    display: inline-block;

    margin: 20px;

    padding: 20px;

    border: 1px solid #4800ff;

}

 

nav#mainNav > .navItem {

    display: inline-block;

    padding: 20px;

    background: #4800ff;

    color: #fff;

}

 

nav#mainNav > .navItemSolution2{

    margin: 0 -4px;

}

menu-margin-fix

Esta solución podría es tar bien pero… ¿y si mañana cambian las interpretaciones en algún navegador? ¿Se seguirá mostrando bien? Pues… podría darnos muchos problemas puesto que habría que reescribir nuestras hojas de estilo.

Solución 3: Ajustar fuente

Otra posible solución, dado que lo que se añade podría equivaler a un espacio de texto…, pasa por ajustar el tamaño de fuente, poniéndolo a 0px en el contenedor y estableciendo el correcto en los propios elementos en línea tal y como os muestro más abajo. Nuevamente jugaré con las clases de los elementos para no tener que reescribir todo.

<nav class="mainNav mainNavSolution3">

    <div class="navItem navItemSolution3">Item 1</div>

    <div class="navItem navItemSolution3">Item 2</div>

    <div class="navItem navItemSolution3">Item 3</div>

    <div class="navItem navItemSolution3">Item 4</div>

</nav>

nav.mainNav {

    display: inline-block;

    margin: 20px;

    padding: 20px;

    border: 1px solid #4800ff;

}

 

nav.mainNavSolution3 {

    font-size: 0;

}

 

nav.mainNav > .navItem {

    display: inline-block;

    padding: 20px;

    background: #4800ff;

    color: #fff;

}

 

nav.mainNav > .navItemSolution3 {

    font-size: 16px;

}

menu-font-size

Como podéis ver, esta solución tampoco es nada buena puesto que nuevamente podemos enfrentarnos a problemas si mañana tenemos que actualizar nuestras hojas de estilo.

Solución 4: Flotar los elementos con float (volver al pasado y a sus horrores)

La siguiente solución pasa por poner los elementos como flotantes, con lo que estaríamos volviendo al pasado y a los problemas de que salten de línea, o que no se ajuste el contenido que se encuentra bajo él, al uso de elementos con “clear:both” para corregir problemas y a veces crear otros…, pero bueno, aquí tenéis el ejemplo.

<nav class="mainNav">

    <h2>Elementos flotantes</h2>

    <div class="navItem navItemSolution4">Item 1</div>

    <div class="navItem navItemSolution4">Item 2</div>

    <div class="navItem navItemSolution4">Item 3</div>

    <div class="navItem navItemSolution4">Item 4</div>

</nav>

nav.mainNav {

    display: inline-block;

    margin: 20px;

    padding: 20px;

    border: 1px solid #4800ff;

}

 

nav.mainNav > .navItem {

    display: inline-block;

    padding: 20px;

    background: #4800ff;

    color: #fff;

}

 

nav.mainNav > .navItemSolution4{

    float: left;

}

 

menu-float

Como podéis observar funciona perfectamente pero, por favor, no viváis del pasado y mantened las cosas más simples, así que olvidad los elementos flotantes salvo que sea estrictamente necesario (K.I.S.S.). Hay soluciones mucho mejores como la que os pongo al final del artículo.

Solución 5: No cerrar los elementos en línea… (MUY MUY MALA PRÁCTICA)

La característica de HTML5 que permite no cerrar los elementos es algo que siempre me ha chirriado y dolido en el alma y provoca problemas como uno que me encontré hace no mucho en un mega-producto de una gran compañía (a Alberto Díaz y a Adrían Díaz les sonará), pero si sois amantes de esta práctica (espero con el corazón que no haya nadie), esta solución os puede valer.

<nav class="mainNav">

    <h2>No cerrar elementos</h2>

    <ul>

        <li>Item 1

        <li>Item 2

        <li>Item 3

        <li>Item 4

    </ul>

</nav>

nav.mainNav {

    display: inline-block;

    margin: 20px;

    padding: 20px;

    vertical-align: top;

    border: 1px solid #4800ff;

}

 

nav.mainNav > ul {

    margin: 0;

    padding: 0;

}

 

nav.mainNav > ul > li {

    display: inline-block;

    padding: 20px;

    background: #4800ff;

    color: #fff;

}

menu-no-closing-tag

No quiero ser pesado pero… esta me parece una muy mala práctica.

Solución 6: Usar modelo de caja flexible (Mi recomendación)

Otro día hablaré más a fondo de este modelo que es una gozada para maquetar y para modelar nuestros sitios responsivos (responsive web design). Esta característica es una de las más potentes porque permite jugar mucho con el modelado de los elementos, su comportamiento, etc etc y es muy simple de usar como podréis observar.

<h2>&nbsp;&nbsp;&nbsp;&nbsp;Modelo de caja flexible</h2>

<nav class="mainNav flexbox">

    <div class="navItem flex-item">Item 1</div>

    <div class="navItem flex-item">Item 2</div>

    <div class="navItem flex-item">Item 3</div>

    <div class="navItem flex-item">Item 4</div>

</nav>

nav.mainNav {

    display: inline-block;

    margin: 20px;

    padding: 20px;

    vertical-align: top;

    border: 1px solid #4800ff;

}

 

nav.mainNav.flexbox {

    /* BROWSER DEFINITION */

    display: -webkit-box; /* OLD - iOS 6-, Safari 3.1-6 */

    display: -moz-box; /* OLD - Firefox 19- (buggy but mostly works) */

    display: -ms-flexbox; /* TWEENER - IE 10 */

    display: -webkit-flex; /* NEW - Chrome */

 

    /* W3C DEFINITION */

    display: flex;

    display: inline-flex;

}

 

nav.mainNav > .navItem {

    display: inline-block;

    padding: 20px;

    background: #4800ff;

    color: #fff;

}

menu-flexbox

Se puede usar tanto “display: flex” como “display: inline-flex” para el contenedor para poder así controlar el modelado dentro de la página (en bloque o en línea). Los elementos que contenga el contenedor al que le apliquemos una de estas propiedades, automáticamente pasarán a comportarse como elementos de caja flexible, adaptándose a la perfección a nuestras necesidades. Si queréis saber más sobre el modelo de caja flexible (flexbox) podéis esperar a que escriba un artículo sobre ello o simplemente consultar este artículo de la MSDN

NOTA: Tened mucho cuidado con Safari porque aún parece que no se ha subido al carro de las especificaciones de W3C

 

download-code