Full text
Equation Chapter 1 Section 1 Trabajo de Fin de Grado Grado en Ingeniería de las Tecnologías de Telecomunicación Aplicación móvil para la gestión de listas de ejercicios de entrenamiento en React Native Dpto. de Ingeniería Telemática Escuela Técnica Superior de Ingeniería Universidad de Sevilla Autor: María de los Reyes Machuca Romero Tutor: María Teresa Ariza Gómez aa Sevilla, 2022
ii
iii Trabajo Fin de Grado Grado en Ingeniería de las Tecnologías de Telecomunicación Aplicación móvil para la gestión de listas de ejercicios de entrenamiento en React Native Autor: María de los Reyes Machuca Romero Tutor: María Teresa Ariza Gómez Profesora titular Dpto. de Ingeniería Telemática Escuela Técnica Superior de Ingeniería Universidad de Sevilla Sevilla, 2022
iv
v Trabajo de Fin de Grado: Aplicación móvil para la gestión de listas de ejercicios de entrenamiento en React Native Autor: María de los Reyes Machuca Romero Tutor: María Teresa Ariza Gómez El tribunal nombrado para juzgar el Proyecto arriba indicado, compuesto por los siguientes miembros: Presidente: Vocales: Secretario: Acuerdan otorgarle la calificación de: Sevilla, 2022 El Secretario del Tribunal
vi
vii A mi familia A mis amigos A mis maestros
viii
ix Agradecimientos Me gustaría agradecer a las personas que me han apoyado durante estos meses tan difíciles y a la vez tan valiosos en los que he estado elaborando este proyecto. En primer lugar, a los docentes cuya enseñanza inspira y motiva a los alumnos a aprender sobre su asignatura. Especialmente agradecer a Teresa, por haberme dado las pautas necesarias para llevar a cabo este proyecto y por guiarme en el proceso. En segundo lugar, a mis amigos y compañeros, que me han ayudado durante la etapa universitaria y que han hecho que esta experiencia sea inolvidable. También quiero agradecer a mi pareja, por prestarme siempre todo su apoyo y por aportarme ideas para el proyecto. En tercer lugar, a mi familia, que siempre me levantan los ánimos y me acompañan en todos los momentos de la vida, y sin los cuales no habría tenido la oportunidad de estudiar esta carrera. Me gustaría destacar el esfuerzo de mis padres, que se han desvivido por otorgar un futuro a mis hermanos y a mí. En último lugar, quiero dedicar este proyecto a unas personas muy importantes para mí, mis abuelos y mi madre. Me gustaría que pudieran estar aquí para presenciar este momento y volver a sentir su apoyo incondicional. Gracias a ellos, en especial a mi madre, me he convertido en la persona que soy y espero que se sientan muy orgullosos de mí. María de los Reyes Machuca Romero Sevilla, 2022
xvi A.2 Despliegue del proyecto con GitHub 119 Anexo B: Código de las funciones para enviar una lista 122 Anexo C: Código de las funciones para realizar un entrenamiento de una lista 126 Referencias 143
xvii ÍNDICE DE TABLAS Tabla 1. CU-01: Registrarse con nombre y correo electrónico 51 Tabla 2. CU-02: Crear un elemento nuevo 53 Tabla 3. CU-03: Modificar un elemento existente 55 Tabla 4. CU-04: Ver lista de elementos 56 Tabla 5. CU-05: Realizar entrenamiento de una lista 56 Tabla 6. CU-06: Enviar una lista por correo electrónico o Bluetooth 57
xviii
xix ÍNDICE DE FIGURAS Ilustración 1 - Evolución del ejercicio físico por año, edad, sexo y nivel educativo (2010-2020). Ministerio de Cultura y Deporte 23 Ilustración 2 - Porcentaje de población sedentaria en España (2020). INE 24 Ilustración 3 - Arquitectura de la aplicación 25 Ilustración 4 - Logo de JavaScript 27 Ilustración 5 - Definición de una función en JavaScript 28 Ilustración 6 - Función setTimeout 28 Ilustración 7 - Uso de la función setInterval de Entrenamiento.js 29 Ilustración 8 - Creación y uso del objeto Promise 29 Ilustración 9 - Función utilizando async/await 30 Ilustración 10 - Logo de React Native 30 Ilustración 11 - Gráfico de la evolución de React Native con respecto a Android e iOS (2016-2018) 31 Ilustración 12 - Componente Video de React Native 31 Ilustración 13 - Componentes de clase y de función 32 Ilustración 14 - Ejemplo de useEffect 33 Ilustración 15 - useNavigation y useFocusEffect en Lista.js 34 Ilustración 16 - Uso de AsyncStorage en AllLists.js 35 Ilustración 17 - Logo de Expo 35 Ilustración 18 - Expo Development Server 36 Ilustración 19 - Logo de JSON 37 Ilustración 20 - Conversión JSON a objeto JavaScript 37 Ilustración 21 - Lista de ejercicios en formato JSON 38 Ilustración 22 - Logo de Visual Studio Code 40 Ilustración 23 - Interfaz de usuario de Visual Studio Code 41 Ilustración 24 - Logo de Expo Go 41 Ilustración 25 - Funcionamiento de Expo Go 42 Ilustración 26 - Interfaz de usuario de Expo Go 43 Ilustración 27 - Logo de Git 43 Ilustración 28 - Logo de GitHub Desktop 44 Ilustración 29 - Interfaz gráfica de GitHub Desktop 44 Ilustración 30 - Logo de Vysor 45 Ilustración 31 - Interfaz de usuario de Vysor 45 Ilustración 32 - Logo de Diagrams.net 46
xx Ilustración 33 - Recursos y plantillas de Diagrams.net 46 Ilustración 34 - Página de Diagrams.net 47 Ilustración 35 - Logo de Visual Paradigm 47 Ilustración 36 - Interfaz de usuario de Visual Paradigm 48 Ilustración 37 - Logo de Pixabay 48 Ilustración 38 - Logo de Pexels 49 Ilustración 39 - Casos de uso para la autenticación de un usuario 51 Ilustración 40 - Diagrama de casos de uso para la creación de un elemento 52 Ilustración 41 - Diagrama de casos de uso para modificar un elemento 54 Ilustración 42 - Diagrama de casos de uso para realizar operaciones con una lista 55 Ilustración 43 - Diagrama de secuencia para el registro e inicio de sesión 58 Ilustración 44 - Diagrama de secuencia para crear una lista 59 Ilustración 45 - Diagrama de secuencia para realizar un entrenamiento 61 Ilustración 46 - Diagrama de secuencia para enviar una lista por correo electrónico 62 Ilustración 47 - Diagrama de secuencia para importar una lista 63 Ilustración 48 - Modelo de datos de la aplicación 64 Ilustración 49 - Pantalla de registro e inicio de sesión 66 Ilustración 50 - Ejemplo de nombre y correo electrónico del usuario 67 Ilustración 51 - Pantalla de modo de visualización 68 Ilustración 52 - Pantalla de lista de listas 69 Ilustración 53 - Menú de la pantalla de listas de listas 70 Ilustración 54 - Ejemplo de fondo de pantalla personalizado 71 Ilustración 55 - Opción eliminar listas 71 Ilustración 56 - Opción duplicar lista 72 Ilustración 57 - Ejemplo de duplicar lista 73 Ilustración 58 - Insertar una lista existente 74 Ilustración 59 - Ejemplo de alerta de Crear lista 75 Ilustración 60 - Pantalla de nueva lista local 76 Ilustración 61 - Alerta para seleccionar una imagen 77 Ilustración 62 - Imágenes del almacenamiento interno 78 Ilustración 63 - Ventana de iconos de la aplicación 78 Ilustración 64 - Ejemplo de añadir ejercicio con vídeo local 79 Ilustración 65 - Pantalla de nueva lista 80 Ilustración 66 - Pantalla de lista de ejercicios del modo Entrenamiento 81 Ilustración 67 - Editar título de una lista 82 Ilustración 68 - Menú de la lista de ejercicios modo Entrenamiento 83 Ilustración 69 - Ejemplo de marcar lista como realizada 83 Ilustración 70 - Ventana de añadir recordatorio 84 Ilustración 71 - Ejemplo de calendario para añadir recordatorio 85
xxi Ilustración 72 - Ejemplo de hora para añadir recordatorio 85 Ilustración 73 - Ejemplo de notificación de recordatorio de una lista 86 Ilustración 74 - Ejemplo de fondo personalizado para una lista 87 Ilustración 75 - Ejemplo de alerta para eliminar una lista 88 Ilustración 76 - Menú de opciones para enviar una lista 89 Ilustración 77 - Ejemplo de envío de una lista por Gmail 90 Ilustración 78 - Ejemplo de envío de una lista por Bluetooth 91 Ilustración 79 - Menú desplegable de un ejercicio 92 Ilustración 80 - Ventana para añadir un emoticono a un ejercicio 93 Ilustración 81 - Ejemplo de ejercicio realizado con emoticono 94 Ilustración 82 - Ejemplo de añadir foto a un ejercicio 95 Ilustración 83 - Ventana de añadir foto a un ejercicio 96 Ilustración 84 - Ejemplo de foto en un ejercicio 96 Ilustración 85 - Pantalla de entrenamiento de una lista 97 Ilustración 86 - Ejemplo de entrenamiento pulsando comenzar 98 Ilustración 87 - Ejemplo de historial de una lista 99 Ilustración 88 - Ejemplo de un historial de entrenamiento 100 Ilustración 89 - Ejemplo de historial vacío de una lista 101 Ilustración 90 - Ejemplo de pantalla lista en el modo Configuración 102 Ilustración 91 - Ejemplo de añadir un ejercicio local 103 Ilustración 92 - Ejemplo de añadir un ejercicio de YouTube 103 Ilustración 93 - Ejemplo de eliminar un ejercicio de la lista 104 Ilustración 94 - Ventana para modificar el correo electrónico de la lista 105 Ilustración 95 - Alerta para salir de la aplicación 106 Ilustración 96 - Modificación del archivo app.json para generar el .APK 108 Ilustración 97 - Comando para generar el .APK 108 Ilustración 98 - Instalación de la aplicación en un dispositivo Android 109 Ilustración 99 - Actualización de Expo SDK para compatibilidad con Expo Go 109 Ilustración 100 - Inicio del servidor de desarrollo de Expo y generación de código QR para Expo Go 110 Ilustración 101 - Pantalla de iniciar sesión en iOS 111 Ilustración 102 - Pantalla de lista de listas en iOS 111 Ilustración 103 - Creación de una lista nueva en iOS 111 Ilustración 104 - Pantalla Entrenamiento en iOS 111 Ilustración 105 - Ejemplo de seleccionar fecha para un recordatorio en iOS 112 Ilustración 106 - Pantalla Lista con notificación en iOS 112 Ilustración 107 - Descargar instalador de Node.js para Windows 115 Ilustración 108 - Ejecutar instalador de Node.js 116 Ilustración 109 - Comprobar versión de Node.js y npm 116 Ilustración 110 - Descargar archivo de instalación de Visual Studio Code para Windows 117
xxii Ilustración 111 - Instalar Visual Studio Code 117 Ilustración 112 - Comprobar versión de Visual Studio Code 118 Ilustración 113 - Instalación de Expo CLI 118 Ilustración 114 - Creación de un proyecto React Native en JavaScript utilizando Expo CLI 118 Ilustración 115 - Inicialización de la aplicación con npm 119 Ilustración 116 - Página de descarga de GitHub Desktop 119 Ilustración 117 - Acceder a una cuenta de GitHub con GitHub Desktop 120 Ilustración 118 - Clonar repositorio con GitHub Desktop 121
23 1 INTRODUCCIÓN El frenético ritmo de vida junto con el avance en las tecnologías ha provocado un aumento en el uso de los teléfonos inteligentes para realizar todo tipo de actividades. Desde hace unos años, se ha podido observar un cambio en la forma de relacionarnos, de trabajar y de gestionar distintos aspectos de nuestra vida gracias a la llegada de estos dispositivos y a la creación de aplicaciones móviles. Además, muchas de estas aplicaciones o apps se pueden utilizar también en otras plataformas, como televisores “Smart tv” con conexión a internet o tabletas, con el fin de abarcar varios tipos de ámbitos y usuarios. Esto es posible gracias a entornos que permiten desarrollar aplicaciones multiplataforma para distintos sistemas operativos. 1.1 Motivación La actividad física ha ido incrementando en la última década según la encuesta de hábitos deportivos en España [1] realizada por el Ministerio de Cultura y Deporte. En la Ilustración 1 se muestra la evolución del ejercicio físico practicado semanalmente por hombres y mujeres a partir de los 15 años. Ilustración 1 – Evolución del ejercicio físico por año, edad, sexo y nivel educativo (2010-2020). Ministerio de Cultura y Deporte Se puede observar un aumento considerable en la práctica deportiva en el último año. Sin embargo, según la Encuesta Europea de Salud en España del Instituto Nacional de Estadística [2], sigue habiendo un
Introducción 24 24 elevado porcentaje de sedentarismo en la población. En la Ilustración 2 se puede apreciar que el nivel de sedentarismo es similar en hombres y mujeres. Ilustración 2 – Porcentaje de población sedentaria en España (2020). INE Al comparar la Ilustración 1 y 2 se puede concluir que, aunque más de la mitad de la población realiza deporte cada semana, hay un notable grado de sedentarismo que, en parte, se debe al periodo de pandemia de Covid-19, en el cual aumentó la inactividad física debido al cese de actividades deportivas en el exterior. Otra de las razones por las que hay una importante falta de ejercicio es la escasez de tiempo y el desconocimiento a la hora de realizarlo. La mayoría de los deportes que se practican necesitan de unas pautas y, con el ritmo de vida que hay actualmente, es difícil dedicarles tiempo. Se plantea una idea en este contexto con el objetivo de aumentar y promover el hábito de ejercicio físico, bajo la supervisión de un especialista en actividad física. El usuario podrá realizar ejercicio desde casa teniendo en cuenta sus indicaciones y llevar un seguimiento que le garantice unos resultados óptimos sin invertir más tiempo del necesario. También podrá crear sus propios entrenamientos y marcar sus propios tiempos. 1.2 Objetivos Durante el desarrollo del proyecto, los objetivos iniciales se han ido variando y modificando, ya que algunos resultaron no ser muy convenientes o eran inalcanzables. Los objetivos se basan principalmente en explorar las tecnologías y funcionalidades que ofrece React Native para desarrollar una aplicación móvil que funcione de forma local, sin servidor, y son los siguientes: • Generar un código único en el lenguaje JavaScript que permita usar la aplicación en Android y en iOS. • Comunicación entre Usuario y Especialista mediante correo electrónico y Bluetooth. • Almacenar los datos del usuario en una base de datos local. • Reproducción de listas de entrenamiento con vídeos de YouTube y vídeos del almacenamiento local.
25 25 Aplicación móvil para la gestión de listas de ejercicios de entrenamiento en React Native 1.3 Descripción de la solución En vista de lo anterior, se propone una aplicación móvil para realizar listas de entrenamientos para la prescripción de ejercicio físico, orientada a usuarios y especialistas. Esta aplicación, denominada My GymList, tiene como función principal proporcionar un servicio personalizado para cada usuario que maximice su nivel de actividad física. Para ello, se realizará un seguimiento periódico de su rendimiento y así lograr sus objetivos físicos y, en consecuencia, un estilo de vida más saludable. En la Ilustración 3 se muestra la arquitectura de la aplicación: Ilustración 3 – Arquitectura de la aplicación En la arquitectura se puede observar que la funcionalidad y la comunicación entre los usuarios se realiza sin
Tecnologías utilizadas 32 32 componentDidUpdate() y componentWillUnmount(). Estos se utilizan para mantener o actualizar un estado. El estado es un objeto que contiene un par clave-valor, determina cómo se comportan los componentes y permite que estos sean dinámicos e interactivos. En cambio, los componentes funcionales están formados por una función que obtiene las propiedades y devuelve un JSX. No tienen métodos para manejar el ciclo de vida. Existen dos tipos de componentes funcionales: componentes “Stateless” o sin estado y “Hooks”. Los Hooks son los únicos que pueden tener un estado. Hay una clara diferencia entre ambos componentes [4] que se muestra en la Ilustración 13 a continuación: Ilustración 13 – Componentes de clase y de función En este ejemplo se implementa un contador que se incrementa en una unidad cada vez que se pulsa un botón. En el componente de clase de la derecha se utilizan los métodos mencionados anteriormente para manejar su ciclo de vida y actualizar el estado del contador. Con el método handleIncrement() se incrementa el contador. Sin embargo, en el componente funcional de la izquierda se utiliza el Hook de estado useState para crear la variable count que guarda el estado del contador con setCount. Se puede observar que es una manera más sencilla, efectiva y rápida de implementar funcionalidades. Por esta razón se han utilizado componentes funcionales (Hooks) para desarrollar la app. 2.2.3 Hooks Los Hooks [12] que se han utilizado en este proyecto son: useState, useEffect, useRef, useCallback, useNavigation y useFocusEffect. 2.2.3.1 Descripción general de los Hooks useEffect realiza la misma función que componentDidMount(), componentDidUpdate() y componentWillUnmount(), pero unificado en una sola API. React ejecuta esta función después de cada renderizado. Si en el ejemplo de la Ilustración 14 se añade este Hook en el componente funcional [5], se le está indicando a React que debe ejecutar useEffect después de pulsar el botón. El resultado sería como
33 33 Aplicación móvil para la gestión de listas de ejercicios de entrenamiento en React Native el de la Ilustración 14 a continuación: Ilustración 14 – ejemplo de useEffect useRef hace una referencia al DOM directamente en el componente funcional. Devuelve un objeto de tipo referencia que tiene una propiedad llamada “current” que contiene un valor mutable. Este valor persiste entre renderizados y, si es actualizado, no causa un nuevo renderizado. Se puede utilizar para guardar la referencia de un componente “Video”. useCallback devuelve una versión memorizada de una llamada o “callback” que cambia solo cuando una de sus dependencias ha cambiado. De esta forma solo se ejecuta cuando sea necesario, permitiendo un mayor rendimiento de la app. useNavigation [13] y useFocusEffect [14] pertenecen a una librería llamada React Navigation que permite implementar funcionalidades para la navegación entre pantallas de la app. useNavigation concede acceso a un objeto de tipo navegación o “navigation” y devuelve la propiedad “navigation” de la pantalla. useFocusEffect permite que se realicen tareas cuando una pantalla está enfocada o “focused”. Su efecto es igual al de useEffect pero solo funciona cuando la pantalla está enfocada. En la Ilustración 15 se muestra una forma de usar estos Hooks en Lista.js:
Tecnologías utilizadas 34 34 Ilustración 15 – useNavigation y useFocusEffect en Lista.js Dentro de useCallback se ha llamado a la función getLista, que obtiene la lista de ejercicios seleccionada. También se ha añadido un “listener” que, cuando se pulsa el botón de atrás del dispositivo, realice las tareas indicadas en el método backAction. Cuando se sale de esta pantalla, se ejecutan las sentencias dentro de “return”. En este caso, se elimina el “listener” y se indica que el componente está desmontado. Esto impide que haya pérdidas de memoria en la app. 2.2.4 AsyncStorage AsyncStorage [15] es un sistema de almacenamiento de pares clave-valor asíncrono y persistente. Permite guardar datos en la aplicación de forma local y, en función del sistema operativo, almacena la información de un modo concreto. En iOS, AsyncStorage está soportado por código nativo que guarda valores ligeros en un diccionario serializado y valores más pesados en ficheros. En cambio, AsyncStorage utiliza SQLite para almacenar datos en Android. 2.2.4.1 Métodos de AsyncStorage Esta librería de React Native proporciona métodos que devuelven un objeto “Promise” o Promesa, mencionado anteriormente en el apartado 2.1.3. Los métodos que se han utilizado en este proyecto son: getItem y setItem. getItem busca un elemento utilizando su clave en formato “string” o cadena, y devuelve un objeto Promesa. Si se ha podido encontrar el elemento, lo devuelve como “result” o resultado. Sin embargo, si no ha encontrado el elemento devuelve un error. setItem establece el valor junto con su clave y devuelve un objeto Promesa. Si no se ha podido realizar la operación devuelve un error. Se puede observar un ejemplo obtenido del archivo AllLists.js en la Ilustración 16 a continuación:
35 35 Aplicación móvil para la gestión de listas de ejercicios de entrenamiento en React Native Ilustración 16 – Uso de AsyncStorage en AllLists.js Se ha añadido un botón que, una vez pulsado, ejecuta una función asíncrona (se indica con la palabra “async” al principio). Esta función obtiene “LISTAS” de AsyncStorage, que contiene todas las listas de la app, y elimina las que tengan una fecha de creación anterior a los meses indicados en la variable listValueNumber. Para obtener las listas se invoca al método getItem con la palabra “await”, que devuelve un objeto Promesa (el resultado si la Promesa se ha resuelto) que se guarda en una variable llamada valorListas. Seguidamente, se filtran las listas devueltas por AsyncStorage (con el método filter) cuya fecha de creación sea mayor o igual a la fecha indicada por listValueNumber. Finalmente, se utiliza el método setItem para guardar el resultado en AsyncStorage y se actualizan las listas con la variable de estado setListas en getItem. 2.3 Expo Ilustración 17 – Logo de Expo 2.3.1 Descripción y características generales Expo [16] es un framework de código abierto que se usa para crear aplicaciones en React Native. Es un conjunto de herramientas y servicios que facilitan el desarrollo de React Native debido a que no se necesita conocer lenguaje nativo para ello. Además, contiene APIs nativas para iOS y para Android, entre las cuales se encuentran “FileSystem”, “Camera” y “Video”. Estas APIs están disponibles en el Expo SDK [17], que proporciona acceso a las funcionalidades del dispositivo, como la cámara, la localización o los contactos en forma de paquetes. 2.3.2 Instalación y ejecución del entorno Para instalar Expo se necesita Node.js [18], que es un entorno de servidor de código abierto que utiliza JavaScript y programación asíncrona. Esto se debe a que la gestión de herramientas y dependencias de la línea de comandos de Expo depende de Node.js. La interfaz de línea de comandos de Expo se denomina Expo CLI, que se utiliza para realizar pruebas en la app mientras está siendo desarrollada.
Tecnologías utilizadas 36 36 Para probar la funcionalidad de la aplicación móvil se necesita la aplicación de cliente de Expo para iPhone y Android, que se puede descargar de App Store y de Play Store respectivamente. Cuando se inicia la aplicación con el comando “expo start” en Expo CLI, un empaquetador de JavaScript llamado Metro [19] se inicializa a la vez. Su función es combinar el código JavaScript en un único fichero y traducir código JavaScript y JSX [20]. También convierte recursos o “assets”, que son imágenes principalmente, en objetos que se pueden visualizar en un componente de tipo imagen o “Image”. Además, con este comando se inicializa también el servidor de Expo llamado Expo Development Server. Su función es obtener el código JavaScript generado por Metro y ejecutarlo en la aplicación de cliente de Expo en el dispositivo o emulador. En la Ilustración 18 se muestra el Expo Development Server al abrir la página localhost:19002, donde se puede escanear el código QR desde la aplicación móvil de Expo o ejecutar la app desde un emulador. Ilustración 18 – Expo Development Server 2.3.3 Flujos de trabajo La forma de desarrollo en Expo mencionada anteriormente se corresponde con uno de los dos flujos de trabajo [21] que existen, denominado “managed”. En este flujo se escribe solo en JavaScript o TypeScript y las herramientas de Expo se encargan de realizar las tareas principales. El otro flujo se denomina “bare”, donde se puede usar cualquier servicio o librería de Expo. Es el usuario quien debe desarrollar los proyectos nativos en Android, utilizando Android Studio, y en iOS, utilizando Xcode. Los desarrolladores que utilizan el flujo “managed” no tienen esa responsabilidad y la complejidad es gestionada por Expo. En el caso de que se encuentren limitaciones y se deba acceder a código nativo, siempre se puede cambiar de “managed” a “bare” y seguir desarrollando el código en ese flujo. En este proyecto se ha utilizado el flujo de trabajo “managed”, donde se configura el icono de la app y la pantalla de carga en un archivo llamado “app.json”, y la configuración de Metro se indica en el archivo “metro.config.js”. Los paquetes de Expo que se han utilizado se indican en el archivo “package.json”, y entre ellos se encuentran: Camera, Video, Document Picker, Image Picker, FileSystem, MediaLibrary, Notifications y Sharing.
37 37 Aplicación móvil para la gestión de listas de ejercicios de entrenamiento en React Native 2.4 JSON Ilustración 19 – Logo de JSON 2.4.1 Descripción y características generales JSON [22] es la forma abreviada de JavaScript Object Notation. Es un formato ligero usado para almacenar y transmitir datos. Es autodescriptivo y fácil de entender. Los datos están separados por comas y se guardan en pares nombre-valor. Los objetos se guardan entre llaves “{ }” y las matrices entre corchetes “[ ]”. Cada objeto puede contener varios pares nombre-valor y cada matriz puede contener varios objetos. Un programa JavaScript puede convertir datos JSON en objetos JavaScript nativos. El formato JSON es solo texto, y se debe diferenciar de la sintaxis JSON, que deriva de la sintaxis de notación de objetos de JavaScript. En la Ilustración 20 se presenta un ejemplo donde se ha creado una cadena JavaScript que contiene sintaxis de JSON, y se utiliza la función “JSON.parse()” para convertirla a un objeto JavaScript: Ilustración 20 – Conversión JSON a objeto JavaScript 2.4.2 Uso en la aplicación En este proyecto se han creado listas de ejercicios en formato JSON, como se puede observar en la Ilustración 21:
Tecnologías utilizadas 38 38 Ilustración 21 – Lista de ejercicios en formato JSON En la lista se pueden identificar los siguientes campos: ▪ imagen: contiene un número que corresponde a un icono que se encuentra en la carpeta “assets” del proyecto, o la uri de una imagen seleccionada del almacenamiento interno del dispositivo. ▪ titulo: contiene el título de la lista “Lista de ejercicios”. ▪ videolista: en este campo se almacenan los enlaces de vídeos de los ejercicios que conforman la lista y todas sus características en una matriz. Algunas de las características o campos de los vídeos son: series, repeticiones, tiempo, videos e id. El campo “videos” puede ser parte de un enlace de un vídeo de Youtube o una uri de un vídeo local. ▪ email: guarda la dirección de correo electrónico del usuario. Esta dirección se almacena de forma local la primera vez que el usuario ingresa en la app. ▪ idlista: es el identificador de la lista. ▪ fechacreacion: indica la fecha en la que se ha creado la lista. ▪ listaRealizado: en este campo se indica si la lista se ha realizado. ▪ imagenListaRealizado: contiene un icono que aparece para indicar si la lista se ha realizado o si está pendiente por realizarse. ▪ historial: en este campo se almacena un historial en una matriz, y cada elemento guarda un intento de entrenamiento de esa lista de ejercicios. Es decir, cada vez que se realiza la lista se guarda una entrada en esa matriz. Los campos de cada entrenamiento son: idHistorial,
39 39 Aplicación móvil para la gestión de listas de ejercicios de entrenamiento en React Native fechaRealizado, tiempoTotal y tiemposEjercicios. En este último se almacena una matriz donde cada entrada corresponde a uno de los vídeos de la lista. Para cada vídeo hay un campo llamado tiempoRealizacion, donde se guarda el tiempo que ha tardado en realizarse el ejercicio, y uno llamado tiempoDescanso, donde se guarda el tiempo de descanso del ejercicio. ▪ fondo: por último, en este campo se almacena la uri de la imagen seleccionada para el fondo de la lista. Todos los campos tienen el formato de una cadena o “string” excepto “imagen”, “imagenRealizado” e “imagenListaRealizado”, ya que pueden ser números que correspondan a una imagen de la carpeta “assets” del proyecto.
40 3 HERRAMIENTAS UTILIZADAS 3.1 Herramientas de desarrollo En este capítulo se especificarán las herramientas empleadas durante el desarrollo del proyecto. 3.1.1 Visual Studio Code Ilustración 22 – Logo de Visual Studio Code Visual Studio Code o VS Code [23] de forma abreviada es un editor de código fuente que es gratuito y de código abierto. Contiene una herramienta llamada IntelliSense que completa el código de forma automática para variables, métodos y módulos importados. Además, incluye un depurador interactivo que permite procesar el código en búsqueda de errores, inspeccionar variables y ejecutar comandos en la consola. Ofrece unas características que facilitan el desarrollo del código, como el subrayado de la sintaxis, correspondencia instantánea de llaves y corchetes, e indentación automática. Integra control de código fuente con Git. Está creado por Microsoft y está disponible para varios sistemas operativos. Contiene soporte para JavaScript, TypeScript y Node.js, y tiene un conjunto de extensiones para otros lenguajes de programación. Está desarrollado con Electron, un marco de trabajo que permite escribir aplicaciones multiplataforma utilizando JavaScript, HTML y CSS. La interfaz de usuario de VS Code [24] se muestra en la Ilustración 23:
41 41 Aplicación móvil para la gestión de listas de ejercicios de entrenamiento en React Native Ilustración 23 – Interfaz de usuario de Visual Studio Code Se puede dividir en 5 áreas: el editor, la barra que se sitúa abajo a la izquierda, la barra de estado, la barra de actividad y los paneles. El editor es el área principal donde se muestra el contenido de los ficheros y donde se pueden editar. Se pueden abrir varios editores a la vez de forma vertical u horizontal. La barra situada abajo a la izquierda contiene un botón que indica el número de fallos que tiene el proyecto y un botón para subir los cambios a GitHub. La barra de estado es la barra inferior de color azul, que contiene información sobre el proyecto y los ficheros. La barra de actividad está localizada a la izquierda del explorador de archivos y ficheros del proyecto. Entre estos archivos se pueden destacar App.js, app.json y metro.config.js mencionados en el capítulo 2. Permite cambiar entre diferentes vistas y proporciona indicadores como el número de cambios pendientes por subir a GitHub. Finalmente, los paneles se encuentran en la región situada debajo del editor y se usan para la depuración, informar sobre errores y escribir en el terminal. Cada vez que se inicia VS Code, se abre en el mismo proyecto y estado en el que se encontraba antes de cerrarlo por última vez. Se conservan los ficheros y las carpetas. 3.1.2 Expo Go Ilustración 24 – Logo de Expo Go Expo Go [25] es una aplicación de código abierto que se utiliza para ejecutar aplicaciones de React
Herramientas utilizadas 48 48 Ilustración 36 – Interfaz de usuario de Visual Paradigm El modelado de datos y los diagramas de secuencia han sido creados con esta tecnología. 3.4 Recursos adicionales 3.4.1 Pixabay Ilustración 37 – Logo de Pixabay Pixabay [31] es una comunidad donde se comparten imágenes, vídeos y música que están bajo la licencia de Pixabay, por lo que se pueden utilizar sin tener que referenciarlas, incluso para fines comerciales. Cualquier usuario registrado en la página puede subir imágenes a Pixabay (bajo unas normas de calidad), y no es necesario registrarse para poder copiar, modificar, usar y distribuir el contenido. Esto se puede hacer mientras que no se vulneren los derechos de privacidad. En este proyecto se han empleado imágenes de esta página para los iconos de la aplicación, entre los cuales se encuentran: eliminar un vídeo, importar una lista, crear una nueva lista y añadir emoticonos en los vídeos. Las imágenes se guardan en la carpeta “assets” del proyecto, y se obtiene la URL de cada una de ellas en un fichero llamado Images.js con la sentencia “require( )”.
49 49 Aplicación móvil para la gestión de listas de ejercicios de entrenamiento en React Native 3.4.2 Pexels Ilustración 38 – Logo de Pexels Pexels [32] es una página web y app donde se alojan fotos y vídeos sin derechos de autor. Proporciona recursos a los usuarios y diseñadores que se pueden utilizar de forma gratuita. Las condiciones de uso son muy similares a las de Pixabay, y se pueden encontrar una gran variedad de imágenes en ambas páginas. Se han utilizado imágenes de Pexels para el fondo de pantalla por defecto de la aplicación.
50 4 ARQUITECTURA Y ANÁLISIS En este capítulo se analizará la arquitectura de la aplicación y se crearán diagramas UML que especifiquen su funcionamiento. 4.1 Casos de uso generales A continuación, se van a describir los casos de uso y se mostrarán los diagramas correspondientes junto con los actores implicados. Esto servirá para explicar las relaciones entre el sistema y los actores y, además, para mostrar el funcionamiento de la aplicación desde la perspectiva del usuario final. 4.1.1 Identidad de los actores El actor que va a interactuar con el sistema y acceder a sus funciones es el usuario. Si no se ha autenticado se denominará Usuario no autenticado. En cambio, si se ha autenticado se denominará Usuario. El usuario puede tener el rol de Usuario o Especialista indistintamente. 4.1.2 Autenticación de un usuario Para la autenticación de un usuario se determinarán los procesos para su registro en la aplicación. Se detallarán los procesos tanto en la Ilustración 39 como en las tablas a continuación: La función de un buen software es hacer que lo complejo aparente ser simple. - Grady Booch -
51 51 Aplicación móvil para la gestión de listas de ejercicios de entrenamiento en React Native Ilustración 39 – Casos de uso para la autenticación de un usuario CU-01 Registrarse con nombre y correo electrónico Precondición El usuario no debe haberse registrado previamente en la aplicación Descripción En este caso de uso se describe el comportamiento de la aplicación para registrar un usuario por primera vez. Secuencia normal Paso Acción 1 El usuario introduce su nombre y correo electrónico 2 El usuario pulsa el botón de iniciar sesión Postcondición El usuario inicia sesión y se encuentra autenticado en la aplicación Excepciones Paso Acción 1 El usuario introduce un correo electrónico inválido E.1 La aplicación advierte al usuario del error y le solicita modificar e introducir los datos de nuevo Comentarios Ninguno Tabla 1. CU-01: Registrarse con nombre y correo electrónico
Arquitectura y análisis 52 52 4.1.3 Operaciones para crear un elemento El usuario podrá realizar operaciones para crear un elemento en la aplicación, que se detallarán en las tablas correspondientes y en el diagrama de casos de uso de la Ilustración 40: Ilustración 40 – Diagrama de casos de uso para la creación de un elemento CU-02 Crear un elemento nuevo (un ejercicio, una lista, un recordatorio para una lista, duplicar una lista, o añadir un ejercicio a una lista, un emoticono o una foto a un ejercicio) Precondición El usuario debe estar autenticado Descripción En este caso de uso se describe el comportamiento de la aplicación para crear un nuevo elemento. Secuencia normal Paso Acción 1 El usuario pulsa el botón de crear una lista 2 El usuario pulsa el botón de añadir un ejercicio e introduce los datos solicitados
53 53 Aplicación móvil para la gestión de listas de ejercicios de entrenamiento en React Native 3 El usuario pulsa el botón de guardar lista 4 El usuario selecciona una lista 5 El usuario pulsa el botón de duplicar la lista 6 El usuario pulsa el botón de añadir un recordatorio para la lista 7 El usuario pulsa el botón de añadir un ejercicio a la lista y rellena los datos solicitados 8 El usuario selecciona la opción de añadir un emoticono a un ejercicio de la lista 9 El usuario selecciona la opción de añadir una foto a un ejercicio 10 El usuario pulsa el botón de hacer una foto 11 El usuario pulsa el botón de guardar foto Postcondición El usuario ha creado un nuevo elemento correctamente. Excepciones Paso Acción 1 El usuario introduce un enlace de un vídeo inválido (si se ha seleccionado previamente la opción de crear lista de ejercicios de YouTube) E.1 La aplicación advierte al usuario del error y le solicita modificar e introducir los datos nuevamente Comentarios Si el usuario pulsa el botón de cancelar, no se crea el elemento y no se produce error. Todos los casos de uso en los que se crean nuevos elementos son muy similares, por lo que se han agrupado en esta tabla. Tabla 2. CU-02: Crear un elemento nuevo 4.1.4 Operaciones para modificar un elemento En la Ilustración 41 se mostrarán las operaciones que podrá llevar a cabo un usuario para modificar un elemento existente en la aplicación. Asimismo, en las tablas de este apartado se explicarán los casos de uso del diagrama con mayor detalle.
Arquitectura y análisis 54 54 Ilustración 41 – Diagrama de casos de uso para modificar un elemento CU-03 Modificar un elemento existente (título de lista, eliminar un ejercicio, eliminar una lista, marcar una lista como realizada, actualizar una lista) Precondición El usuario debe estar autenticado Descripción En este caso de uso se describe el comportamiento de la aplicación para modificar un elemento que existe. Secuencia normal Paso Acción 1 El usuario pulsa el botón de editar título de una lista y pulsa el botón de aceptar 2 El usuario pulsa el botón de eliminar ejercicio 3 El usuario pulsa el botón de eliminar una lista 4 El usuario selecciona la opción de marcar una lista como realizada 5 El usuario pulsa el botón de importar una lista y, si la lista ya existe, puede actualizarla (se realiza el caso de uso “Actualizar una lista”) Postcondición El usuario ha modificado un elemento correctamente. Excepciones Ninguna
55 55 Aplicación móvil para la gestión de listas de ejercicios de entrenamiento en React Native Comentarios Si el usuario pulsa el botón de cancelar, no se modifica el elemento y no se produce error. Debido a que todos los casos de uso en los que se modifican elementos son muy similares, se han agrupado en esta tabla. Tabla 3. CU-03: Modificar un elemento existente 4.1.5 Operaciones con una lista Se detallarán las operaciones que se pueden efectuar con una lista de la aplicación en la Ilustración 42. En las tablas que aparecerán en este apartado se definirán los casos de uso del diagrama. Ilustración 42 – Diagrama de casos de uso para realizar operaciones con una lista CU-04 Ver lista de elementos (de ejercicios, de listas, historial de una lista, detalles de historial de entrenamiento) Precondición El usuario debe estar autenticado Descripción En este caso de uso se describe el comportamiento de la aplicación para mostrar una lista de elementos (ejercicios, listas, historial de una lista o detalles de un historial de entrenamiento). Secuencia Paso Acción
Arquitectura y análisis 56 56 normal 1 El usuario selecciona una lista que existe en la aplicación Postcondición El usuario visualiza la lista de elementos e interactúa con ella Excepciones Ninguna Comentarios Si se selecciona el historial de una lista y este está vacío no se devuelve una lista, ni aparece ningún error, sino que se muestra el mensaje: “El historial está vacío”. Se han agrupado en esta tabla todos los casos de uso en los que se visualizan listas porque son muy similares entre sí. Tabla 4. CU-04: Ver lista de elementos CU-05 Realizar entrenamiento de una lista Precondición El usuario debe estar autenticado Descripción En este caso de uso se describe el comportamiento de la aplicación para reproducir una lista de ejercicios. Secuencia normal Paso Acción 1 El usuario pulsa el botón de iniciar entrenamiento 2 El usuario pulsa el botón de comenzar ejercicio 3 El usuario reproduce el vídeo del ejercicio 4 El usuario pulsa el botón de siguiente 5 El usuario pulsa el botón de guardar (se realiza el caso de uso “Guardar historial de entrenamiento de la lista”) Postcondición El usuario visualiza los vídeos de los ejercicios y guarda el historial de entrenamiento. Excepciones Ninguna Comentarios Si el usuario pulsa el botón de cancelar, no se guarda el historial de entrenamiento de la lista y no se produce error. Tabla 5. CU-05: Realizar entrenamiento de una lista
57 57 Aplicación móvil para la gestión de listas de ejercicios de entrenamiento en React Native CU-06 Enviar una lista por correo electrónico o Bluetooth Precondición El usuario debe estar autenticado Descripción En este caso de uso se describe el comportamiento de la aplicación para enviar una lista Secuencia normal Paso Acción 1 El usuario selecciona una lista 2 El usuario pulsa el botón de enviar lista 3 El usuario selecciona la opción de enviar por correo electrónico o Bluetooth Postcondición El usuario ha enviado una lista correctamente. Excepciones Ninguna Comentarios Si el usuario pulsa el botón de atrás del dispositivo, no se envía la lista y no se produce error. Tabla 6. CU-06: Enviar una lista por correo electrónico o Bluetooth 4.2 Diagramas de secuencia En este apartado se representarán las interacciones más relevantes que se llevan a cabo entre los elementos de la aplicación mediante diagramas de secuencia. En ellos se detallarán los componentes que intervienen en las acciones realizadas. 4.2.1 Registro e inicio de sesión Primero, se analizará el proceso de registro e inicio de sesión de un usuario en la aplicación. Cuando el usuario accede a la app y se inicia, este debe introducir su nombre y correo electrónico y presionar el botón de “Login”. Una vez pulsado, la base de datos local guarda los datos del usuario. A partir de ahora, cada vez que el usuario abra la aplicación tendrá la sesión iniciada, es decir, estará autenticado, y no tendrá que volver a rellenar sus datos. Los elementos que aparecen en la Ilustración 43 son los siguientes: • Usuario: es el usuario de la aplicación, que se va a registrar e iniciar sesión • App: es el componente principal en el que se basa la aplicación, desde el cual se va a llamar al resto de componentes que intervienen. • LogIn: es el componente que muestra la pantalla en la que el usuario va a registrarse por primera vez. • Base Datos Local: es donde se almacenan los datos de la aplicación, y es SQLite en Android y un fichero local en iOS.
Arquitectura y análisis 64 64 Ilustración 48 – Modelo de datos de la aplicación Para mayor claridad, se han incluido los métodos más importantes de los componentes, sin los parámetros asociados. Se puede observar que el componente Lista contiene una mayor cantidad de métodos que el resto. Esto es debido a que hay un mayor número de operaciones a realizar con una lista, que han sido mencionadas en el apartado 4.1 en este capítulo.
65 65 Aplicación móvil para la gestión de listas de ejercicios de entrenamiento en React Native
66 5 INTERFAZ DE USUARIO Y FUNCIONALIDAD En este capítulo se detallará la interfaz de usuario de la aplicación. Se mostrará la distribución de sus elementos y sus funcionalidades, y se definirá el tipo de interacciones que se puede realizar con cada uno de los componentes. 5.1 Pantalla de registro e inicio de sesión Ilustración 49 – Pantalla de registro e inicio de sesión En la Ilustración 49 se puede observar la pantalla inicial, que se muestra cuando el usuario no está autenticado. Dispone de un título que se denomina “Login”, el logo de la aplicación situado debajo de este, y un formulario que contiene dos campos: nombre y correo electrónico. Estos campos sonobligatorios por lo que, si no se rellenan, saltará una alerta informando al usuario de que debe El diseño accesible es un buen diseño. - Steve Ballmer -
67 67 Aplicación móvil para la gestión de listas de ejercicios de entrenamiento en React Native rellenarlos. En el caso de que se introduzca una dirección de correo electrónico errónea, aparecerá una alerta indicando el error. Un ejemplo de nombre y correo electrónico de un usuario se indica en la Ilustración 50 a continuación: Ilustración 50 – Ejemplo de nombre y correo electrónico del usuario El correo electrónico que ha introducido el usuario será añadido por defecto en las listas de ejercicios creadas y, por tanto, no tendrá que volver a introducirlo cada vez que cree una lista. Cuando el usuario envíe una lista, el destinatario del mensaje podrá ver el correo electrónico del usuario que la ha creado y, por tanto, saber a quién pertenece la lista.
Interfaz de usuario y funcionalidad 68 68 5.2 Pantalla de modo de visualización Ilustración 51 – Pantalla de modo de visualización En la pantalla de la Ilustración 51 aparecen dos botones: “Entrenamiento” y “Configuración”. Al pulsar cualquiera de los dos botones, se mostrará la pantalla donde se visualizan las listas. Sin embargo, al seleccionar una de las listas, se podrán realizar acciones diferentes en función del modo de visualización escogido.
69 69 Aplicación móvil para la gestión de listas de ejercicios de entrenamiento en React Native 5.3 Pantalla de lista de listas Ilustración 52 – Pantalla de lista de listas En la Ilustración 52 se puede observar la lista que recoge todas las listas de ejercicios de la aplicación. Las funcionalidades que ofrece son las que se especifican a continuación:
Interfaz de usuario y funcionalidad 70 70 5.3.1 Añadir fondo de lista de listas Ilustración 53 – Menú de la pantalla de listas de listas Para añadir un fondo de pantalla, el usuario debe pulsar en el menú de la esquina superior derecha de la Ilustración 53, donde aparecen dos opciones: “Añadir fondo de pantalla” y “Eliminar listas”. Una vez seleccionada la opción de añadir un fondo, se mostrarán las imágenes del almacenamiento interno del dispositivo. Tras escoger una de ellas, se colocará la imagen en el fondo de la pantalla tal y como aparece en la Ilustración 54:
71 71 Aplicación móvil para la gestión de listas de ejercicios de entrenamiento en React Native Ilustración 54 – Ejemplo de fondo de pantalla personalizado 5.3.2 Eliminar listas Ilustración 55 – Opción eliminar listas
Interfaz de usuario y funcionalidad 72 72 Si el usuario escoge la opción de eliminar listas, aparecerá un componente de tipo “Modal” [37] mostrado en la Ilustración 55, que permite que se visualice contenido encima de una vista. En este componente se muestra un botón con una lista de números, donde el usuario puede escoger el número de meses deseado. Al pulsar el botón “Guardar”, se eliminan las listas que se han creado en una fecha anterior al número de meses escogido. 5.3.3 Duplicar una lista Ilustración 56 - Opción duplicar lista En el menú situado a la derecha de cada lista de ejercicios aparece una opción llamada “Duplicar lista”, que se puede observar en la Ilustración 56. Si el usuario escoge esta opción aparece una lista idéntica a la anterior, solo que con id y título diferentes, tal y como se aprecia en la Ilustración 57:
73 73 Aplicación móvil para la gestión de listas de ejercicios de entrenamiento en React Native Ilustración 57 – Ejemplo de duplicar lista 5.3.4 Insertar una lista Cuando un usuario quiere insertar una lista en la aplicación, debe pulsar en el botón “Importar lista” que se sitúa en la esquina inferior izquierda de la pantalla. Tras pulsarlo, aparecerán los ficheros del almacenamiento interno y escogerá la lista que desea insertar. Una vez elegida la lista con formato .TXT, se añadirá a la lista de listas. En el caso de que se quiera importar una lista que ya exista en la aplicación, aparecerá una alerta en la pantalla tal y como se muestra en la Ilustración 58:
Interfaz de usuario y funcionalidad 80 80 5.4.2 Pantalla de nueva lista Ilustración 65 – Pantalla de nueva lista En la Ilustración 65 se muestra la pantalla para crear una lista nueva con ejercicios de YouTube. El procedimiento es el mismo que para crear una lista con ejercicios en local excepto que, en este caso, hay un botón para acceder a la aplicación de YouTube, y así obtener un enlace a un vídeo que se insertará en el formulario. 5.5 Pantalla de lista de ejercicios modo Entrenamiento Al seleccionar una lista, se pueden abrir dos tipos de pantallas diferentes: la pantalla de “Lista” si se ha escogido el modo “Entrenamiento”, y la pantalla de “Lista Configuración” si se ha escogido el modo “Configuración”.
81 81 Aplicación móvil para la gestión de listas de ejercicios de entrenamiento en React Native Ilustración 66 – Pantalla de lista de ejercicios del modo Entrenamiento En la Ilustración 66 se detallan los elementos de una lista de ejercicios en el modo “Entrenamiento”, que son los siguientes: un icono para indicar si la lista o el ejercicio se ha realizado; un icono para editar el título de la lista; un menú desplegable tanto en la lista como en el ejercicio; un botón para eliminar la lista; un botón para iniciar un entrenamiento y un botón para enviar la lista.
Interfaz de usuario y funcionalidad 82 82 5.5.1 Editar título de una lista Ilustración 67 – Editar título de una lista Para modificar el título de una lista, se debe presionar en el icono de “editar lista” situado al lado del título. Tras pulsarlo, aparecerá un icono de confirmación y el teclado del teléfono tal y como se muestra en la Ilustración 67. Una vez editado el título, se podrá pulsar el botón de confirmación del teclado o el icono de confirmación ubicado al lado del título para guardar los cambios. 5.5.2 Marcar una lista como realizada En la Ilustración 68 se puede observar el menú de una lista situado en la esquina superior derecha, donde aparecen las siguientes opciones:
83 83 Aplicación móvil para la gestión de listas de ejercicios de entrenamiento en React Native Ilustración 68 – Menú de la lista de ejercicios modo Entrenamiento Si se escoge la opción de “Marcar como realizado”, se cambiará el icono ubicado en la esquina superior izquierda y aparecerá un símbolo de “realizado”, como se puede observar en la Ilustración 69: Ilustración 69 – Ejemplo de marcar lista como realizada
Interfaz de usuario y funcionalidad 84 84 Si se elige la opción de “Marcar como realizado” en uno de los ejercicios, aparecerá el mismo símbolo en el ejercicio y cambiará a estado “realizado”. 5.5.3 Añadir recordatorio de una lista Al pulsar el botón de “Añadir recordatorio”, aparece una ventana de tipo “Modal” que se muestra en la Ilustración 70 a continuación: Ilustración 70 – Ventana de añadir recordatorio Para añadir un recordatorio, el usuario puede seleccionar el día pulsando el botón “Seleccionar día”, que abre el calendario, y puede seleccionar la hora pulsando el botón “Seleccionar hora”. En la Ilustración 71 y 72 se muestran el calendario y el reloj respectivamente para elegir la fecha y la hora:
85 85 Aplicación móvil para la gestión de listas de ejercicios de entrenamiento en React Native Ilustración 71 – Ejemplo de calendario Ilustración 72 – Ejemplo de hora para añadir recordatorio para añadir recordatorio Una vez seleccionada la fecha y la hora, se puede elegir si se prefiere recibir la notificación con una antelación de 0, 10, 15, 30 o 60 minutos. En la parte inferior de la ventana se muestra la fecha y la hora en la cual se recibirá la notificación. Una vez finalizado, se pulsará el botón “Guardar” y se habrá guardado el recordatorio. La notificación se recibirá de forma periódica el mismo día de la semana que se ha elegido. Es decir, si se ha elegido un lunes, se repetirá cada lunes a la misma hora. En el caso de que quiera dejar de recibir un recordatorio para esa lista, puede pulsar el botón de “Eliminar recordatorio”. En la Ilustración 73 se muestra un ejemplo de notificación de un recordatorio de una lista. La notificación aparece 60 minutos antes de la hora del entrenamiento.
Interfaz de usuario y funcionalidad 86 86 Ilustración 73 – Ejemplo de notificación de recordatorio de una lista 5.5.4 Añadir fondo de lista Para añadir un fondo de pantalla en la lista se utiliza el mismo procedimiento que en el apartado 5.3.1 excepto que, en este caso, se guarda la uri del fondo escogido en un campo de la lista. En la Ilustración 74 se muestra un ejemplo de un fondo personalizado para una lista:
87 87 Aplicación móvil para la gestión de listas de ejercicios de entrenamiento en React Native Ilustración 74 – Ejemplo de fondo personalizado para una lista 5.5.5 Eliminar una lista Al pulsar el botón de “Eliminar lista” situado en la esquina inferior izquierda, aparece una alerta tal y como se indica en la Ilustración 75:
Interfaz de usuario y funcionalidad 88 88 Ilustración 75 – Ejemplo de alerta para eliminar una lista Al pulsar “Sí”, la lista se eliminará y se volverá a la pantalla anterior (de lista de listas). 5.5.6 Enviar una lista Una vez pulsado el botón de “Enviar lista”, se mostrará el menú de opciones para compartir la lista que aparece en la Ilustración 76:
89 89 Aplicación móvil para la gestión de listas de ejercicios de entrenamiento en React Native Ilustración 76 – Menú de opciones para enviar una lista Entre las opciones que se muestran se puede escoger enviar la lista por Gmail o por Bluetooth. En el caso de enviar la lista por Gmail, se abrirá la aplicación de Gmail y se mostrará un correo electrónico como el de la Ilustración 77 donde se introducirá el destinatario, el asunto y la descripción. La lista se adjuntará de forma automática.
Interfaz de usuario y funcionalidad 96 96 Ilustración 83 – Ventana de añadir foto a un ejercicio Ilustración 84 – Ejemplo de foto en un ejercicio
97 97 Aplicación móvil para la gestión de listas de ejercicios de entrenamiento en React Native En el caso de que el usuario quiera borrar la foto tomada, aparecerá la opción de “Borrar foto” en el menú despegable del ejercicio y, una vez pulsada, se mostrará una alerta donde el usuario podrá confirmar que desea eliminar la foto. Estas tres funcionalidades son opcionales a la hora de realizar un entrenamiento de una lista y se han añadido para ofrecer una mayor personalización de una lista al usuario. 5.6 Pantalla entrenamiento de una lista Para realizar un entrenamiento de una lista, se debe seleccionar una lista en el modo “Entrenamiento” y pulsar en el botón de “Iniciar entrenamiento”. En la Ilustración 85 se muestra un ejemplo de la pantalla de entrenamiento de la lista seleccionada: Ilustración 85 – Pantalla de entrenamiento de una lista Se puede observar que aparece un cronómetro, el número de series, repeticiones y tiempo, y el vídeo del ejercicio. Si se pulsa el botón de “Comenzar ejercicio”, el cronómetro empieza a contar y aparece el botón “Siguiente” en la pantalla, tal y como se muestra en la Ilustración 86:
Interfaz de usuario y funcionalidad 98 98 Ilustración 86 – Ejemplo de entrenamiento pulsando comenzar Una vez terminado el ejercicio, se pulsará el botón “Siguiente” para que aparezca el siguiente ejercicio de la lista. Además, se habrá guardado el tiempo de realización del ejercicio tras pulsar el botón. Para empezar el siguiente ejercicio, se pulsará el botón “Comenzar ejercicio”, y de esta forma se guardará el tiempo de descanso del ejercicio anterior. Una vez terminado el último ejercicio de la lista, aparecerá el botón “Guardar” y, al pulsarlo, se pausará el cronómetro y se almacenarán los resultados en el historial de la lista. 5.7 Pantalla de historial de una lista Para visualizar el historial de una lista, se debe seleccionar la opción “Abrir historial” del menú desplegable de la lista. En la Ilustración 87 se detalla la pantalla del historial de una lista:
99 99 Aplicación móvil para la gestión de listas de ejercicios de entrenamiento en React Native Ilustración 87 – Ejemplo de historial de una lista En el historial se almacena cada historial de entrenamiento de la lista, donde se muestra la fecha del entrenamiento y el tiempo total empleado en realizarlo. Asimismo, se muestra el botón “Borrar historial” y “Atrás” en la parte inferior de la pantalla. Para visualizar un historial de entrenamiento concreto, se pulsará en el elemento y se abrirá una pantalla que muestra el número de series y repeticiones, y el tiempo de realización y de descanso de cada ejercicio de la lista. En la Ilustración 88 se puede observar un ejemplo de un historial de entrenamiento específico:
Interfaz de usuario y funcionalidad 100 100 Ilustración 88 – Ejemplo de un historial de entrenamiento Si se pulsa el botón “Borrar historial”, se eliminará el historial completo de la lista y aparecerá por pantalla el texto “El historial está vacío”, y desaparecerá el botón “Borrar historial”, como se muestra en la Ilustración 89:
101 101 Aplicación móvil para la gestión de listas de ejercicios de entrenamiento en React Native Ilustración 89 – Ejemplo de historial vacío de una lista 5.8 Pantalla de lista de ejercicios modo Configuración En el modo “Configuración”, se muestra la lista de listas igual que en el modo “Entrenamiento” pero, al seleccionar una lista, aparecen algunas funcionalidades diferentes. En la Ilustración 90 se detallan los elementos de una lista en el modo “Configuración”:
Interfaz de usuario y funcionalidad 102 102 Ilustración 90 – Ejemplo de pantalla lista en el modo Configuración Las funcionalidades que tienen en común una lista en el modo “Entrenamiento” y en el modo “Configuración” son: eliminar la lista, enviar la lista y añadir fondo de pantalla. Sin embargo, las funcionalidades que se encuentran en una lista en el modo “Configuración” y que no aparecen en el modo “Entrenamiento” son: “Añadir ejercicio”, “Modificar correo electrónico” y “Eliminar ejercicio”. De esta forma, se separan las funcionalidades que se relacionan con realizar un entrenamiento y las que se atribuyen a configurar una lista y sus elementos. 5.8.1 Añadir un ejercicio a una lista creada Al pulsar el botón de “Añadir ejercicio”, en función de si la lista es de ejercicios de YouTube o de ejercicios del almacenamiento local, aparecerá una ventana de tipo “Modal” diferente. En la Ilustración 91 aparece un ejemplo de una ventana para añadir un ejercicio local, y en la Ilustración 92 aparece una ventana para añadir un ejercicio de YouTube:
103 103 Aplicación móvil para la gestión de listas de ejercicios de entrenamiento en React Native Ilustración 91 – Ejemplo de añadir Ilustración 92 – Ejemplo de añadir un ejercicio local un ejercicio de YouTube 5.8.2 Eliminar un ejercicio de una lista Al pulsar el botón de “Eliminar ejercicio”, aparece una alerta de confirmación como en el ejemplo de la Ilustración 93. Tras presionar la opción “Sí”, se borrará el ejercicio de la lista.
Interfaz de usuario y funcionalidad 104 104 Ilustración 93 – Ejemplo de eliminar un ejercicio de la lista 5.8.3 Modificar el correo electrónico Al pulsar el botón de “Modificar correo electrónico de la lista”, aparecerá una ventana de tipo “Modal” donde se podrá introducir el correo electrónico nuevo. Si el usuario pulsa el botón de “Guardar” y el campo está vacío, aparecerá una alerta indicándolo. Si se ha introducido un correo electrónico con formato inválido, se alertará del error. En la Ilustración 94 se muestra la ventana para modificar el correo electrónico:
105 105 Aplicación móvil para la gestión de listas de ejercicios de entrenamiento en React Native Ilustración 94 – Ventana para modificar el correo electrónico de la lista 5.9 Salir de la aplicación Para salir de la aplicación, se debe pulsar el botón “volver atrás” del dispositivo desde la pantalla de “Modo”. En la Ilustración 95 aparece la alerta que se muestra tras pulsar el botón, para confirmar si el usuario desea salir de la aplicación.
Instalación y pruebas 112 112 Ilustración 105 – Ejemplo de seleccionar Ilustración 106 – Pantalla Lista con fecha para un recordatorio en iOS notificación en iOS
113 7 LÍNEAS DE MEJORA Y CONCLUSIONES El propósito de este capítulo es sintetizar y reunir las tecnologías aprendidas durante el desarrollo del proyecto, proponer posibles mejoras y extraer conclusiones a raíz de los resultados obtenidos. El uso de módulos de Expo ha permitido que se pueda acceder a funciones y aplicaciones del dispositivo, como la cámara y el sistema de archivos, que de otra forma habría sido más complejo. Sin embargo, estos módulos están en constante cambio y se debe tener el Expo SDK actualizado cada cierto tiempo para que funcionen correctamente. Además, algunos de estos módulos se vuelven obsoletos con el tiempo, y es necesario comprobarlo de forma periódica para garantizar el correcto funcionamiento de la aplicación. A la hora de realizar la instalación de la aplicación, el proceso ha sido más sencillo en el caso de Android, ya que solo ha sido necesario crear el archivo .APK ejecutando el comando correspondiente e instalarlo directamente en el dispositivo físico. No obstante, en el caso de iOS ha habido un inconveniente, que es el de necesitar un ordenador con macOS para instalar la app en el emulador de iOS con Xcode, del que no disponía durante el desarrollo del proyecto. La otra opción disponible era crear una cuenta de desarrollador de Apple, que rondaba los 99 dólares al año, para subir la aplicación a la App Store, que no era viable para el proyecto. Para realizar las pruebas de la app, no ha habido mayores inconvenientes debido a que se ha utilizado la aplicación Expo Go en los dispositivos Android e iOS, que permite observar el comportamiento de la aplicación en tiempo real, actualiza los cambios de la interfaz de usuario en cortos periodos de tiempo y que indica los fallos en el momento. El único impedimento encontrado ha sido a la hora de instalar Expo Go en el iPhone, ya que la versión de Expo SDK del proyecto era inferior a la soportada en Expo Go, por lo que ha sido necesario actualizar la versión de Expo SDK de la 44 a la 45 y desinstalar algunos módulos que eran incompatibles o que estaban obsoletos en la nueva versión. En cuanto a los objetivos del proyecto, analizando cada uno de ellos se puede concluir lo siguiente: • Generar un código único en el lenguaje JavaScript que permita usar la aplicación en Android y en iOS: El desarrollo de la aplicación en React Native con Expo ha aportado grandes ventajas, como el generar un único código que se pueda utilizar para las plataformas con sistema operativo iOS y Android. Esto ha permitido que no haya sido necesario escribir código nativo en ningún momento, es decir, escribir en código Java o Kotlin en el caso de Android, o escribir en código ObjectiveC o Swift en el caso de iOS. Esto ha propiciado el no necesitar aprender más de un lenguaje de programación y poder profundizar en el lenguaje JavaScript, ahorrando tiempo y recursos en el proceso. • Comunicación entre Usuario y Especialista mediante correo electrónico y Bluetooth: en un principio se propuso realizar una aplicación para el Usuario y otra para el Especialista con funcionalidades diferentes. En cambio, este objetivo fue modificado y se decidió crear una única aplicación que pueda usar cualquier tipo de usuario ya que, al no hacer uso de una API de autenticación ni de un servidor, no fue necesario distinguir funcionalidades entre los dos roles. El módulo “Sharing” de Expo ha permitido que el envío de listas por correo electrónico (Gmail en concreto) y Bluetooth sea eficiente y sencillo. Si se hubiera desarrollado el código en Android Studio o Xcode, se habría necesitado utilizar librerías diferentes y métodos más complejos para poder enviar las listas de ambas formas. Sin embargo, Expo no proporciona ningún módulo para comprimir una carpeta en formato .zip, por lo que no es posible enviar una lista de ejercicios en local. Por tanto, una posible mejora sería exportar el proyecto para poder escribir código nativo y utilizar la librería correspondiente para comprimir los vídeos y enviar la lista. No obstante, si el archivo .zip tiene un tamaño mayor al
Líneas de mejora y conclusiones 114 114 soportado por Gmail o Bluetooth, no sería posible compartir la lista. En ese caso, una solución posible sería permitir al usuario autenticarse con su cuenta de Google Drive desde la app para poder subir la carpeta con los vídeos de la lista, y compartirla. • Almacenar los datos del usuario en una base de datos local: esto ha sido posible gracias a la librería “AsyncStorage” de React Native, que permite almacenar los datos en la aplicación sin tener que utilizar un servidor de base de datos en la nube. Una ventaja de no depender de un servidor para almacenar las listas es que no es necesario mantener un servidor y se puede ahorrar el coste que eso conlleva. En cambio, una desventaja es que no se puede acceder a las listas de ejercicios almacenadas en otro dispositivo. Para obtener las listas habría que enviarlas e importarlas una a una en el otro dispositivo, lo cual llevaría más tiempo. Por tanto, una posible mejora sería almacenar las listas de cada usuario en una base de datos remota. • Reproducción de listas de entrenamiento con vídeos de YouTube y vídeos del almacenamiento local: el módulo “AV” de Expo y la librería “React Native YouTube iframe” de React Native ha permitido que se puedan reproducir vídeos en local y de YouTube respectivamente. Una ventaja de que estos vídeos se almacenen en el dispositivo es que se puede usar la aplicación y realizar un entrenamiento para una lista de ejercicios en local sin necesidad de una conexión a Internet. Solo es necesaria en el caso de realizar un entrenamiento de una lista de ejercicios de YouTube.
115 ANEXO A: INSTALACIÓN Y DESPLIEGUE En este anexo se explicará el proceso llevado a cabo para crear y desplegar el proyecto. A.1 Instalación del entorno Primero, se debe instalar Node.js que, en función del sistema operativo, se utilizará un método distinto. En este caso, se utilizará el método para un ordenador con Windows 10. Para instalarlo, primero debemos acceder a la página web oficial y descargar el instalador para Windows [40] que aparece en la Ilustración 107: Ilustración 107 – Descargar instalador de Node.js para Windows Una vez descargado, se debe ejecutar el instalador y seleccionar las opciones requeridas de la Ilustración 108. Se puede observar que también se instalará el Node Package Manager (npm) [41], que es el sistema de gestor de paquetes para Node.js. Permite instalar componentes y módulos de React Native y Expo desde la ventana de comandos.
Anexo A: Instalación y despliegue 116 116 Ilustración 108 – Ejecutar instalador de Node.js Tras finalizar el proceso de instalación, se puede comprobar la versión de Node.js y de npm instaladas en el sistema ejecutando los comandos que aparecen en la Ilustración 109: Ilustración 109 – Comprobar la versión de Node.js y npm Para escribir el código del proyecto se ha empleado la herramienta Visual Studio Code. Para poder instalarla, se debe acceder a la página oficial [42] y seleccionar el archivo de instalación para Windows que aparece en la Ilustración 110:
117 117 Aplicación móvil para la gestión de listas de ejercicios de entrenamiento en React Native Ilustración 110 – Descargar archivo de instalación de Visual Studio Code para Windows Una vez descargado, se debe abrir el paquete de instalación y escoger la configuración deseada, tal y como se muestra en la Ilustración 111: Ilustración 111 – Instalar Visual Studio Code Para verificar que se ha instalado correctamente y confirmar la versión, se ejecutará el comando que aparece en la Ilustración 112 a continuación:
Anexo A: Instalación y despliegue 118 118 Ilustración 112 – Comprobar versión de Visual Studio Code Tras instalarlo, ya se puede inicializar una aplicación con Expo [43]. Para ello, primero se debe instalar la interfaz de línea de comandos Expo CLI utilizando el comando que se muestra en la Ilustración 113: Ilustración 113 – Instalación de Expo CLI Una vez instalada, se puede crear un proyecto de React Native con Expo ejecutando el comando “expo init”. En la consola aparecerá la opción de crear un proyecto JavaScript o TypeScript, y elegiremos el lenguaje JavaScript. En la Ilustración 114 se puede observar la ejecución del comando: Ilustración 114 – Creación de un proyecto React Native en JavaScript utilizando Expo CLI Tras crear el proyecto, se puede inicializar utilizando el comando “npm start” que se muestra en la Ilustración 115. Esto ejecuta el comando “expo start” mencionado en el capítulo 2 para iniciar el empaquetador de JavaScript “Metro” y el servidor de desarrollo de Expo.
119 119 Aplicación móvil para la gestión de listas de ejercicios de entrenamiento en React Native Ilustración 115 – Inicialización de la aplicación con npm A.2 Despliegue del proyecto con GitHub Para guardar el progreso del proyecto y realizar un control de versiones es recomendable subir la carpeta del proyecto a GitHub. Para ello, se deben seguir los siguientes pasos: Primero, se debe instalar la aplicación GitHub Desktop desde la página web oficial [44] y presionar el botón de descargar el instalador para Windows que aparece en la Ilustración 116: Ilustración 116 – Página de descarga de GitHub Desktop Una vez descargado, se debe abrir el instalador y avanzar hasta que termine la instalación. De este modo, aparecerá una ventana en la cual se podrá iniciar sesión con una cuenta de GitHub o crear una nueva, tal y como se muestra en la Ilustración 117:
Anexo A: Instalación y despliegue 120 120 Ilustración 117 – Acceder a una cuenta de GitHub con GitHub Desktop Una vez accedido a una cuenta de GitHub, se puede crear un nuevo repositorio, añadir un repositorio existente en local o clonar un repositorio de la nube. Para guardar los avances de la aplicación, se seleccionará la opción de crear un nuevo repositorio. Este se guardará en el sistema de archivos del ordenador. Para subir o publicar el repositorio en la nube, se debe seleccionar la opción de “Publicar repositorio” que aparece en GitHub Desktop. Una vez publicado, si se quiere guardar los cambios realizados en el proyecto, se pueden subir a la nube presionando el botón de “Push origin”. En el caso de querer obtener un repositorio alojado en la nube para poder realizar pruebas se deben seguir los pasos siguientes: En primer lugar, se debe obtener la carpeta donde se encuentra el código de la aplicación, que está alojada en el repositorio de GitHub en la nube. Para almacenar la carpeta de forma local, se debe clonar el repositorio [45] desde la aplicación GitHub Desktop y así crear un repositorio local en el ordenador. En GitHub Desktop aparece una opción para “Clonar repositorio” y, tras pulsarla, aparecerá la ventana de la Ilustración 107, donde se podrá seleccionar el repositorio deseado o introducir la URL para obtener el repositorio de forma manual. Además, se podrá elegir la carpeta donde se almacenará de forma local.
121 121 Aplicación móvil para la gestión de listas de ejercicios de entrenamiento en React Native Ilustración 118 – Clonar repositorio con GitHub Desktop
Anexo C: Código de las funciones para realizar un entrenamiento de una lista 128 128 // Convertimos el objeto lista en una cadena en formato JSON jsonListArray = JSON.stringify(listVideo); break; } } else { if((JSON.parse(item).id) == (JSON.parse((JSON.parse(listaActualT)).videolista[i]).id)){ numLista = i; let tiempoEjFinal = tiempoFinal; let horasFinal = (tiempoEjFinal.split(":")[0]) * 3600; let minutosFinal = tiempoEjFinal.split(":")[1] * 60; let segundosFinal = tiempoEjFinal.split(":")[2] * 1; let segundosTotalActual = (hours * 3600) + (minutes * 60) + seconds; let segundosTotalFinal = horasFinal + minutosFinal + segundosFinal; let segundosDescansoTotal = Math.abs(segundosTotalActual - segundosTotalFinal); let horasDescanso = Math.round(segundosDescansoTotal/60/60); let minutosparaDescanso = Math.round(segundosDescansoTotal/60); let minutosDescanso = Math.round(minutosparaDescanso % 60); let segundosDminutos = Math.round(segundosDescansoTotal % 60); listVideo = JSON.parse(listArray[i-1]); if(horasDescanso < 10){ horasDescanso = "0" + horasDescanso; } if(minutosDescanso < 10){ minutosDescanso = "0" + minutosDescanso; } if(segundosDminutos < 10){ segundosDminutos = "0" + segundosDminutos; } listVideo.tiempoDescanso = horasDescanso + ":" + minutosDescanso + ":" + segundosDminutos; jsonListArray = JSON.stringify(listVideo); break; } } } var listaTiempo = {};
129 129 Aplicación móvil para la gestión de listas de ejercicios de entrenamiento en React Native listaTiempo.id = JSON.parse(jsonListArray).id; listaTiempo.series = JSON.parse(jsonListArray).series; listaTiempo.repeticiones = JSON.parse(jsonListArray).repeticiones; listaTiempo.tiempoRealizacion = JSON.parse(jsonListArray).tiempoRealizacion; if(jsonListArray !== ''){ listaTiempo.tiempoDescanso = JSON.parse(jsonListArray).tiempoDescanso; listaTiempo.video = JSON.parse(jsonListArray).video; } else { listaTiempo.tiempoDescanso = ''; listaTiempo.video = JSON.parse(item).videos; } let newTiempo5 = ''; if(listVideo !== ''){ if(numLista !== 1){ // Si hay más de un ejercicio en la lista, se guardará el tiempo de descanso del ejercicio anterior en la base de datos newTiempo5 = t.filter((lista) => lista !== listArray[numLista-1]); } else{ // Si solo hay un ejercicio en la lista, se borrarán los tiempos de la base de datos newTiempo5 = t; newTiempo5.length=0; } console.log('newTiempo5 es: ', newTiempo5) } var jsonLista = JSON.stringify(listaTiempo); newTiempo5.push(jsonLista); await AsyncStorage.setItem("TIEMPO", JSON.stringify(newTiempo5)); await AsyncStorage.getItem("TIEMPO").then((tiempo) => { console.log('El valor de los tiempos es: ', tiempo) }); setFlagSaveTime(true); setFlagButton(true); } } } catch(error){ console.log(error) } }
Anexo C: Código de las funciones para realizar un entrenamiento de una lista 130 130 “tiempoVideoRealizado” es la función que se llama cuando se pulsa el botón de “Siguiente ejercicio”. Esta función establece el tiempo final del ejercicio y, si se han guardado previamente los tiempos de los ejercicios en la base de datos, calcula el tiempo de realización del ejercicio actual. Si no se han guardado previamente, asigna el tiempo actual como tiempo de realización del ejercicio. const tiempoVideoRealizado = async(item) => { try{ // Guardamos el tiempo de realización final del ejercicio setTiempoFinal(hours + ":" + minutes + ":" + seconds); // Obtenemos los tiempos de la base de datos const valorTiempo = await AsyncStorage.getItem("TIEMPO"); const t = valorTiempo ? JSON.parse(valorTiempo) : []; if(t.length==0){ var listaTiempo = {}; listaTiempo.id = JSON.parse(item).id; listaTiempo.series = JSON.parse(item).series; listaTiempo.repeticiones = JSON.parse(item).repeticiones; let horas = ''; let minutos = ''; let segundos = ''; if(hours < 10){ horas = "0" + hours; } else { horas = hours; } if(minutes < 10){ minutos = "0" + minutes; } else { minutos = minutes; } if(seconds < 10){ segundos = "0" + seconds; } else { segundos = seconds; } listaTiempo.tiempoRealizacion = horas + ":" + minutos + ":" + segundos; listaTiempo.tiempoDescanso = ''; listaTiempo.video = JSON.parse(item).videos; let newTiempo3 = t;
131 131 Aplicación móvil para la gestión de listas de ejercicios de entrenamiento en React Native var jsonLista = JSON.stringify(listaTiempo); newTiempo3.push(jsonLista); // Si no se han guardado los tiempos en la base de datos, se guarda el tiempo de realización del ejercicio await AsyncStorage.setItem("TIEMPO", JSON.stringify(newTiempo3)); await AsyncStorage.getItem("TIEMPO").then((tiempo) => { console.log('El valor de los tiempos es: ', tiempo) }); setFlagButton(false); // Si hay más de un ejercicio en la lista, se avanza al siguiente ejercicio if(flagOneVideo === false){ setFlagTiempoInicial(true); } setFlagTiempo(!flagTiempo); } else { if(tiempoInicio !== ""){ let listArray = t; let listVideo = ''; let videoArray = ''; let numVideo = ''; // Si se han guardado los tiempos en la base de datos, se calcula el tiempo de realización del ejercicio for (let i = 0; i < listaInicialT.videolista.length; i++){ if((JSON.parse(item).id) == (JSON.parse(listaInicialT.videolista[i]).id)){ numVideo = i; let tiempoEjInicial = tiempoInicio; let horasInicial = (tiempoEjInicial.split(":")[0]) * 3600; let minutosInicial = tiempoEjInicial.split(":")[1] * 60; let segundosInicial = tiempoEjInicial.split(":")[2] * 1; let segundosTotalActual = (hours * 3600) + (minutes * 60) + seconds; let segundosTotalInicial = horasInicial + minutosInicial + segundosInicial; let segundosRealizacionTotal = Math.abs(segundosTotalActual - segundosTotalInicial); listVideo = JSON.parse(listaInicialT.videolista[i]); videoArray = JSON.parse(listaInicialT.videolista[i]);
Anexo C: Código de las funciones para realizar un entrenamiento de una lista 132 132 let horasRealizacion = Math.round(segundosRealizacionTotal/60/60); let minutosparaRealizacion = Math.round(segundosRealizacionTotal/60); let minutosRealizacion = Math.round(minutosparaRealizacion % 60); let segundosRminutos = Math.round(segundosRealizacionTotal % 60); if(horasRealizacion < 10){ horasRealizacion = "0" + horasRealizacion; } if(minutosRealizacion < 10){ minutosRealizacion = "0" + minutosRealizacion; } if(segundosRminutos < 10){ segundosRminutos = "0" + segundosRminutos; } listVideo.tiempoRealizacion = horasRealizacion + ":" + minutosRealizacion + ":" + segundosRminutos; break; } } var listaTiempo = {}; listaTiempo.id = JSON.parse(item).id; listaTiempo.series = JSON.parse(item).series; listaTiempo.repeticiones = JSON.parse(item).repeticiones; if(listVideo !== ''){ listaTiempo.tiempoRealizacion = listVideo.tiempoRealizacion; } else{ listaTiempo.tiempoRealizacion = JSON.parse(item).tiempoRealizacion; } listaTiempo.tiempoDescanso = ''; listaTiempo.video = JSON.parse(item).videos; let newTiempo4 = ''; if(videoArray !== ''){ newTiempo4 = t.filter((lista) => lista !== listArray[numVideo]); } var jsonLista = JSON.stringify(listaTiempo); newTiempo4.push(jsonLista); // Almacenamos el tiempo de realización del ejercicio await AsyncStorage.setItem("TIEMPO", JSON.stringify(newTiempo4)); await AsyncStorage.getItem("TIEMPO").then((tiempo) => {
133 133 Aplicación móvil para la gestión de listas de ejercicios de entrenamiento en React Native console.log('El valor de los tiempos es: ', tiempo) }); // Si hay más de un ejercicio en la lista, se avanza al siguiente ejercicio setFlagButton(false); if(flagOneVideo === false){ setFlagTiempoInicial(true); } setFlagTiempo(!flagTiempo); } } } catch(error){ console.log(error) } } “tiempoEjerciciosRealizados” es la función que se llama cuando se pulsa el botón de “Guardar ejercicios”. Esta función establece el tiempo final del ejercicio y el tiempo total del entrenamiento. Si se han guardado previamente los tiempos de los ejercicios en la base de datos, calcula el tiempo de realización del ejercicio actual. Si no se han guardado previamente, asigna el tiempo actual como tiempo de realización del ejercicio. const tiempoEjerciciosRealizados = async(item) => { try{ // Guardamos el tiempo final del ejercicio realizado y el tiempo total de entrenamiento setTiempoFinal(hours + ":" + minutes + ":" + seconds); setTiempoTotal(hours + ":" + minutes + ":" + seconds); // Obtenemos los tiempos de la base de datos const valorTiempo = await AsyncStorage.getItem("TIEMPO"); const t = valorTiempo ? JSON.parse(valorTiempo) : []; if(t.length==0){ var listaTiempo = {}; listaTiempo.id = JSON.parse(item).id; listaTiempo.series = JSON.parse(item).series; listaTiempo.repeticiones = JSON.parse(item).repeticiones; let horas = ''; let minutos = ''; let segundos = ''; if(hours < 10){ horas = "0" + hours; } else { horas = hours;
Anexo C: Código de las funciones para realizar un entrenamiento de una lista 134 134 } if(minutes < 10){ minutos = "0" + minutes; } else { minutos = minutes; } if(seconds < 10){ segundos = "0" + seconds; } else { segundos = seconds; } listaTiempo.tiempoRealizacion = horas + ":" + minutos + ":" + segundos; listaTiempo.tiempoDescanso = ''; listaTiempo.video = JSON.parse(item).videos; let newTiempo6 = t; var jsonLista = JSON.stringify(listaTiempo); newTiempo6.push(jsonLista); // Si no se han guardado los tiempos, almacenamos el tiempo de realización del ejercicio en la base de datos await AsyncStorage.setItem("TIEMPO", JSON.stringify(newTiempo6)); await AsyncStorage.getItem("TIEMPO").then((tiempo) => { console.log('El valor de los tiempos es: ', tiempo) }); setFlagButton(false); if(flagOneVideo === false){ setFlagTiempoInicial(true); } setFlagTiempo(!flagTiempo); } else { if(tiempoInicio !== ""){ let listVideo = ''; let videoArray = ''; // Si se han guardado los tiempos, calculamos el tiempo de realización del ejercicio for (let i = 0; i < listaInicialT.videolista.length; i++){ if((JSON.parse(item).id) == (JSON.parse(listaInicialT.videolista[i]).id)){
135 135 Aplicación móvil para la gestión de listas de ejercicios de entrenamiento en React Native let tiempoEjInicial = tiempoInicio; let horasInicial = (tiempoEjInicial.split(":")[0]) * 3600; let minutosInicial = tiempoEjInicial.split(":")[1] * 60; let segundosInicial = tiempoEjInicial.split(":")[2] * 1; let segundosTotalActual = (hours * 3600) + (minutes * 60) + seconds; let segundosTotalInicial = horasInicial + minutosInicial + segundosInicial; let segundosRealizacionTotal = Math.abs(segundosTotalActual - segundosTotalInicial); listVideo = JSON.parse(listaInicialT.videolista[i]); videoArray = JSON.parse(listaInicialT.videolista[i]); let horasRealizacion = Math.round(segundosRealizacionTotal/60/60); let minutosparaRealizacion = Math.round(segundosRealizacionTotal/60); let minutosRealizacion = Math.round(minutosparaRealizacion % 60); let segundosRminutos = Math.round(segundosRealizacionTotal % 60); if(horasRealizacion < 10){ horasRealizacion = "0" + horasRealizacion; } if(minutosRealizacion < 10){ minutosRealizacion = "0" + minutosRealizacion; } if(segundosRminutos < 10){ segundosRminutos = "0" + segundosRminutos; } listVideo.tiempoRealizacion = horasRealizacion + ":" + minutosRealizacion + ":" + segundosRminutos; break; } } var listaTiempo = {}; listaTiempo.id = JSON.parse(item).id; listaTiempo.series = JSON.parse(item).series; listaTiempo.repeticiones = JSON.parse(item).repeticiones; if(listVideo !== ''){ listaTiempo.tiempoRealizacion = listVideo.tiempoRealizacion; } else{ listaTiempo.tiempoRealizacion = ''; }
Anexo C: Código de las funciones para realizar un entrenamiento de una lista 136 136 listaTiempo.tiempoDescanso = ''; listaTiempo.video = JSON.parse(item).videos; let newTiempo1 = ''; if(videoArray !== ''){ newTiempo1 = t.filter((lista) => (JSON.parse(lista).id !== videoArray.id)); } var jsonLista = JSON.stringify(listaTiempo); newTiempo1.push(jsonLista); // Almacenamos el tiempo de realización del ejercicio en la base de datos await AsyncStorage.setItem("TIEMPO", JSON.stringify(newTiempo1)); await AsyncStorage.getItem("TIEMPO").then((tiempo) => { console.log('El valor de los tiempos es: ', tiempo) }); setFlagButton(false); if(flagOneVideo === false){ setFlagTiempoInicial(true); } setFlagTiempo(!flagTiempo); } } } catch(error){ console.log(error) } } “useEffect” es el Hook que se ejecuta cuando cambia el valor de la variable de estado “flagTiempo”. Si se ha pulsado el botón Siguiente, y no se ha llegado al final de la lista, avanza al próximo ejercicio. Si se pulsa el botón “Guardar ejercicio”, llama a la función “guardarTiemposEjercicios”. useEffect(() => { if(isMounted===true){ // Si se ha pulsado el botón Siguiente, se avanza al próximo ejercicio if(flagOneVideo === false && flagTiempoInicial === true){ pulsarSiguiente(); // Si se ha llegado al último ejercicio, se actualiza la lista if(currentSectionIndex >= ((listaActualT !== '') ? (JSON.parse(listaActualT).videolista.length-2) : (listaInicialT.videolista.length-2))) {
137 137 Aplicación móvil para la gestión de listas de ejercicios de entrenamiento en React Native setFlagButtonGuardar(true); } } // Si se ha pulsado el botón Guardar, guardamos el tiempo de realización y descanso de los ejercicios if(flagTiempoPress === true){ guardarTiemposEjercicios(); } } return () => { isMounted = false; }; }, [flagTiempo]); “guardarTiemposEjercicios” es la función que se llama si se ha pulsado el botón de “Guardar ejercicios”. Esta función guarda el tiempo de realización y de descanso de los ejercicios en el campo “tiemposEjercicios” del historial de entrenamiento actual. Además, rellena el resto de los campos del historial de entrenamiento y lo almacena en el campo “historial” de la lista. Finalmente, almacena la lista en la base de datos local. const guardarTiemposEjercicios = async() => { try{ // Obtenemos las listas y los tiempos de la base de datos const valorListas = await AsyncStorage.getItem("LISTAS"); const l = valorListas ? JSON.parse(valorListas) : []; const valorTiempo = await AsyncStorage.getItem("TIEMPO"); const t = valorTiempo ? JSON.parse(valorTiempo) : []; // Obtenemos la fecha actual var dia = new Date().getDate(); var mes = new Date().getMonth() + 1; var año = new Date().getFullYear(); var fecha = dia + '-' + mes + '-' + año; let listaHist = ''; var listaHistorial = {}; listaHistorial.idHistorial = (Math.round(Math.random() * 1000)).toString(); if (listaActualT !== '' && listaActualT !== undefined) { listaHist = JSON.parse(listaActualT); } else { listaHist = listaInicialT; } // Comprobamos que los id de los historiales de entrenamiento sean únicos en la lista
Referencias 144 144 [14] Facebook, 3 de septiembre de 2019. useFocusEffect. Recuperado de: https://reactnavigation.org/docs/usefocus-effect/. [Último acceso: 10/11/2022] [15] Facebook, 5 de septiembre de 2022. AsyncStorage. Recuperado de: https://reactnative.dev/docs/asyncstorage. [Último acceso: 10/11/2022] [16] Brex, 17 de julio de 2014. Expo. Recuperado de: https://expo.dev/. [Último acceso: 11/11/2022] [17] Brex, 3 de agosto de 2017. API Reference. Recuperado de: https://docs.expo.dev/versions/latest/. [Último acceso: 11/11/2022] [18] Fundación OpenJS, 9 de octubre de 2009. Node.js. Recuperado de: https://nodejs.org/en/. [Último acceso: 11/11/2022] [19] Facebook, 5 de diciembre de 2017. Metro, The JavaScript bundler for React Native. Recuperado de: https://facebook.github.io/metro/. [Último acceso: 11/11/2022] [20] Brex, 24 de abril de 2020. Expo CLI. Recuperado de: https://docs.expo.dev/workflow/expo-cli/. [Último acceso: 11/11/2022] [21] Brex, 22 de abril de 2020. Workflows. Recuperado de: https://docs.expo.dev/introduction/managed-vs- bare/. [Último acceso: 11/11/2022] [22] State Software, 26 de enero de 2009. Introducción a JSON. Recuperado de: https://www.json.org/jsones.html. [Último acceso: 12/11/2022] [23] Microsoft, 1 de enero de 2017. Why did we build Visual Studio Code?. Recuperado de: https://code.visualstudio.com/docs/editor/whyvscode. [Último acceso: 13/11/2022] [24] Microsoft, 29 de agosto de 2022. User Interface. Recuperado de: https://code.visualstudio.com/docs/getstarted/userinterface. [Último acceso: 13/11/2022] [25] Brex, 14 de septiembre de 2022. Expo Go. Recuperado de: https://docs.expo.dev/workflow/expo-go/. [Último acceso: 13/11/2022] [26] Linux, 22 de abril de 2012. Git. Recuperado de: https://git-scm.com/. [Último acceso: 13/11/2022] [27] Microsoft, 27 de agosto de 2020. Getting started with GitHub Desktop. Recuperado de: https://docs.github.com/en/desktop/installing-and-configuring-github-desktop/overview/getting-started- with-github-desktop. [Último acceso: 14/11/2022] [28] Koushik Dutta, 25 de agosto de 2015. Vysor - A window to your Phone. Recuperado de: https://www.vysor.io/. [Último acceso: 14/11/2022] [29] JGraph Ltd, 22 de diciembre de 2019. Diagrams.net. Recuperado de: https://www.diagrams.net/. [Último acceso: 14/11/2022] [30] Visual Paradigm International Ltd, 17 de marzo de 2009. Visual Paradigm. Recuperado de: https://www.visual-paradigm.com/. [Último acceso: 20/11/2022]
145 145 Aplicación móvil para la gestión de listas de ejercicios de entrenamiento en React Native [31] Canva, 16 de junio de 2015. Pixabay. Recuperado de: https://pixabay.com/es/. [Último acceso: 14/11/2022] [32] Bruno Joseph, 26 de febrero de 2019. Pexels. Recuperado de: https://www.pexels.com/es-es/. [Último acceso: 14/11/2022] [33] Brex, 27 de marzo de 2018. ImagePicker. Recuperado de: https://docs.expo.dev/versions/latest/sdk/imagepicker/. [Último acceso: 19/11/2022] [34] Brex, 27 de febrero de 2018. Sharing. Recuperado de: https://docs.expo.dev/versions/v47.0.0/sdk/sharing/. [Último acceso: 19/11/2022] [35] Brex, 29 de julio de 2021. DocumentPicker. Recuperado de: https://docs.expo.dev/versions/latest/sdk/document-picker/. [Último acceso: 20/11/2022] [36] Brex, 22 de noviembre de 2022. FileSystem. Recuperado de: https://docs.expo.dev/versions/latest/sdk/filesystem/. [Último acceso: 20/11/2022] [37] Facebook, 5 de septiembre de 2022. Modal. Recuperado de: https://reactnative.dev/docs/modal. [Último acceso: 28/11/2022] [38] Brex, agosto de 2022. Building Standalone Apps. Recuperado de: https://docs.expo.dev/archive/classicupdates/building-standalone-apps/?redirected. [Último acceso: 01/12/2022] [39] Brex, 11 de diciembre de 2020. Creating your first build. Recuperado de: https://docs.expo.dev/build/setup/. [Último acceso: 01/12/2022] [40] Fundación OpenJS, 27 de julio de 2016. Descargas. Recuperado de: https://nodejs.org/es/download/. [Último acceso: 02/12/2022] [41] npm Inc, 17 de febrero de 2014. npm. Recuperado de: https://www.npmjs.com/. [Último acceso: 02/12/2022] [42] Microsoft, 29 de abril de 2015. Download Visual Studio Code. Recuperado de: https://code.visualstudio.com/download. [Último acceso: 02/12/2022] [43] Brex, 10 de noviembre de 2022. Create your first app. Recuperado de: https://docs.expo.dev/tutorial/create-your-first-app/. [Último acceso: 03/12/2022] [44] Microsoft, 21 de mayo de 2012. GitHub Desktop. Recuperado de: https://desktop.github.com/. [Último acceso: 03/12/2022] [45] Microsoft, 17 de mayo de 2022. Cloning a repository. Recuperado de: https://docs.github.com/en/repositories/creating-and-managing-repositories/cloning-a-repository. [Último acceso: 03/12/2022]
Referencias 146 146