






tal como reza el cartel superior derecho de Latitud y Longitud. En este mismo cartel podemos controlar el nivel de zoom del mapa con el deslizador dispuesto a tal efecto. Otros controles útiles son el centrador de posición ,con el botón “Mi posición“, tendremos actualizada nuestra posición en todo momento, centrando el mapa en esta cada cierto número de segundos. Los botones Mapa|Sat|Híb modifican el formato de visualización de aquel de mapa a satélite o híbrido (mezcla de los dos primeros). Ahora, usaremos el botón con fondo azul y un radar blanco para que la aplicación busque el establecimiento más cercano a nuestra posición (si es que hemos permitido a esta el uso de nuestra localización,claro), y se mostraría una ventana con el título “El sitio más cercano es:” y el título y los kilómetros de distancia, al aceptar observaríamos que el mapa ahora está posicionado con el centro en dicho establecimiento y que pinchando sobre el icono de chincheta de Abades ([a]) aparece un recuadro con el título, categoría y un botón para mostrar una ventana que contiene información del sitio y un botón para hacer Checkin.
El reto de esta app consistió en poder crear una herramienta que sincronizara los datos de la web actual (abades.com) con los demás dominios (abadestriana.com, abadesnevadapalace.com) y appspot.com, y después crear un algoritmo para hacer un checkin válido así como sincronizar todos los elementos RSS en un único canal y adjuntarlo al programa de promociones actuales de las webs (blogs, noticias, etc. para cada idioma, inglés y español).
La programación empezó donde véis el artículo de como crear una aplicación productiva y social, el esquema era el mismo, pero había que añadirle toda la parte de programación de servidor, ya que la empresa necesita tener actualizada la información que se comparte con los dispositivos y sus webs, la opción de crear un algoritmo en PHP era tentadora pero una aplicación de móbil necesita una buena respuesta y un servidor web no es precisamente una máquina en la que uno desee confiar plenamente, es decir, no siempre está operativa 100% porque tiene muchos usuarios desde la web, por lo que opté por un servidor de google app engine y usando Java creé todas las estructuras de datos donde almacenar la información de establecimientos como en las guías de los cursos de este blog, después lancé los servicios web que permiten dar de alta todos estos datos, y que son capturados por los analizadores sintácticos de la aplicación móvil, más adelante configuré efectos gráficos, mejoré el diseño y añadí la API de Foursquare gracias a frameworks ya disponibles en la red.
El analizador sintáctico es NSXMLparser, el framework ASIHttp permite descargar imágenes con caché de forma síncrona o asíncrona, el scroll view de regalos usa una caché para poder crear todos los que hagan falta, el modelo de datos es sencillo, contiene elementos transformables para almacenar listas, estas listas en Google App Engine con DataStore son persistentes y embebidas en clases que permiten la serialización de objetos, etc.
En cuanto a los mapas no hay mucho que contar, es lo que se suele hacer, una clase para las anotaciones, se captura el evento del dibujado para dibujar un icono distinto e intercalar un botón en recuadro que se muestra al pulsar sobre una chincheta o anotación, y las animaciones están hechas con QuartzCore, es decir UVAnimation con cambios entre transiciones de opacidad, tamaño y posición,…lo sé ,aún se puede mejorar :)
Puedes descargar la aplicación desde su sección: aquí.
Esta aplicación surgió como un proyecto personal a partir de la necesidad de crear cartas astrales.
El reto comenzó con la forma en que se han realizar los cálculos de una carta astral. Por suerte, hay un software escrito en C, de los alemanes Dieter Koch and Alois Treindl y Astrodienst Zurich llamado SWISSEPH, conecté por consola ssh con mi servidor, utilicé wget con la última versión ( 1.76 ) y tras el make probé Swetest que a partir de una serie de argumentos de entrada muestra por pantalla un “ephemeris”, el resultado de leer una base de datos de posiciones de planetas, asteroides, estrellas, etc. y devolver las posiciones para cada una de las casas de dicha fecha y hora en el lugar especificado por longitud y latitud.Este programa además lanza una serie de datos para generar gráficas como “spreadsheets”.
Usando estos datos y un pequeño script:
//Analizar sintácticamente la fecha,hora,longitud y latitud exec ("swetest -edir../src/ -b$utdatenow -ut$utnow -p0123456789 -eswe -house$longitud,$latitud, -fPlj -g, -head", $salida); foreach ($salida as $key => $linea) { $row = explode(',',$linea); $pl_name[$key] = $row[0]; $longitude[$key] = $row[1]; $house_pos[$key] = $row[3]; };
Donde cada línea de salida de swetest se divide en arrays $row, con los elementos:0 = planeta,1 = longitud,2 = posición de casa, planetas en 0 – 9, cúspides en 10 – 21. Los nombres de los componentes,empiezan por 0 = Sol, que es la estrella del sistema solar,junto con la Luna=1 y Mercurio = 2 hasta Plutón = 9, los símbolos serían del 1 = Aries hasta 12 = Piscis. Para asociar la longitud y latitud al signo se hace una regla de 30 que limita la longitud y la combina con la casa asociada que devuelve el programa, de esta forma, podemos generar una imagen con instrucciones de dibujado geométrico (círculos, líneas, símbolos como texto)…Podéis ver un ejemplo aquí.
Para generar textos más completos he utilizado webs que los devuelven gratuitamente a partir de los datos, como grupovenus.
Finalmente, con un script en Python dentro de Google App Engine se crean todas las consultas en segundo plano, se construye el XML con HTML+CSS embebido, imágenes, etc. y se guardan, previo análisis sintáctico mediante la clase NSXMLParser en la base de datos SQlite asociada al Modelo de Datos, tal como vimos en los cursos.
Las animaciones de la app: las transiciones están hechas en OpenGL (HMGLTransition) y con las clases CAAnimation. El menú giratorio es una extensión de la clase UIGestureRecognizer ( KTOneFingerRotationGestureRecognizer ) modificada adaptando cada sección a un ángulo con una animación UIView…
Para la base de datos, primero se genera el modelo de datos, luego se compila y ejecuta la aplicación para que el mismo SDK cree el fichero SQlite así, tenemos la base sobre la que insertar los datos, una vez hemos rellenado todas las tablas, copiamos el fichero sqlite al proyecto y con un código como este:
NSString *storePath = [[self applicationDocumentsDirectory] stringByAppendingPathComponent: @"Carta_Astral.sqlite"]; // Set up the store. // For the sake of illustration, provide a pre-populated default store. NSFileManager *fileManager = [NSFileManager defaultManager]; // If the expected store doesn’t exist, copy the default store. if (![fileManager fileExistsAtPath:storePath]) { NSString *defaultStorePath = [[NSBundle mainBundle] pathForResource:@"Carta_Astral" ofType:@"sqlite"]; if (defaultStorePath) { [fileManager copyItemAtPath:defaultStorePath toPath:storePath error:NULL]; } }
la primera vez que se ejecuta la aplicación, se copia al directorio de Documentos y ahí es donde se graban los datos del usuario, hago especial énfasis en que los tipos de datos complejos como Arrays de imágenes, textos y nombres se guardan en un tipo de dato del Modelo de Datos de Cocoa llamado Transformable.
En la sección de manuales hay tres tipos de manuales, los vídeos de youtube que se cargan sobre un objeto WebView, los textos con imagen que se cargan sobre una vista a mano y los pdf’s que se descargan a una caché con ASIHttp DownloadCache…Para paginar todos los documentos, libros, vídeos he usado una clase que crea un número infinito (gracias Andreas Katzian) de ScrollViews y los guarda en una caché de vistas para no tener que ir generándolos cada vez que se cambia de página, de forma que sólo se consulta una vez a la base de datos, se guarda una caché de tuplas y luego una caché de vistas con sus correspondientes botones, etc., así es mucho más eficiente y sencillo.
Para compartir textos e imágenes se utilizó ShareKit.
Veréis que las barras de navegación y las barras botones (tab) tienen una textura de fondo, esto se hace sobrecargando la clase correspondiente, en concreto el método de dibujado, para hacer que pinte una imagen por debajo y luego el resto del contenido.
La aplicación está siendo desarrollada
Estamos hablando de las preferencias por defecto del usuario. En otras palabras, vamos a usar la clase NSUserDefaults, que accede las preferencias que creemos o bien por código o bien con el diseñador de “Settings Bundle”, estas quedan almacenadas en un fichero plist (xml), donde se define cada elemento como un diccionario que contiene los diferentes parámetros en tipos de datos que son diccionarios internamente.
Ejemplo de creación: File -> New File -> Resource -> Settings Bundle.
Normalmente el nombre que se le suele dar al fichero es “Root.plis”, la edición dentro de XCode de este tipo de ficheros de configuración viene a ser algo así:
Estos diccionarios tienen unos tipos de atributos, los siguientes:
Veréis que existen varios tipos de datos a la hora de añadir un diccionario que contiene un elemento de preferencias, estos tipos pueden ser:
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; NSString *strUser = [defaults objectForKey:@"usuario"]; int level = [[defaults objectForKey:@"nivel"] intValue]; NSString *strName = [defaults objectForKey:@"nombre"]; NSString *strPass = [defaults objectForKey:@"password"];
Si cargamos la aplicación por primera vez, debemos guardar los valores, igual que antes pero usando la función
[[NSUserDefaults standardUserDefaults] setValue:(id) forKey:(NSString*)];
[NSUserDefaults standardUserDefaults] synchronize]; //imprescindible!
,evidentemente, si los tipos de datos son numéricos, tenemos que encapsularlos en una clase NSNumber, etc.
Para reiniciar los valores en el simulador (esto debemos hacerlo también para cuando cambiemos un fichero traducido de Interface Builder) , borramos el directorio ~/Library/Application Support/iPhone Simulator/User/Applications o bien, abrimos el simulador, y borramos la aplicación o por último, en el menú del simulador – > Restablecer contenidos y ajustes. Esta última opción borrará todas las compilaciones de XIB a NIB (ficheros de I.B.).
Este fichero, según la documentación de XCode, contiene la información de configuración de la aplicación (en un bundle), puede utilizarse para especificar el icono de la aplicación, incluso una cadena “audio” en la variable UIBackgroundModes para cuando la aplicación pasa a segundo plano y estamos haciendo streaming ,que no se corte.
O se puede indicar con la cadena “voip” para que se use un socket para VoIP (luego hace falta que se invoque al método setKeepAliveTimeout: handler para especificar la frecuencia con la que despertar la aplicación para que funcione bien la aplicación, por ejemplo, para cargar el buffer que se está reproduciendo).
Para realizar las traducciones utilizamos dos aplicaciones de XCode que extraen las cadenas de texto a traducir a todos los idiomas: ( ver recursos de traducción> ),
toma como entrada todos los ficheros de implementación y busca NSLocalizedString, creando un fichero codificado con el juego de caracteres UTF-16 con líneas así:
/* Comentario de la llave */
"llave" = "Texto para la llave";
Una vez generados los ficheros para los .m en cada idioma, pues se traducen y luego se deben añadir los directorios al proyecto, si véis que no coge las cadenas de texto, quitad los directorios (en.lproj) sin borrarlos ,sólo la referencia, y luego añadirlos de nuevo
En el fichero strings estarán las cadenas de texto a traducir, una vez hecho, las escribimos de nuevo al .xib:
[sourcecode language="bash"]
ibtool --write MiFichero.strings MiFichero.xib
<< Volver al Curso de Aplicaciones de iOS
|| Ir al siguiente capítulo: Geolocalización con MapKit de Google y CoreLocation »
Esta aplicación de escritorio consiste en un Editor de Artículos en base a Plantillas de Revistas que construí en el año 2007 con tecnología .NET para una tesis doctoral de una profesora del Departamento de Traducción e Interpretación de la Universidad de Granada. Para ver más información usar el siguiente PDF [ aquí la tesis ].
El programa puede utilizar servicios web para descargar bases de datos de revistas con reglas para ejecutar sobre dos documentos del paquete Office Word ©: el documento del artículo y el de tablas asociado al primero, en conjunto forman un proyecto, con notas, información y referencias bibliográficas,etc. Para hacer esto crea instancias de la aplicación del editor de textos y se controla que esté correcto desde Sciscribe para poder enviarlo a la Revista elegida facilitando así la corrección de los revisores.
Otro servicio web comprueba la versión de la aplicación para ser actualizada.
Este otro caso es de una aplicación de una base de datos compartida en Red con acceso por usuario,
generador de informes, listados de tareas asociadas, etc. hay una aplicación web que administra los avisos que recibirá cada usuario en su pc, es del año 2005-2007 y el vídeo sólo muestra el login pero es sólo para dar un ejemplo de como pueden comunicarse las aplicaciones web con las de escritorio a través de servicios, almacenando los datos en bases de datos locales o remotas y restringiendo el acceso por privilegios de usuario de la manera más fuerte, software compilado para la arquitectura en la que se ejecuta…
Existen más ejemplos de aplicaciones de escritorio que se comunican por medio de internet con una base de datos administrada remotamente…por ahora es suficiente…
Desde que Facebook empezó a tener éxito, los clones de redes sociales no pararon de aparecer, sobre todo webs de contactos como zoosk, badoo, linked in, …o las miles de redes más, cada una con su propósito, sin embargo las necesidades del público son tan dispares que empezaron a salir generadores online de redes sociales, no contentos con esto, ya que a nadie le interesa tener alojada una red social en las máquinas de alguien que no conoce, aparecieron generadores de redes sociales pero esta vez ,instalables en un servidor propio…una de esas opciones, de la más extendida ,es elgg…
Con elgg podemos simular un facebook, y digo simular porque no trae soporte para clústers, ni gestor de aplicaciones con APi externa, ni chat integrado, pero sí trae las herramientas para programar todas estas cosas, empezando por el muro, existe un componente llamado riverdash que lo implementa, en mi caso he estado extendiendo la funcionalidad de este plugin para un cliente y tengo que decir que el código de elgg aún tiene que madurar ,sin embargo entraña un potencial muy grande que puede aprovecharse tanto para construir una buena red social como para una aplicación de un grupo más reducido de personas que necesiten compartir información.
Podemos consultar la Wiki de Elgg aquí y descargarnos la última versión aquí.
Para añadir funcionalidades a esta red social personal se utiliza el directorio “mod” donde creamos un nuevo subdirectorio con el nombre de nuestro módulo, llamémoslo “saludo”, dentro, si creamos un fichero llamado “start.php” elgg cargará nuestro módulo, en dicho fichero se especifican las inicializaciones a realizar; lo primero después de esto es crear un subdirectorio dentro de “saludo” para las vistas, llamado “views”…aquí empieza a complicarse, tenemos varios tipos de vistas, lo normal es xhtml así que por defecto se llama al subdirectorio dentro de views , “default”, ahora, si es un widget (zona flotante que se puede colocar en cualquier lugar de las plantillas de la web) pues irá dentro del subdirectorio de default, “widgets”, y vamos a llamar al nuevo fichero “vista.php”, luego la ruta completa es
/mod/saludo/views/default/widgets/vista.php , y el código para esta vista es:
[source language="php"]
[/source]
para que podamos gestionar el widget desde la administración iremos a /mod/saludo/start.php y lo dejaremos así:
[source language="php"]
function iniciar_saludo() {
add_widget_type(‘saludo’, ‘Mod de Saludo’, ‘Simplemente saluda’);
}
register_elgg_event_handler(‘init’,'system’,'iniciar_saludo’);
[/source]
De forma que elgg ya sabe qué es lo que tiene que hacer con nuestro nuevo módulo…
Para complicarlo un poco más y pasarle datos a nuestro módulo usaremos una vista de elgg, creando un fichero llamado hola.php donde estaba vista.php, con el siguiente contenido:
[source language="php"]
Tu saludo:
echo elgg_view('input/text', array( 'internalname' => ‘params[mensaje]‘,
‘value’ => $vars['entity']->mensaje,
‘class’ => ‘hola-input-text’ ) );
?>
[/source]
así, especificamos a elgg que queremos mostrar un tipo de vista basada en un input text con el nombre “mensaje” y el valor es el que tenga la propia entidad (al principio ninguno) en su atributo mensaje, la class es CSS…
Ahora, para que la vista.php muestre el saludo enviado, necesitamos cambiarla para que quede así:
[source language="php"]
[/source]
Para más información acerca de las vistas pinchar aquí.
La gestión de idiomas se lleva por medio de un array de valores en /mod/saludo/languages/es.php, el índice o clave de una palabra o frase a almacenar contiene el prefijo del módulo, en nuestro caso “saludo:____” , donde ___ es el resto de la llave, por ejemplo, para inicio ->
[source language="php"]
$espanol = array ( “saludo:inicio” => “Inicio”);
$english = array(“saludo:inicio” => “Home”);
add_traslation(“es”, $espanol);
add_traslation(“en”, $english);
//Para utilizar las claves:
echo elgg_echo(“saludo:inicio”);
[/source]
En este vídeo se puede comprobar como se ha modificado elgg para añadir un motor tipo “muro” de facebook, se ha añadido la funcionalidad de mostrar comentarios, eventos, “me gusta” y “no me gusta”, enviar a redes sociales, etc.
Los encargos que he realizado están asociados a la creación de herramientas (plugins) y modificaciones del núcleo para importar y exportar contenido entre redes sociales y elgg. Desde Blogger hasta Facebook pasando por WordPress, las “tools” que he diseñado específicamente importan y exportan entradas del river-dashboard, también conocido como el famoso muro en facebook, pero adaptado para elgg.
Crear un plugin como extensión de otro para elgg:
1.- crear directorio en /mod/nombre_plugin
2.- crear /mod/nombre_plugin/manifest.xml
[sourcecode language="xml"]
3.- crear /mod/nombre_plugin/start.php
donde al menos registraremos una función para la carga del plugin y otra función para manejar los eventos, opcionalmente añadiremos acciones también (funciones,claro).
register_elgg_event_handler('init','system','nombre_plugin_init'); register_elgg_event_handler('pagesetup','system','nombre_plugin_pagesetup');
En el caso en que queramos permitir el uso de preferencias por usuario del plugin, usaremos en start.php -función nombre_plugin_init()-, el siguiente código:
register_plugin_hook('usersettings:save','user','nombre_plugin_user_settings_save');
La función para guardar estas preferencias debe ser algo como:
function nombre_plugin_user_settings_save(){ //sólo usuario registrado y propietario de la cuenta a editar opciones gatekeeper(); $user = page_owner_entity(); if (!$user) { $user = $_SESSION['user']; } $user->nombre_input = get_input('nombre_input','valor_por_defecto'); }
Evidentemente tenemos que añadir las vistas como página
en la función nombre_plugin_pagesetup:
//Añadir los campos de configuración de usuario extend_elgg_settings_page( 'nombre_plugin/settings/usersettings', 'usersettings/user' );
y claro, necesitamos crear el fichero que referenciamos, en
/mod/nombre_plugin/views/default/settings/usersettings.php
donde colocaremos los (html) que necesitemos. Para obtener los valores en dicha vista de los propios inputs, usaremos
$user = page_owner_entity();
y los valores están dentro de esta clase: $user->nombre_input...
Como truquito que me gusta utilizar, para crear una lista de valores con un select, usar las funciones implode para guardar el dato y split para el dato leído e interpretarlo.
Si queremos que el plugin tenga opciones para el administrador creamos el directorio
/mod/nombre_plugin/views/settings/nombre_plugin/
y dentro colocamos el fichero edit.php. Aquí lo único que tenemos que hacer es escribir por pantalla los campos input que queramos como opciones de administración del plugin, el motor de Elgg nos guardará solito los valores al pulsar en en el botón submit "save", para obtener el valor del input tenemos que llamar a la función get_plugin_setting('nombre_input','nombre_plugin') que nos devuelve el valor.
Tened en cuenta que Elgg usa muchos automatismos, por ejemplo sólo con crear un fichero con el mismo nombre del plugin dentro del directorio settings de mod, ya tenéis hecho un gestor de opciones para vuestra contribución, son cosas como estas las que la comunidad agradece tanto, si echáis un vistazo a los foros veréis de lo que hablo, un saludo