Publicat per

(PR2) Camina i fes UNLOCK! Tarragona

Publicat per

(PR2) Camina i fes UNLOCK! Tarragona

  Procés d’ideació i evolució del projecte El projecte Camina i fes UNLOCK! neix amb la voluntat de transformar una activitat quotidiana…
  Procés d’ideació i evolució del projecte El projecte Camina i fes UNLOCK! neix amb la voluntat de transformar…

 

Procés d’ideació i evolució del projecte

El projecte Camina i fes UNLOCK! neix amb la voluntat de transformar una activitat quotidiana com caminar en una experiència lúdica i visualment significativa. A partir de la base desenvolupada a la PR1, l’objectiu de la PR2 ha estat ampliar aquesta proposta mantenint la mecànica principal, però afegint una nova capa de contingut mitjançant la integració d’una API externa. Enfocarem aquesta nova versió com una app específica amb contingut de Tarragona.

Des del punt de vista conceptual, s’ha considerat important no alterar la naturalesa “effort-free” de l’app. L’ usuari continua interactuant mínimament amb el dispositiu, mentre el progrés es produeix de manera natural a mesura que camina. La nova funcionalitat introduïda no substitueix el joc, sinó que l’enriqueix, aportant context cultural i informatiu a les imatges desbloquejades.

 

Integració d’una API externa

S’ha integrat una API externa pública: la MediaWiki API (Viquipèdia) en llengua catalana.

L’ elecció d’aquesta API respon a diversos criteris:

  • és gratuïta i sense necessitat d’autenticació,
  • permet consultes dinàmiques en format JSON,
  • ofereix contingut rellevant i contextualitzat,
  • i disposa de suport CORS, imprescindible per a la seva integració en una aplicació web híbrida amb Capacitor.

Cada imatge desbloquejada a l’ app està associada a un indret real de la ciutat de Tarragona. Quan l’usuari accedeix a la galeria i selecciona el botó Info, l’ aplicació realitza una crida dinàmica a l’API de la Viquipèdia per obtenir informació contextual sobre aquell indret: títol, resum descriptiu i enllaç per ampliar la informació.

Aquesta integració compleix el requisit de “petició personalitzada”, ja que la consulta depèn directament de la imatge seleccionada, i inclou control d’errors per gestionar possibles problemes de xarxa o respostes no disponibles.

Visualització de la informació

La informació retornada per l’API es mostra dins l’ aplicació mitjançant un modal dedicat, evitant així que l’usuari abandoni el flux principal del joc. Aquesta solució permet mantenir la coherència visual de l’app i reforça la idea que la informació forma part de l’ experiència de desbloqueig.

 

La presentació de les dades s’ha dissenyat de manera clara i jerarquitzada, prioritzant la llegibilitat i l’accessibilitat, i reforçant el valor afegit de l’API sense sobrecarregar la interfície.

Funcionalitats natives i feedback tècnic

L’aplicació continua fent ús de funcionalitats natives del dispositiu, principalment la geolocalització, que és l’eix central del funcionament del joc. El càlcul de la distància recorreguda permet determinar el progrés de desbloqueig de cada imatge.

Arran del feedback rebut a la PR1, es va analitzar la possibilitat d’implementar watchPosition per millorar la precisió del seguiment continu. Tot i reconèixer els avantatges d’aquesta aproximació, en aquesta iteració s’ha prioritzat l’estabilitat del MVP i la integració correcta de l’API externa. Com a solució tècnica per facilitar el desenvolupament i el testeig, es manté el Mode Demo, que permet simular l’avanç de metres sense necessitat de desplaçar-se físicament. Aquest plantejament ha permès continuar iterant sobre el projecte de manera eficient, deixant la millora del seguiment GPS com a possible evolució futura.

Galeria, navegació i estat del joc

Les imatges completades es poden consultar en qualsevol moment i s’obren en un visor amb opcions de zoom. La integració del botó Info dins la galeria reforça la connexió entre el contingut visual i la informació contextual obtinguda de l’API.

S’ha tingut especial cura a separar els estats de “desbloqueig en curs” i “visualització”, evitant animacions o efectes que poguessin generar confusió quan l’usuari navega per contingut ja completat.

 

Proves i entorn de test

Les proves s’han realitzat principalment amb Android Studio, utilitzant diferents perfils d’emulador per validar el comportament de l’aplicació en diverses resolucions i formats de dispositiu. Aquest procés ha permès detectar i solucionar problemes relacionats amb l’estat persistent, la configuració de l’entorn i la reconstrucció del projecte en entorns nets.

Com a millora respecte versions anteriors, l’aplicació arrenca des d’un estat inicial net en el primer llançament, evitant conflictes derivats de dades de proves prèvies guardades en emmagatzematge local.

Les proves finals s’han realitzat amb Android Studio amb els següents perfils:

  • Tablet Pixel (API 35)
  • Pixel 9 Pro XL (API 36)
  • Medium Phone (API 36.1)

Dependències i avisos de seguretat

Durant la instal·lació del projecte mitjançant npm install, el gestor de paquets indica l’existència d’algunes vulnerabilitats en dependències de tercers (2 de nivell moderat i 2 de nivell alt).

Aquests avisos corresponen a llibreries utilitzades internament pel framework i no a codi propi del projecte. En tractar-se d’un MVP amb finalitats educatives i no d’una aplicació destinada a producció, s’ha prioritzat l’estabilitat del projecte i no s’han aplicat actualitzacions forçades (npm audit fix --force), ja que podrien introduir canvis trencadors o incompatibilitats amb Capacitor i Vite. Aquesta decisió reflecteix un criteri habitual en entorns reals, on la gestió de vulnerabilitats es fa de manera controlada i contextualitzada segons l’estat i l’objectiu del producte.

 

Resultat final i aprenentatges

El resultat final és una aplicació Android funcional, estable i coherent amb el concepte inicial. A nivell d’aprenentatge, la PR2 ha posat de manifest la importància de:

  • integrar serveis externs de manera significativa,
  • gestionar correctament els estats i errors,
  • i prendre decisions tècniques equilibrades entre ambició i estabilitat.

El projecte consolida el potencial de Capacitor com a eina per portar aplicacions web a l’àmbit mòbil i estableix una base sòlida per futures ampliacions.

 

ENLLAÇ A GITHUB: https://josepmsole.github.io/CaminaifesUnlockTarragona/

 

Debat0el (PR2) Camina i fes UNLOCK! Tarragona

No hi ha comentaris.

Publicat per

Pràctica 2

Publicat per

Pràctica 2

Ideació inicial de la nova App L’objectiu d’aquesta pràctica 2 ha estat donar continuïtat a la feina feta en la pràctica 1…
Ideació inicial de la nova App L’objectiu d’aquesta pràctica 2 ha estat donar continuïtat a la feina feta en…

Ideació inicial de la nova App

L’objectiu d’aquesta pràctica 2 ha estat donar continuïtat a la feina feta en la pràctica 1 i desenvolupar una app interactiva basada en un puzle de peces mòbils, que permet a l’usuari carregar la imatge amb la qual es jugarà dins del puzle.
A la pràctica 1, l’app permetia escollir entre una imatge feta amb la càmera o una imatge existent a la galeria. A la pràctica 2 mantinc aquestes funcionalitats i n’afegeixo una de nova: obtenir imatges de Picsum per utilitzar-les en el puzle.
També es manté l’opció de mostrar un botó de configuració per escollir la mida del puzle amb què es vol jugar.
Aquests són els esbossos de la pràctica 1 i el resultat final de la pràctica 2.

Interfície proposada a la pràctica 1
Evolució del disseny de la pràctica 2

 

Consultes i passos seguits a la documentació de Capacitor

Per tal de desenvolupar l’app amb Capacitor i integrar funcionalitats natives, he seguit el procés de consulta i experimentació següent:

  • Revisió de la documentació oficial de Capacitor per entendre com funciona la integració amb projectes web.
  • Consulta dels plugins oficials i dels seus exemples d’ús.

Especial focus en:

  • Camera Plugin: per capturar imatges directament des del dispositiu o carregar-les des de la galeria.
  • Haptics Plugin: per afegir feedback tàctil durant la interacció amb el puzle.
  • També s’ha considerat com adaptar el codi perquè funcioni correctament dins d’una app híbrida (ús de webPath, càrrega d’imatges amb p5.loadImage, etc.).

Aquestes consultes han permès comprendre com utilitzar les APIs natives des de JavaScript, i com gestionar errors, permisos i diferents comportaments segons el dispositiu.

Proves amb diferents funcionalitats natives del dispositiu

Per a la pràctica, s’han provat funcionalitats natives per donar valor afegit a l’aplicació:

Càmera i galeria (Camera Plugin)

L’usuari pot:

  • Fer una foto amb la càmera.
  • Seleccionar una imatge de la galeria.

Aquestes imatges es processen i es transformen en un puzle.

Vibració / feedback tàctil (Haptics Plugin)
  • Quan el jugador fa un moviment vàlid, l’app fa una vibració lleugera.
  • Quan el puzle queda resolt, es mostra un efecte extra (vibració més forta o més llarga).

Aquestes funcionalitats fan que l’experiència sigui més “game-like” i milloren la resposta al tacte.

Proves realitzades:
  • Verificar la càrrega correcta de la imatge a p5.js.
  • Comprovar el comportament quan l’usuari cancel·la la selecció (sense perdre la partida actual).
  • Detectar problemes amb l’orientació/simetria de la foto (amb càmera frontal). Aquest punt queda pendent de resoldre per falta de temps per buscar una solució.

Decisions preses i aprenentatges adquirits

Durant el desenvolupament de l’MVP, he pres diverses decisions tècniques i de disseny:

Decisió 1: API externa → Picsum

S’ha triat Picsum com a API externa per:

  • Poder obtenir imatges aleatòries per jugar sense necessitat de tenir fotos personals.
  • Tenir una resposta en format JSON amb dades útils (com l’autor).
  • Evitar complicacions com l’autenticació o l’ús d’API keys.
  • Facilitar la idea d’un joc “rejugable”.
Decisió 2: Mostrar l’autor de la imatge

Quan s’utilitza una imatge de Picsum, es mostra un text sota el puzle amb l’autor. Això aporta:

  • Transparència.
  • Un toc de “crèdit” visual.
  • Millor integració amb el requisit de mostrar dades de l’API dins l’app.
Decisió 3: Afegir una previsualització de la imatge original

Com que el puzle pot ser difícil, s’ha afegit:

  • Una icona que permet veure la imatge sencera com a referència. No es tracta de la imatge original completa, sinó d’una secció quadrada de la imatge original. Aquesta imatge retallada és la que utilitzarà el puzle.
  • Aquesta funcionalitat millora el gameplay i permet resoldre el puzle amb més facilitat.
Aprenentatges principals
  • Les funcionalitats natives en apps híbrides poden tenir comportaments diferents segons el dispositiu (càmera frontal invertida, cancel·lacions, permisos…).
  • La UI afecta molt l’experiència: cal ajustar espais, alineacions, overlays i coherència visual.

Esbossos, captures i iteracions que mostrin l’evolució del projecte

Iteració 1: MVP funcional (PR1): puzzle amb imatge local i funcionament bàsic:

 

 

 

 

 

 

Iteració 2: Integració de l’API

  • Afegir el botó de Picsum per arregar una imatge aleatòria des del JSON.
  • Mostrar l’autor de la imatges
  • Afegir un HUD amb:
    • Comptador de moviments.
    • Comptador de temps.
    • Icona de previsualització i overlay per mostrar la imatge utilitzada en el puzzle itenir-la de referència.

Justificació breu: problemes trobats, solucions i conclusions

  • Problema 1: l’autor desapareix quan es cancel·la galeria/càmera
    Causa: el text de l’autor s’esborrava abans de confirmar que s’havia carregat una nova imatge.
    Solució: netejar l’autor només quan la càrrega de la nova imatge sigui exitosa.
  • Problema 2: puzles que començaven ja resolts
    Causa: el shuffle podia deixar el mateix estat final que el puzle resolt.
    Solució: aplicar una comprovació després del shuffle i repetir-lo fins que el puzle no estigui resolt.
  • Problema 3: el temps no s’aturava en resoldre el puzle
    Causa: el valor puzzle.solved no s’actualitzava just en el mateix moment del touchStarted.
    Solució: aturar el cronòmetre des del draw() quan el puzle està resolt.

Citació de totes les fonts utilitzades

Documentació oficial / fonts tècniques:

  • Capacitor (documentació oficial): Camera Plugin i Haptics Plugin.
  • Recursos sobre CORS i consum d’APIs en aplicacions web.

API externa:

  • Lorem Picsum API (endpoint /v2/list i càrrega d’imatges per ID).

He utilitzat ChatGPT com a suport per:

  • Depurar errors de l’app.
  • Proposar estructures de codi.
  • Millorar el CSS i la UX.
  • Resoldre conflictes d’overlays i layout.

Vídeo

Per realitzar aquest vídeo he utilitzat un ZTE Blade A51, Android versió 11.

Carregant...

Debat0el Pràctica 2

No hi ha comentaris.

Publicat per

DropApp – PR2

Publicat per

DropApp – PR2

1. Ideació i Evolució del Projecte Concepte: DropApp evoluciona d’un temporitzador passiu (PR1) a un assistent oftalmològic contextual. La sequedat ocular depèn…
1. Ideació i Evolució del Projecte Concepte: DropApp evoluciona d’un temporitzador passiu (PR1) a un assistent oftalmològic contextual. La…

1. Ideació i Evolució del Projecte

Concepte:

DropApp evoluciona d’un temporitzador passiu (PR1) a un assistent oftalmològic contextual. La sequedat ocular depèn directament de la humitat ambiental. Per tant, l’App no només avisa quan posar-se les gotes, sinó que informa l’usuari de l’estat del seu entorn immediat.

Selecció d’APIs (Estratègia de Dades):

Per oferir una experiència completa, he optat per combinar dues APIs complementàries:

  • BigDataCloud (Reverse Geocoding): Permet traduir les coordenades GPS fredes (ex: 41.38, 2.17) a un nom de ciutat comprensible per a l’usuari (ex: “Barcelona”).
  • Open-Meteo (Temps): Aporta la dada mèdica rellevant (% Humitat Relativa) sense necessitat de registre ni claus d’API.

Esbós preliminar de l’app

2. Desenvolupament Tècnic amb Capacitor

2.1. Arquitectura Híbrida

L’aplicació segueix el patró Bridge:

  • Capa Lògica (main.js): Actua com a orquestrador. Gestiona la geolocalització nativa i encadena les peticions a les dues APIs.

  • Capa Visual (sketch.js): Rep les dades processades (Nom de ciutat i Humitat) a través d’un objecte global compartit window.eyeWeather i les pinta al canvas

2.2. Integració de les APIs (Flux en Cascada)

S’ha implementat una lògica asíncrona robusta (async/await) al fitxer main.js per connectar el dispositiu amb les dues APIs externes:

  1. GPS Natiu (Geolocation): El plugin @capacitor/geolocation obté la latitud i longitud precises quan l’usuari té activat el mode “Ubicació GPS (Automàtic)”. S’utilitza enableHighAccuracy: true i un timeout de 10 segons per evitar bloquejos.

  2. Identificació (API 1 – BigDataCloud): Amb les coordenades rebudes, es consulta l’endpoint reverse-geocode-client de BigDataCloud amb el paràmetre localityLanguage=ca, prioritzant el nom de ciutat/localitat en català sempre que sigui possible.

  3. Dades Climàtiques (API 2 – Open-Meteo): A partir de la mateixa latitud/longitud es consulta Open-Meteo per obtenir la temperatura actual i la humitat relativa (temperature_2mrelative_humidity_2m), sense necessitat de registres ni claus d’API.

  4. Persistència i flux manual: Si l’usuari desactiva el GPS i selecciona una ciutat manualment, les coordenades escollides es desen a localStorage i es reutilitzen a les crides següents, mantenint el flux de dades encara que el GPS estigui aturat.

  5. Fallback per IP: Si no disposem de coordenades (primera obertura, error de GPS) l’app consulta de nou BigDataCloud, però en aquest cas mitjançant geolocalització per IP, per obtenir unes coordenades aproximades i un nom de ciutat genèric com a reserva.

  6. Sincronització i estats UX: Mentre esperem resposta de les APIs, l’objecte global window.eyeWeather mostra un estat de “????️ Cercant GPS” per indicar activitat. Si alguna de les crides falla, l’App entra en “Mode Offline (Sense dades)”, però evita trencar el flux visual del temporitzador i manté un estat de seguretat per a l’usuari.

2.3. Funcionalitats Natives

A part de la geolocalització, s’han integrat tres funcionalitats hardware per a l’experiència d’alerta:

    • Llanterna (@capawesome/capacitor-torch): Des de sketch.js es controla una màquina d’estats (0 = off, 1 = llum fixa, 2 = estroboscòpic) i, en funció del temps restant, es fan crides a window.setFlashMode() exposada per main.js. Aquest pont és el que activa o desactiva realment el maquinari de la llanterna al dispositiu.

    • Haptics (@capacitor/haptics): main.js encapsula el patró de vibració en bucle (setInterval) quan sona l’alarma final, i sketch.js hi accedeix mitjançant window.dropappVibrate() per donar feedback tàctil immediat en prémer els botons.

    • Local Notifications: Per garantir l’avís fins i tot si el dispositiu entra en repòs profund (Doze Mode), main.js programa l’alarma en el moment d’iniciar el comptador utilitzant la propietat allowWhileIdle i canals prioritaris. Això delega la responsabilitat al sistema operatiu, assegurant la puntualitat exacta independentment de l’estat de l’app.

Integració final mostrant ubicació i dades ambientals.

Temporitzador acabat, moment on està activat el flash, la vibració i on apareix la notificació

2.4. Mode de proves (interval 0)

Durant el desenvolupament ha estat necessari verificar el comportament del temporitzador i de les alertes sense haver d’esperar una hora real entre dosis. Per això, al fitxer sketch.js he implementat un mode prova:

  • L’usuari pot configurar les “Hores entre dosis” a 0 mitjançant la finestra de configuració.

  • Si el valor llegit des de localStorage és 0, l’aplicació interpreta que es tracta d’un mode debug i força l’interval intern a 1 minut (60 * 1000 ms) en lloc d’1 hora (60 * 60 * 1000 ms).

  • Això permet testejar totes les fases de l’alarma (pre-avís, estroboscopi, vibració i notificació) de forma ràpida, mantenint la configuració normal per a l’ús mèdic real.

D’aquesta manera puc comprovar el flux complet de l’app (UI p5.js + hardware + notificacions) sense haver d’esperar períodes llargs.

2.5. Resiliència i Gestió del Segon Pla

Per garantir que l’usuari rebi l’avís de la gota encara que el sistema operatiu “congeli” el JavaScript de l’App per estalviar bateria (comú en Android), he implementat una Estratègia Híbrida de Resurrecció:

  • Alarmes Exactes Nativament: He configurat els permisos SCHEDULE_EXACT_ALARM i USE_EXACT_ALARM a l’AndroidManifest. Això permet que el sistema natiu de notificacions desperti el dispositiu en el moment precís, independentment de l’estat de l’App.

  • Sincronització al Resume: Al fitxer main.js, he programat un listener del cicle de vida (resume). Quan l’usuari obre l’App des de la notificació, el codi compara immediatament el Timestamp actual amb l’hora objectiu emmagatzemada a localStorage.

  • Feedback Immediat: Si el temps s’ha esgotat durant el segon pla, l’App reactiva instantàniament les funcions de hardware (flash estroboscòpic i vibració) i l’estat d’alarma visual a p5.js, garantint una transició fluida i sense errors entre el segon pla i el primer pla.

3. Decisions Preses i Solució de Problemes

Un aspecte clau del disseny va ser la interpretació visual de les dades (Data Viz). No volia que l’usuari hagués d’interpretar xifres fredes. Per això, vaig implementar una lògica reactiva: si l’API d’Open-Meteo detecta una humitat inferior al 35% (llindar de risc per ull sec), l’app canvia automàticament el text d’estat a “Ambient SEC (Risc sequetat ocular)” i tenyeix la gota central de color ambre/groc. Això ofereix un diagnòstic visual instantani sense necessitat de lectura atenta.

Un altre repte va ser la gestió de noms de ciutat llargs al canvas. Ciutats com ” Colinas del Campo de Martín Moro” es tallaven visualment, així que al sketch.js vaig optar per utilitzar caixes de text delimitades que permeten el salt de línia automàtic (text wrapping), mantenint el text sempre centrat i llegible.

La latència de les APIs també va aparèixer com a problema: com que es fan dues crides externes (BigDataCloud + Open-Meteo), el temps de resposta podia allargar-se. Per evitar la sensació que l’app s’havia penjat, vaig afegir un estat intermedi “Cercant GPS…” a l’objecte global window.eyeWeather, de manera que l’usuari rep feedback immediat mentre arriba la informació.

Pel que fa als permisos de GPS, a Android 13 l’app fallava si no tenia ACCESS_FINE_LOCATION declarat al AndroidManifest.xml. A més d’afegir el permís, vaig introduir un timeout de 10 segons a la crida de geolocalització per evitar bloquejos en entorns amb mala cobertura de satèl·lits.

També es va detectar un crash relacionat amb les notificacions per falta del recurs gràfic de la icona. La solució va passar per generar el recurs ic_stat_dropapp dins de res/drawable i referenciar-lo a la configuració de LocalNotifications.schedule(), assegurant que Android disposa sempre d’una icona vàlida per mostrar l’avís.

Finalment, per garantir que l’alerta fos efectiva en entorns sorollosos o quan el dispositiu no és a la vista, es va decidir combinar tres canals: l’efecte visual de la llanterna i el fons “d’alarma”, la vibració repetida amb @capacitor/haptics i la notificació de sistema. Aquesta decisió reforça l’ús del maquinari natiu i millora l’accessibilitat general de l’app.

Objecte global:

window.eyeWeather: Sincronitza dades API entre main.js (productor) i sketch.js (consumidor), amb estats UX (“Cercant GPS…”, “Mode Offline”).

Finestra flotant de la configuració i cerca de GPS

4. Pròxims Passos: Publicació i Beta

Per convertir aquest MVP en una versió final preparada per a la Google Play Store, els passos següents són:

  • Optimització de Processos en Background: Tot i que l’estratègia actual de resurrecció és efectiva, el següent pas tècnic seria implementar @capacitor/background-runner. Això permetria que l’App seguís consultant l’API meteorològica de forma invisible per a l’usuari, actualitzant el diagnòstic climàtic fins i tot si l’App no s’obre en tot el dia.

  • Signatura de l’Aplicació (Keystore): Cal generar un Android App Bundle (.aab) signat criptogràficament des d’Android Studio. Aquest és un requisit indispensable de seguretat per identificar-me com a desenvolupador oficial davant de Google.

  • Privacitat i GDPR: Atès que l’App fa ús de geolocalització precisa i APIs de tercers (BigDataCloud/Open-Meteo), és necessari redactar i enllaçar una Política de Privacitat formal. En ella s’ha d’especificar que les coordenades GPS s’utilitzen de manera efímera i no s’emmagatzemen en servidors externs.

  • Proves en més dispositius: Tot i que el funcionament en Android 15 (Xiaomi) és correcte, caldria testejar l’App en versions anteriors d’Android (11 i 12) per assegurar que la gestió de permisos natius es comporta de manera consistent.

5. Referències i Recursos Utilitzats

Serveis de Dades (APIs)

  • Open-Meteo Weather API: Servei de dades meteorològiques (Humitat Relativa) sota llicència Creative Commons (CC BY 4.0). [https://open-meteo.com/]

  • BigDataCloud Reverse Geocoding: API client-side per a la transformació de coordenades a toponímia. Versió gratuïta per a desenvolupadors. [https://www.bigdatacloud.com/]

Tecnologies i Llibreries

  • Nucli: Capacitor (v6) per a la compilació nativa Android.

  • Visualització: p5.js (Processing Foundation) per al renderitzat del canvas i animacions.

  • Plugins de Sistema:

    • @capacitor/geolocation: Accés al GPS natiu.

    • @capacitor/local-notifications: Gestió d’avisos en segon pla.

    • @capacitor/haptics: Motor de vibració del dispositiu.

    • @capawesome/capacitor-torch: Control del maquinari de la llanterna (Flash).

Repositori del Projecte

  • Codi Font: Repositori públic disponible a GitHub: [https://github.com/Javime85/DropApp-PR2]

Debat0el DropApp – PR2

No hi ha comentaris.

Publicat per

PR2 – SKIP BALLS

Publicat per

PR2 – SKIP BALLS

Vídeo de presentación del proyectoEn este vídeo se muestra el funcionamiento de la App. Ideación de la App y selección de la…
Vídeo de presentación del proyectoEn este vídeo se muestra el funcionamiento de la App. Ideación de la App y…

Vídeo de presentación del proyecto
En este vídeo se muestra el funcionamiento de la App.

Ideación de la App y selección de la API externa

Para continuar con la segunda práctica, como se pedía en el enunciado, debía integrar una API externa que aportara valor real a la aplicación desarrollada en la PR1. Desde el inicio tuve claro que no quería añadir la API como un simple “extra técnico”, sino que debía integrarse de forma coherente dentro del concepto del juego.

Mi primera idea, antes incluso de investigar APIs existentes, fue que los skins de los robots pudieran obtenerse externamente. Sin embargo, rápidamente descarté esta opción, ya que el diseño del juego requiere que los personajes tengan ruedas y no animaciones de caminar, lo que hacía muy compleja la integración de assets externos sin romper la coherencia visual y funcional del juego.

La segunda idea fue utilizar la API Astronomy Picture of the Day de la NASA para mostrar un fondo distinto cada día. Llegué incluso a obtener el token y hacer pruebas, pero finalmente descarté esta opción al darme cuenta de que trabajar con imágenes tan pesadas no era adecuado para un juego arcade sencillo, además de suponer una carga innecesaria de procesamiento en cada iteración del draw.

Finalmente opté por integrar JokeAPI, una API que ofrece chistes de forma ligera y rápida. Me pareció una opción especialmente adecuada para un MVP, ya que aporta personalidad y trasfondo a los personajes sin interferir en la jugabilidad. En un juego arcade tan simple, dotar de carácter a los robots suma valor a la experiencia del usuario. Además, esta idea deja abierta una clara evolución futura del proyecto, como la creación de un lore o guion más elaborado, o personajes con estilos de humor propios que se puedan desbloquear progresivamente.

Para reforzar esta idea, el usuario puede seleccionar desde el panel de ajustes la categoría de humor que desea, y será el robot el que le “cuente” el chiste, reforzando la sensación de personaje con identidad propia.

Consultas y pasos seguidos en la documentación de Capacitor

El primer uso de Capacitor en el proyecto fue Capacitor Motion, utilizado para leer la inclinación del dispositivo móvil y permitir el movimiento lateral del jugador. Esta funcionalidad se encapsuló en un módulo externo motion.js, que posteriormente se importaba en sketch.js. En concreto, se utilizó Motion.addListener('orientation',
callback)
, obteniendo el valor gamma para controlar el movimiento izquierda/derecha.

En una iteración posterior del proyecto fue necesario mantener la pantalla encendida mientras el usuario jugaba, ya que en partidas largas la pantalla se apagaba automáticamente. Para solucionar esto se utilizó Capacitor Keep Awake, llamando a KeepAwake.keepAwake() desde setup(). Para asegurar la persistencia de los datos a largo plazo se decidió utilizar Capacitor Preferences. A diferencia del almacenamiento temporal, Preferences garantiza que los datos no se pierdan entre sesiones. Este plugin se utilizó para guardar información como la categoría de chistes seleccionada, opciones de audio, personajes desbloqueados, nombre de usuario y ranking de puntuaciones. La lógica se centralizó en el módulo storage.js, utilizando Preferences.get() y Preferences.set().

Durante el desarrollo surgió un problema con el audio: la música continuaba sonando aunque el usuario cambiara de aplicación o apagara la pantalla. Para gestionar correctamente estos estados se utilizó Capacitor App, empleando App.addListener('appStateChange',
callback)
para pausar música y lógica del juego cuando la app pasaba a segundo plano.

Para mejorar el feedback durante la partida se integró Capacitor Haptics. Se creó un módulo específico haptics.js, desde el que se utilizó Haptics.impact() para acciones suaves como recoger monedas y Haptics.vibrate() con duración para el Game Over. En este punto fue importante adaptar la implementación a las limitaciones del dispositivo utilizado.

Finalmente, la integración de la API externa se realizó mediante fetch, gestionando todas las llamadas de forma asíncrona con async/await.

El flujo de desarrollo fue el habitual con Capacitor:

  • En ordenador: npm run dev
  • En dispositivo real (Xiaomi Redmi Note 12): npm run
    build
    , npx cap sync android, npx cap open
    android

Pruebas con funcionalidades nativas del dispositivo

Para ajustar el control por inclinación fue necesario realizar múltiples pruebas, afinando la velocidad del movimiento del jugador hasta encontrar un equilibrio entre sensibilidad y control. Se limitaron los rangos de inclinación para evitar comportamientos erráticos.

En el caso de Haptics, el dispositivo Xiaomi utilizado no diferenciaba claramente entre los estilos light, medium y heavy. Por este motivo se optó por combinar Haptics.impact() para acciones leves y Haptics.vibrate() con duración para eventos importantes como la muerte del jugador, ofreciendo así un feedback más claro.

Integración de la API: dinamismo y control de errores

Cuando el jugador pierde la partida al colisionar con una bomba, el juego realiza una petición a la API de forma dinámica. Esta llamada depende directamente de la configuración del usuario, ya que la categoría de chistes seleccionada se inyecta como parámetro en la URL de la petición.

Dado que la conexión a internet puede fallar o no estar disponible, se implementó un sistema de fallback. Si la petición a la API falla o tarda demasiado, el juego utiliza una base de datos interna de chistes almacenados localmente, garantizando que la experiencia no se rompa.

Aunque la API permite seleccionar idioma, la cantidad de chistes disponibles en castellano era muy limitada, por lo que se decidió mantener los chistes en inglés, manteniendo el resto de la interfaz del juego en castellano.

Decisiones y aprendizajes

Inicialmente la idea era mostrar los chistes durante la partida cada vez que el jugador recogía una moneda. Sin embargo, tras probarlo, se comprobó que esta decisión rompía el ritmo del juego y perjudicaba la experiencia de usuario. Finalmente se optó por mostrar los chistes únicamente en la pantalla de Game Over, momento en el que el jugador puede leerlos con calma.

Fue necesario implementar un sistema claro de estados del juego: pantalla de inicio, juego activo, Game Over y ajustes. Esto permitió que el proyecto funcionara como un MVP estable y comprensible.

Durante el desarrollo también fue clave aprender a depurar directamente en Android mediante Logcat, ya que muchos errores no eran visibles desde las herramientas de desarrollo del navegador.

Problemas, soluciones y conclusiones

Uno de los problemas más complejos fue gestionar correctamente el audio y la persistencia de datos asíncronos. Al tener el código distribuido en varios módulos y trabajar de forma intermitente en el tiempo, fue necesario apoyarse en flags, pruebas controladas y herramientas de IA como Gemini y Copilot para identificar rápidamente los errores.

Como conclusión, este proyecto ha servido para consolidar el flujo completo de desarrollo de una app híbrida con Capacitor, desde la ideación hasta la distribución, y para entender la importancia de diseñar bien un MVP antes de escalar funcionalidades.

Bocetos, capturas e iteraciones

Primeros bocetos para la implementación de los chistes:

Resultados del estado de inicio de la app, estado de juego, Game Over y settings:

Fuentes y citaciones

Vínculo al .apk

https://github.com/elecinas/skip-balls/releases/download/v1.0/app-debug.apk

Debat0el PR2 – SKIP BALLS

No hi ha comentaris.

Publicat per

(PR1) Camina i fes UNLOCK!

Publicat per

(PR1) Camina i fes UNLOCK!

  Procés d’ideació i possible aplicació del projecte El projecte Camina i fes UNLOCK! s’ha concebut com una aplicació que transforma l’acció…
  Procés d’ideació i possible aplicació del projecte El projecte Camina i fes UNLOCK! s’ha concebut com una aplicació…

 

Procés d’ideació i possible aplicació del projecte

El projecte Camina i fes UNLOCK! s’ha concebut com una aplicació que transforma l’acció quotidiana de caminar en una experiència de descobriment visual progressiu. La idea principal és que l’usuari desbloquegi contingut sense haver d’interactuar constantment amb el dispositiu, fent de l’app una experiència pràcticament effort-free.

Durant la fase d’ideació, un dels primers problemes va ser definir un concepte prou senzill però amb projecció futura. Inicialment es van considerar idees més complexes, però es va optar per una mecànica clara i escalable. Aquesta decisió va permetre mantenir la demo acotada i funcional, però alhora obrir la porta a un possible ús turístic, on ciutats o pobles podrien oferir conjunts d’imatges associades a recorreguts concrets, incloent informació històrica o cultural.

Funcionament de la demo actual

La demo implementa el comportament de l’app amb 5 imatges, suficients per entendre el funcionament general del sistema. Les imatges utilitzades són fotografies pròpies realitzades entre 2010 i 2013, fet que aporta coherència i control total sobre el contingut visual.

Un dels problemes detectats en aquesta fase va ser com representar visualment el progrés sense recórrer només a números o barres clàssiques. La solució va ser utilitzar el canvas per mostrar una imatge pixelada que es va revelant progressivament, convertint el progrés en una experiència visual clara i intuïtiva. Això va permetre reforçar la idea de “desbloqueig” i fer el procés més atractiu.

Canvas i representació del progrés

El canvas és l’element central de l’aplicació. Cada imatge comença mostrant-se pixelada i es va revelant mitjançant tiles segons el percentatge de progrés assolit. El càlcul es basa en una relació directa entre distància recorreguda i metres necessaris per completar la imatge:

const progress = distanceMeters / METERS_TO_UNLOCK;

const tilesToShow = Math.floor(progress * totalTiles);

Durant el desenvolupament d’aquesta part va aparèixer el problema de gestionar l’estat visual sense sobrecarregar l’emmagatzematge. Inicialment es va plantejar guardar l’estat de cada tile, però això complicava el sistema. Finalment, es va optar per recalcular el nombre de tiles visibles a partir del percentatge global, simplificant el codi i millorant el rendiment.

Controls, navegació i mode DEMO

L’aplicació inclou diversos controls: START per iniciar el repte, SEGÜENT per seleccionar quina imatge es vol desbloquejar i RESET per reiniciar completament la demo. També s’ha incorporat un mode DEMO que permet avançar manualment el progrés.

Un problema clau en aquesta fase va ser com provar correctament l’app sense disposar d’un dispositiu Android físic. La solució va ser implementar el mode DEMO, que permet simular l’avanç de metres dins l’emulador d’Android Studio. Aquest sistema ha estat essencial per validar animacions, lògica de progrés i navegació sense dependre del GPS real.

Dins dels settings, apart del mode DEMO, trobem també un “mode NIT”, un on/off per la vibració, i un selector per la mida dels TILES. Totes aquestes opcions són per a que l’usuari pugui adaptar l’app a les seves necessitats.

Galeria i visualització d’imatges desbloquejades

Les imatges completades es poden consultar des d’una galeria integrada. Quan una imatge està desbloquejada, s’obre en un visor net amb opcions de zoom per examinar-la amb més detall.

Durant el desenvolupament de la galeria va sorgir un problema important: les animacions de desbloqueig apareixien també quan s’obrien imatges ja desbloquejades. Això generava confusió visual. La solució va ser separar clarament l’estat de “desbloqueig en curs” de l’estat de “visualització”, assegurant que les animacions només apareguin durant el moment exacte del desbloqueig.

Proves i entorn de test

Atès que no s’ha disposat de cap smartphone o tablet Android físic, totes les proves s’han realitzat amb Android Studio mitjançant emuladors. Aquest procés ha permès testejar l’app diverses vegades i ajustar tant la interfície com el comportament intern.

Un problema recurrent en aquesta fase va ser la configuració inicial del projecte Android i la gestió de fitxers generats automàticament. Es van produir errors d’importació a Android Studio fins que es va entendre quins fitxers havien de formar part del codi font i quins no. La resolució va consistir a eliminar caches i fitxers locals (com .gradle, build o local.properties) i verificar que el projecte es pogués reconstruir correctament amb les comandes estàndard.

 

Les proves finals s’han realitzat amb Android Studio am bels següents perfils:

  • Tablet Pixel (API 35)
  • Pixel 9 Pro XL (API 36)
  • Medium Phone (API 36.1)

 

 

Resultat final i aprenentatges

El resultat final és una aplicació Android funcional i estable, amb una experiència d’usuari clara i coherent amb el concepte inicial. Camina i fes UNLOCK! demostra com una idea senzilla pot convertir-se en una experiència rica mitjançant una bona representació visual i l’ús adequat de funcionalitats natives.

A nivell d’aprenentatge, el projecte ha posat en evidència la importància del testing iteratiu, la resolució progressiva de problemes i la necessitat de preparar correctament un projecte perquè sigui executable en entorns nets. També ha servit per entendre el potencial de Capacitor com a eina per portar aplicacions web a l’àmbit mòbil.

 

ENLLAÇ A GITHUB: https://github.com/JosepMSole/camina-i-fes-unlock

Debat0el (PR1) Camina i fes UNLOCK!

No hi ha comentaris.

Publicat per

Pràctica 1

Publicat per

Pràctica 1

Introducció i objectiu de l’App L’objectiu d’aquest projecte ha estat desenvolupar una App interactiva basada en un puzle de peces mòbils que…
Introducció i objectiu de l’App L’objectiu d’aquest projecte ha estat desenvolupar una App interactiva basada en un puzle de…

Introducció i objectiu de l’App

L’objectiu d’aquest projecte ha estat desenvolupar una App interactiva basada en un puzle de peces mòbils que permet a l’usuari carregar una imatge des de la càmera o la galeria del dispositiu. L’App transforma aquesta imatge en un trencaclosques i ofereix opcions de configuració per ajustar-ne la dificultat (mida del puzle).

Procés d’ideació de l’App

Des de l’inici tenia clar que volia crear una App lúdica i senzilla, però tenia dubtes sobre quines funcionalitats natives del mòbil volia incorporar. Finalment, vaig decidir experimentar amb la càmera i, a partir d’aquí, em va sorgir la idea de desenvolupar un joc de puzle utilitzant una imatge triada per l’usuari.
Com que aquesta App tindrà continuïtat a la Pràctica 2, he creat una estructura inicial senzilla amb la previsió d’ampliar-la i evolucionar-la en la pròxima entrega.

En el menú opcions ofereix la possibilitat de triar la mida del puzzle. Es permet triar 2×2,3×3,4×4, 5×5,6×6. L’opció escollida es guarda en localStorage per redimensionar la graella del puzzle.

Consultes externes

Durant el desenvolupament vaig realitzar consultes externes per resoldre dubtes tècnics i generar proves ràpides. Principalment, vaig utilitzar ChatGPT com a suport per:

  • Detectar errors en la gestió del DOM amb p5 i millorar l’estructura del codi i l’organització de funcions.
  • Consultar exemples de projectes similars i fragments d’algorismes per assegurar-me que seguia una lògica correcta.

Documentació de Capacitor rellevant per a l’App

Per integrar funcionalitats natives, he utilitzat Capacitor. Les parts més rellevants han estat:

  • Camera API: per obtenir imatges del dispositiu. A través de Camera.getPhoto() amb resultType: Uri vaig recuperar la ruta webPath que posteriorment es carrega a p5 amb loadImage().
    Per fer us de la càmera cal modificar el AndroidManifest.xml. Aconcretament, s’ha d’afegir aquest codi dins manifest > application > provider.
<intent-filter>
<action android:name="com.google.android.gms.metadata.MODULE_DEPENDENCIES" />
</intent-filter>
<meta-data android:name="photopicker_activity:0:required" android:value="" />

A l’apartat de permisos també cal afegir:

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> 
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

En el codi, cal instal·lar les dependències necessàries:

import { Camera, CameraResultType, CameraSource } from '@capacitor/camera';
import { Haptics, ImpactStyle } from '@capacitor/haptics';

I executar les següents ordres:

npm install @capacitor/camera
npm install @capacitor/haptics
  • Haptics API: he aprofitat l’exemple del tutorial Pomodoro per afegir feedback a la interacció. Cada moviment vàlid de peça activa un impact lleuger i, en completar el puzle, una vibració curta.
import { Haptics, ImpactStyle } from '@capacitor/haptics';

Amb la següent ordre:

npm install @capacitor/haptics

Esbossos i captures

 

 

 

 

 

 

 

 

 

 

Principals proves i millores

Les principals proves i millores han estat les següents:

  • Ajust del canvas a la pantalla per garantir una experiència coherent en diferents dispositius.
  • Tractament de la imatge: inicialment, la imatge es deformava; es va solucionar aplicant un retall quadrat centrat (cropToSquare) abans de redimensionar-la al canvas.
  • Barreja del puzle: per evitar combinacions impossibles, es va implementar una barreja basada en moviments vàlids a partir de la configuració inicial resolta.
  • Experiència d’usuari: es va incorporar feedback hàptic en cada moviment i també quan es completa el puzle.

Problemes trobats

Durant el desenvolupament, els principals problemes trobats han estat:

  • Gestió de l’estat: com detectar quan hi ha una imatge carregada i com canviar correctament la vista.
  • Tractament d’imatges amb formats diferents: solucionat amb un retall quadrat centrat i el redimensionament posterior.Assegurar que la barreja del puzle fos resoluble: solucionat mitjançant una barreja basada en moviments vàlids.

A més, prèviament vaig tenir un problema amb el Virtual Device Manager d’Android Studio. En intentar iniciar l’emulador Medium Phone API 36.1 des del Virtual Device Manager, apareixia un error que impedia l’execució.

Tot i que utilitzo Ubuntu 24.04.3 LTS, també vaig provar d’executar-lo en Windows i el problema es mantenia. Per resoldre aquesta incidència, vaig utilitzar especialment ChatGPT com a suport.
Finalment, vaig entendre que aquest error indicava que l’emulador no podia utilitzar l’acceleració per maquinari (KVM) perquè el dispositiu /dev/kvm no existia. Aquesta situació acostuma a produir-se per diversos motius, però en el meu cas la causa era que la virtualització (VT-x/AMD-V) estava desactivada a la BIOS.

Debat0el Pràctica 1

No hi ha comentaris.

Publicat per

App Skip Balls

Publicat per

App Skip Balls

Procés d’ideació de l’aplicació Per a la realització d’aquest repte era necessari concebre una aplicació mòbil que fes ús d’alguna funcionalitat nativa…
Procés d’ideació de l’aplicació Per a la realització d’aquest repte era necessari concebre una aplicació mòbil que fes ús…

Procés d’ideació de l’aplicació

Per a la realització d’aquest repte era necessari concebre una aplicació mòbil que fes ús d’alguna funcionalitat nativa del dispositiu mòbil. Des del principi tenia clar que volia desenvolupar una aplicació de caràcter lúdic, ja que és un tipus de projecte que permet experimentar tant amb la interacció com amb la part visual.

Com a referència inicial, em vaig inspirar en jocs clàssics d’arcade com Galaxian o Arkanoid, especialment pel que fa a la simplicitat mecànica i al’ús de moviment com a element central del joc. A partir d’aquí vaig decidir aprofitar el giroscopi del mòbil per controlar el moviment del personatge, fent que aquest es desplaci lateralment segons la inclinació del dispositiu.

La idea final es concreta en un joc on cauen objectes des de la part superior de la pantalla, i el jugador ha d’esquivar-los movent el mòbil de costat a costat, simulant un efecte de gravetat.

Procés de desenvolupament i adaptació del tutorial base

El punt de partida del projecte va ser el tutorial base proporcionat per l’assignatura, que explicava com crear una aplicació senzilla amb Capacitor, p5.js i accés a les funcionalitats natives del dispositiu.

A partir d’aquesta base, el projecte va evolucionar progressivament mitjançant la integració d’un canvas a pantalla completa, la implementació d’un sistema de joc i l’ús de les funcionalitats natives.

Durant el desenvolupament es van resoldre diversos problemes tècnics, especialment relacionats amb errors d’instal·lació d’Android Studio, configuració de dependències i execució de l’app en dispositius reals.

Tot aquest procés va permetre entendre millor com Capacitor actua com a pont entre el codi JavaScript i les funcionalitats natives del sistema operatiu.

Ús de funcionalitats natives del dispositiu

L’aplicació, mitjançant Capacitor, fa ús dels sensors d’orientació (Motion API) que detencten la inclinació del dispositiu i permeten controlar el moviment lateral del personatge dins del joc.

També es va fer servir la pantalla sempre activa (Keep Awake) utilitzant un plugin de Capacitor per evitar que la pantalla s’apagui durant la partida. I, finalment, l’emmagatzematge local mitjançant l’API Preferences que es fa servir per guardar l’informació de l’usuari, puntuació, ranking i personatges desbloquejats. Amb tot aixó s’aconsegueix complir el requisit d’integrar elements natius dins l’aplicació.

Proves, iteracions i millores

Durant el desenvolupament es van realitzar múltiples proves tant en emulador Android com en dispositius reals, ja que algunes funcionalitats (com els sensors) no es poden fer servir en entorns simulats.

Després de les proves es van aplicar millores com l’ajustament de velocitat i acceleració del personatge, regular freqüéncia i velocitat de caiguda de partícules, afegir sistema de Game Over i reinici de partida i, finalment, implementar un sistema de dificultat progressiva.

Presa de decisions i aprenentatges

Una de les decisions més importants va ser simplificar l’abast del projecte, centrant-me en una mecànica clara i funcional, en lloc d’intentar integrar massa funcionalitats natives que podrien complicar el desenvolupament.

També va ser rellevant decidir separar el codi en mòduls (particles, storage, motion), millorant la llegibilitat i el manteniment del projecte.

A nivell d’aprenentatge, aquest projecte ha permès entendre el flux de treball amb Capacitor, el desplegament d’apps en Android, depurar errors natius mitjançant Logcat i integrar sensors del dispositiu en una aplicació.

Ús d’IA generativa com a suport

Durant el desenvolupament del projecte s’ha utilitzat la IA generativa com a eina de suport, principalment:

  • ChatGPT: Per resoldre bloquejos tècnics, errors de consola, problemes d’instal·lació i dubtes sobre Capacitor. Els prompts incloïen directament errors i captures de pantalla.
  • GitHub Copilot: Integrat a Visual Studio Code per detectar errors de codi.
  • Gemini: utilitzat per a la generació d’estils visuals (CSS), ja que la part estètica no era l’objectiu principal de l’assignatura.

L’ús d’aquestes eines ha permès agilitzar el procés i centrar esforços en el disseny i la lògica del joc.

Fonts i recursos utilitzats

Conclusions

Aquest projecte ha estat una primera aproximació al desenvolupament d’aplicacions mòbils natives utilitzant tecnologies web. A través de Capacitor, ha estat possible reutilitzar coneixements previs de JavaScript i p5.js per crear una aplicació funcional, interactiva i preparada per créixer en futures iteracions (pràctica 2).

El procés ha posat especial èmfasi en la resolució de problemes, l’experimentacio i l’aprenentatge pràctic, aspectes clau en el desenvolupament d’apps reals.

Vincle a GitHub

Repositori: https://github.com/elecinas/skip-balls

Dispositiu mòbil per les proves

Xiaomi Redmi Note 12

Debat0el App Skip Balls

No hi ha comentaris.

Publicat per

Ideació de DropApp

Publicat per

Ideació de DropApp

Pomodoro base amb Vite, p5.js i Capacitor Abans de dissenyar DropApp, vaig seguir un tutorial de Pomodoro Timer per entendre el flux complet entre Vite, p5.js i Capacitor.…
Pomodoro base amb Vite, p5.js i Capacitor Abans de dissenyar DropApp, vaig seguir un tutorial de Pomodoro Timer per entendre el…

Pomodoro base amb Vite, p5.js i Capacitor

Abans de dissenyar DropApp, vaig seguir un tutorial de Pomodoro Timer per entendre el flux complet entre Vitep5.js i Capacitor. Vaig crear un projecte amb plantilla vanilla de Vite, afegir p5.js i p5.sound com a scripts clàssics al directori public, i utilitzar el mode instància per evitar conflictes de variables globals.

Captura del navegador amb el primer canvas

A continuació vaig implementar un Pomodoro complet a src/sketch.js: dues fases (25 min treball + 5 min pausa), cercle de progrés, temps gran al centre i botó play/pausa. La targeta vertical centrada millora la llegibilitat i prepara la base visual per DropApp.

Captura del navegador amb el Pomodoro final

Finalment vaig integrar Capacitor, afegir la plataforma Android, generar el build amb npm run build i copiar-lo amb npx cap copy android. Al Android Studio es va executar en emulador i dispositiu físic, comprovant que el Pomodoro funciona igual que al navegador.

Captura d’Android Studio amb l’emulador mostrant el Pomodoro

Captura del telèfon físic amb el Pomodoro en execució

Ideació de DropApp

Partint del tutorial Pomodoro, vaig adaptar el context cap a una necessitat personal: recordar la pauta de gotes oftalmològiques diàries. DropApp mostra el temps fins a la pròxima dosi amb un cercle animat i botó de confirmació, més una configuració mínima (hores entre dosis + mode fosc).

Esbós de com volia que fos inicialment la pàgina principal

Esbós de com volia que fos inicialment la pàgina de configuració

Desenvolupament i adaptació del tutorial

Un cop el Pomodoro funcionava empaquetat amb Capacitor a Android Studio, vaig adaptar el codi:

  • Texts de “treball” → missatges sobre gotes

  • Cercle → temps fins a pròxima dosi

  • Temporitzador → hores en lloc de minuts

Captura del navegador amb DropApp funcionant 

Captura DropApp a Xiaomi Redmi Note 14 Pro

Vaig afegir un panell de configuració (botó ⚙️) per definir hores entre dosis i activar mode fosc, guardant valors a localStorage.

Panell de configuració obert al navegador

Panell configuració al dispositiu

El logotip dissenyat com “p” + ull + gota es va processar amb Android Studio Image Asset per icones adaptatives.

Logotip original DropApp “p + ull + gota”

Icona de DropApp al launcher del Xiaomi Redmi Note 14 Pro

Integració de funcionalitats natives

Per complir el requisit d’integrar funcionalitats natives s’ha utilitzat el plugin Haptics de Capacitor per generar feedback de vibració quan l’usuari prem el botó “M’he posat les gotes” i quan el temporitzador arriba a zero, moment en què es vol reforçar que toca una nova aplicació del col·liri. A més, s’ha provat el plugin de Local Notifications per mostrar una notificació amb so quan s’esgota el temps, amb l’objectiu que l’usuari rebi l’avís encara que no estigui mirant la pantalla.

​Fragment de codi destacant la crida a Haptics i LocalNotifications 

Per a les funcionalitats natives he emprat el plugin Haptics per generar vibració quan l’usuari marca que s’ha posat les gotes i quan el temporitzador arriba a zero, i he provat Local Notifications per programar avisos amb so encara que l’app estigui en segon pla.

Llanterna + vibració activades quan el temporitzador arriba a zero (Xiaomi Redmi Note 14 Pro)

Durant les proves s’ha detectat que, en el dispositiu Xiaomi utilitzat, la vibració i el so de notificació estan fortament condicionats per la configuració de MIUI i les opcions de seguretat. Tot i que el codi fa les crides correctes als plugins, en alguns casos la vibració és imperceptible o les notificacions queden limitades, fet que es documenta com a limitació del dispositiu i no de la lògica de l’app.

Problemes trobats i solucions

Problema Solució
INSTALL_FAILED_USER_RESTRICTED Activar “Instal·lació USB” a opcions desenvolupador MIUI
p5.sound “Loading…” Eliminar so web → Haptics + navigator.vibrate()
Pantalla negra Android WebView + configuració dispositiu (funciona navegador)
Timer segon pla Pendent: timestamp localStorage + notificació nativa

Mirant cap a la PR2

De cara a la PR2 es planteja mantenir DropApp com a eina de recordatori de gotes, peròenriquir-la amb una API externa gratuïta i sense autenticació. Es considera especialment interessant una API de clima o humitat, com ara Open-Meteo, per mostrar a l’usuari dades ambientals relacionades amb la sequedat ocular (temperatura, humitat relativa, vent) i contextualitzar la importància de seguir la pauta de gotes.​

Mockup de com es podria veure

Això permetrà que, a la PR2, DropApp no només recordi quan aplicar la gota, sinó que també ofereixi informació externa rellevant per comprendre millor per què alguns dies els símptomes de sequedat ocular poden ser més intensos.

Referències i eines

  • HTML5. Llenguatge de marcat per estructurar la interfície base de l’aplicació híbrida.
  • CSS3. Utilitzat per disseny visual, disposició responsive i mode fosc/clar de DropApp.
  • JavaScript (ES6+). Llenguatge principal per lògica del temporitzador, gestió d’estats, controls UI i comunicació amb plugins natius.
  • p5.js. Llibreria per canvas interactiu, animació gota procedimental (bézier + map()) i cercle progrés (arc()).
    **p5.js Reference. (2025). arc() & bezierVertex(). https://p5js.org/reference**
  • Capacitor 6. Framework per empaquetar app web en aplicació mòbil Android, pont entre JavaScript i APIs natius.
    • @capacitor/haptics. Plugin natiu per vibració (ImpactStyle.Heavy) al confirmar gotes i final temporitzador.
    • Capacitor Documentation. (2025). Haptics Plugin API. https://capacitorjs.com/docs/apis/haptics**
      @capacitor/local-notifications. Plugin per notificacions locals amb so quan s’esgota interval de dosis.
    • Ionic Team. (2025). Local Notifications Plugin. https://capacitorjs.com/docs/apis/local-notifications**
      @capawesome/capacitor-torch. Plugin per llanterna (fix + parpelleig) al final temporitzador.
  • localStorage. Emmagatzematge persistent per configuració (hores dosis + mode fosc).
  • Android Studio. Entorn desenvolupament per compilar APK, executar emulador/dispositiu, analitzar Logcat i generar icones adaptatives amb Image Asset Studio.
  • Vite. Build tool per desenvolupament ràpid (HMR) i optimització producció (npm run build).
  • Node.js & npm. Gestió dependències i execució comandes Capacitor (npx cap sync android).
  • Xiaomi Redmi Note 14 Pro (Android 15). Dispositiu proves principals amb HyperOS/MIUI limitacions documentades.
  • Perplexity AI. Assistència IA per ideació mockups PR2 (Open-Meteo API + gràfics humitat).

Debat0el Ideació de DropApp

No hi ha comentaris.

Publicat per

(R3) METEOQUARS

Publicat per

(R3) METEOQUARS

El projecte METEOQUARS s’ha desenvolupat per al Repte 3, que plantejava la creació d’una extensió per a Firefox basada en l’ús del…
El projecte METEOQUARS s’ha desenvolupat per al Repte 3, que plantejava la creació d’una extensió per a Firefox basada…

El projecte METEOQUARS s’ha desenvolupat per al Repte 3, que plantejava la creació d’una extensió per a Firefox basada en l’ús del temps, en la reutilització del Rellotge Creatiu del Repte 1 i en la incorporació d’una interfície construïda amb el DOM i amb persistència de dades.

En el marc d’aquest enunciat, es va adaptar el rellotge original programat amb p5.js a un format més reduït i coherent amb l’espai disponible a la barra superior del navegador, i es va sincronitzar automàticament amb l’hora real del sistema (a diferencia del Repte 1, que es podía programar manualment), assegurant que continués representant el pas del temps tal com s’exigia en l’activitat. Aquesta adaptació es va integrar al fitxer clock.js, carregat des del content-script.

Es van realizar alguns petits esboixos per decidir-ne l’aspecte, ja que el rellotge creatiu tenia una forma més aviat rectangular. Així doncs, es va decidir que l’extensió ocuparia l’ample de la pàgina, mantenint l’alçada de 150px.

També es va treballar en la creació de l’extensió amb Manifest V3. El manifest.json inclou els permisos necessaris, com storage, i els host_permissions per poder connectar amb l’API d’Open-Meteo. A més, s’hi defineixen tots els recursos externs de l’extensió —p5.js, icones GIF, scripts principals— que estructuren la base del projecte i en garanteixen el funcionament dins del navegador Firefox.

La construcció de la interfície amb el DOM es va fer completament des del content-script.js. Aquesta interfície incorpora elements de UI com el cercador de localització, els botons de desament i previsió, les etiquetes informatives i els contenidors visuals per a la icona meteorològica i el rellotge. Es van distribuir en tres blocs principals (esquerra, centre i dreta) per aconseguir una presentació clara i organitzada. Els estils visuals, es van aplicar amb CSS, injectat des del mateix script, però adaptable a un fitxer style.css extern si cal.

Quant a la persistència de dades, un altre punt clau del repte, es va optar per utilitzar localStorage, que funciona com a equivalent als mètodes storeItem() i getItem() de p5.js. En aquest espai s’hi desa la localització escrita per l’usuari i les seves coordenades corresponents. Quan l’extensió es torna a activar, el content-script recupera automàticament aquesta informació i actualitza la meteorologia, garantint que l’usuari mantingui el seu estat sense necessitat de repetir cap acció.

Amb l’objectiu d’“anar més enllà”, es van integrar fonts externes i funcionalitats ampliades. Concretament, es va utilitzar l’API pública d’Open-Meteo per obtenir temperatura, precipitació i codis meteorològics sense necessitat de clau d’accés. A partir d’aquestes dades, es va implementar una previsió de 48 hores analitzant la variació de precipitació, l’estat del cel i les temperatures.

L’ experiència visual es va reforçar amb cinc icones meteorològiques animades (amb After Effects) en format GIF, creades especialment per representar els 5 estats posibles d’aquesta primera versió: sol, sol i núvol, núvol, pluja i tempesta. També es va incorporar un sistema de color de fons dinàmic que canvia automàticament segons l’estat meteorològic detectat, aportant una lectura immediata i enriquint la percepció final de la interfície.

Com a possibles millores futures es podria incloure una webcam en directe mostrant una camera meteo del lloc buscat, però després d’investigar una mica, no hi ha cap servei que permeti mostrar qualsevol webcam de qualsevol lloc del mon, així que es varia la idea, i per tal d’aprofitar aquell espai, la següent iteració podria incloure una imatge omplint aquell espai (amb un degradat al final de l’esquerra) relacionada amb el resultat del temps de la ubicació cercada.

En el següent exemple es mostra la opció de “Ennuvolat”:

També es podria generar una versió “Mini” de la barra, i readaptar els elements per a un display més reduït.

CONCLUSIÓ

En conjunt, METEOQUARS (que podem variar el nom a METEOQUARTS, tot i què per algun motiu sonava millor sense la T) es presenta com una extensió que integra l’ús del temps, p5.js i una interfície construïda amb el DOM. Manté les dades entre sessions, mostra informació meteorològica actual i incorpora elements visuals i funcionals que en milloren l’experiència. El resultat és una eina clara i pràctica que et permetrà dir: “Abans de dos quarts de 6 estava plovent a Quito”.

————————————-

ENLLAÇ A GITHUB

https://github.com/JosepMSole/-R3-_METEOQUARS

 

Debat0el (R3) METEOQUARS

No hi ha comentaris.

Publicat per

R3 extensió web

Publicat per

R3 extensió web

Documentació de l’Extensió Rellotge Binari   Concepte del projecte Aquesta extensió és una aplicació de tipus WebExtension per al navegador Firefox. Mostra…
Documentació de l’Extensió Rellotge Binari   Concepte del projecte Aquesta extensió és una aplicació de tipus WebExtension per al…

Documentació de l’Extensió Rellotge Binari

 

Concepte del projecte

Aquesta extensió és una aplicació de tipus WebExtension per al navegador Firefox. Mostra un rellotge binari minimalista dins d’un popup, permetent personalitzar el color dels bits i la visualització de l’hora digital. L’objectiu és oferir una eina visual i estètica que representi el temps d’una manera alternativa.

Esbossos del disseny


Les tres columnes representen l’hora (columna esquerra), els minuts (columna central) i els segons (columna dreta). Cada columna té sis quadrats que representen els bits d’un nombre binàri.

Hi ha nombres que, en convertir-los a binari, no necessiten 6 dígits per ser representats. Per exemple, el número 23 es converteix en 10111, que només té 5 dígits. Per mantenir totes les columnes del rellotge amb la mateixa alçada i el mateix nombre de quadrats, he afegit zeros a l’esquerra fins a completar els 6 dígits. D’aquesta manera, hores, minuts i segons sempre formen columnes uniformes i visualment alineades.

Alhora de representar aquest números binaris en les columnes, el primer dígit de l’esquerra es representa a dalt de tot en la seva colummna corresponent i els digits següents és van dibuixant en la columna en ordre descendent. Els quadrats grisos equivalen a 0 i els quadrats blaus equivalen a 1.

Casos d’ús principals

  • Consultar l’hora en format binari.
  • Personalitzar el color dels bits per adaptar-lo al gust o al tema del navegador.
  • Activar o desactivar la visualització de l’hora digital.

Interacció amb els elements

La icona de configuració en el popup redirecciona a la secció de configuració on es pot decidir:

  • Mostrar o no l’hora en format digital
  • Canviar el color dels cuadrats que representen bits actius.

Ús de storeItem() i getItem()

L’extensió utilitza localStorage per recordar les preferències de l’usuari. Quan l’usuari canvia el color dels bits o la configuració de l’hora digital, la informació s’emmagatzema amb storeItem(). Quan el popup es torna a obrir, getItem() recupera les preferències guardades, permetent mantenir la configuració personalitzada sempre activa.

Millora proposada
Fixar el popup perquè es pugui mantenir obert (“pin popup”).

Normalment, el popup d’una extensió es tanca automàticament quan l’usuari fa clic fora o canvia de pestanya. Això és una limitació de totes les extensions: un popup no pot quedar-se obert per si mateix. La millora consisteix a simular un “popup fix” obrint una finestra pròpia de l’extensió que actua com una mini-aplicació flotant.

Això permetria:

  • Mantenir el rellotge sempre visible.
  • Posicionar-lo lliurement.
  • Tancar-lo manualment quan l’usuari vulgui.
  • Obrir múltiples “rellotges” si es permet.

Procediment proposat:

  • Afegir una icona estil “xinxeta” al popup

Quan l’usuari prem el botó, sobre una petita finestra independent que no es tanca sola, es pot moure, i té el mateix contingut que el popup.

  • Diferenciar el popup real de la finestra flotant

El codi podria detectar si està dins una finestra flotant:

  • 3. Desactivar elements innecessaris en la versió fixada.

• Amagar el botó “Opcions”
• amagar la icona “xinxeta” (per no obrir infinites finestres)

Enllaç Git

https://github.com/magulloc/rellotge-binari.git

Debat0el R3 extensió web

No hi ha comentaris.