Aplicación Android (Kotlin) para gestión de tareas, contactos y notas.
Este README recoge:
- cómo compilar y ejecutar el proyecto en Windows (PowerShell)
- la estructura principal del repositorio
- permisos y consideraciones (notificaciones, SMS, contactos, alarmas)
- problemas detectados y soluciones inmediatas (incluyendo el arreglo en
AndroidManifest.xml) - recomendaciones y pasos para depurar errores recurrentes
Índice
- Requisitos
- Estructura del repositorio
- Compilar y ejecutar
- Ejecutar en emulador / dispositivo
- Ejecutar tests
- Permisos importantes
- Cambios aplicados (rápido)
- Problemas detectados y soluciones recomendadas
- Depuración y logcat
- Contribuir
- Licencia
- JDK 11+ (o la versión requerida por el Gradle Wrapper del proyecto)
- Android SDK (API level según
compileSdkVersiondel proyecto) - Android Studio (recomendado) o usar
gradlewdesde PowerShell - Conexión a internet para dependencias (la primera vez)
app/- módulo principal Androidsrc/main/AndroidManifest.xml- manifiesto de la aplicaciónsrc/main/java/...- código Kotlin del app (UI, presentation, utils...)build/- artefactos de compilación (generado)
build.gradle.kts,settings.gradle.kts,gradlew- configuración y wrapperdocs/,test-results/- documentación y resultados de prueba
Desde PowerShell en la raíz del proyecto:
# Compilar APK de debug
.\gradlew assembleDebug
# Instalar en dispositivo conectado (debug)
.\gradlew installDebug
# Limpieza y rebuild
.\gradlew clean assembleDebugSi usas Android Studio, abre la carpeta PymeTask y deja que IDE sincronice Gradle.
- Asegúrate de tener un emulador con Google Play o un dispositivo físico conectado.
- Para problemas con envío de SMS/Email en emulador: muchos emuladores no traen apps de SMS o clientes de email instalados por defecto. Prueba con:
- un emulador con Google Play o una imagen con apps preinstaladas
- un dispositivo físico (recomendado para pruebas de intents de SMS/MMS)
Unit tests:
.\gradlew testTests instrumentados (requieren emulador o dispositivo):
.\gradlew connectedAndroidTestEl manifiesto del proyecto declara permisos para:
- Notificaciones:
POST_NOTIFICATIONS - Lectura de contactos:
READ_CONTACTS - Acceso a Internet
- Alarmas exactas:
SCHEDULE_EXACT_ALARM - Vibración
- Localización (coarse / fine)
Lee y solicita permisos en runtime cuando sea necesario (Android 6+). Para notificaciones en Android 13+ es necesario pedir POST_NOTIFICATIONS explícitamente.
-
Se corrigió la estructura de
app/src/main/AndroidManifest.xmlque contenía un cierre prematuro de la etiqueta<application>y un atributo sobrante, provocando el error: "El tipo de elemento "application" debe finalizar por la etiqueta final coincidente ""."- Añadí la declaración de la activity lanzadora
.main.MainActivitycon suintent-filterMAIN/LAUNCHER dentro de<application>. - Verifiqué el manifiesto con las comprobaciones disponibles y no quedaron errores de sintaxis.
- Añadí la declaración de la activity lanzadora
A continuación se listan los problemas que me comentaste y recomendaciones prácticas para resolverlos o investigarlos más a fondo.
- Valor 0.00 en movimientos al crear/editar
- Síntoma: al crear un movimiento, a veces aparece como
0.00y hay que editarlo manualmente. - Causa probable: parsing del input numérico que falla por el separador decimal (coma
,vs punto.) o porque el campo vacío se interpreta como 0. - Soluciones recomendadas:
-
En los
TextFielddonde se captura el importe, normalizar la cadena antes de parsear: reemplazar,por.y luegotoDoubleOrNull().Ejemplo (Kotlin - Compose):
val raw = importeText val normalized = raw.replace(',', '.') val value = normalized.toDoubleOrNull() ?: 0.0
-
Validar que el campo no esté vacío antes de crear el movimiento y mostrar un error si no es válido.
-
Como alternativa (UI), usar
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number)oKeyboardType.Decimaly aplicar un filtro de entrada que reemplace,por.al teclear. -
Nota: no es fiable "deshabilitar la tecla coma" en todos los teclados; es mejor normalizar el input.
-
- Tecla coma en el teclado y casting
- Recomendación: interceptar/normalizar la cadena en el listener del TextField y forzar el cast seguro, p.ej.
text.replace(',', '.'). - Para evitar la coma visualmente en algunos teclados: usar
KeyboardType.Number(aunque puede variar según el IME).
- Editar contactos — botón eliminar
- Requisito: añadir un botón para eliminar el contacto desde la pantalla de edición.
- Recomendaciones de implementación:
- En
EditarContactoScreenañadir un botón (p. ej. IconButton con trash) que llame a la función de ViewModel para borrar el contacto. - Confirmar acción con un diálogo
AlertDialogantes de eliminar. - Después de eliminar, navegar hacia atrás o mostrar Toast.
- En
- Envío de nota por SMS / intent que rompe la app
- Síntoma: "no reconoce ninguna aplicación para enviar sms ni email en el emulador" y el intento rompe la app cuando seleccionas el programa.
- Causa probable: emulator sin apps, o el PendingIntent/Intent usado no es correcto (flags, uri, o formato del extra).
- Recomendaciones:
- Probar en dispositivo físico o en emulador con Play Store y app de Mensajes instalada.
- Validar el Intent de envío. Para SMS usar:
val intent = Intent(Intent.ACTION_SENDTO).apply { data = Uri.parse("smsto:$phoneNumber") putExtra("sms_body", message) } if (intent.resolveActivity(context.packageManager) != null) { context.startActivity(intent) } else { // manejar ausencia de app }
- Antes de startActivity, comprobar
resolveActivity()para evitar el crash cuando no hay apps que gestionen el intent.
- Crash al elegir app para enviar SMS (app rompe)
- Diagnóstico: revisar
logcatpara la excepción exacta (stacktrace). Suele ser ActivityNotFoundException si intent mal formado, o SecurityException si falta permiso. - Pasos de depuración:
- Reproducir con el emulador y revisar
logcatfiltrando por el package de la app o por "AndroidRuntime". - Añadir manejo defensivo con
resolveActivity()como se indica arriba.
- Reproducir con el emulador y revisar
- Notificaciones de alarmas que suenan pero no aparecen en el terminal/logcat
- Comportamiento: la alarma suena pero no se ve la notificación en el panel ni en logcat.
- Comprobaciones:
- Revisar
NotificationHelper.kty confirmar que se crea/registran los canales (API >= 26). - Asegurarse de que
NotificationManager.notify(id, notification)sea llamado y el id sea único/conocido. - Revisar
AlarmReceiver/DismissAlarmReceiverpara comprobar que suonReceive()crea la notificación. - Revisar permisos de notificación y
POST_NOTIFICATIONS(Android 13+): si no se concedió, no aparecerán notificaciones.
- Revisar
- Accionar notificación debería cancelar alarma o abrir tarea
- Mejora propuesta:
- En la notificación, agregar acciones (botones) con PendingIntents: "Cancelar alarma" y "Abrir tarea".
- Para abrir la app en la tarea específica, la
PendingIntentpuede ser ungetActivity()apuntando aMainActivitycon extras (id tarea) yflags = PendingIntent.FLAG_UPDATE_CURRENT. - Para cancelar la alarma, enviar
PendingIntent.getBroadcast()a unBroadcastReceiver(p. ej.DismissAlarmReceiver) que cancele la alarma y actualice estado.
- Para ver logs en PowerShell:
# Mostrar logs (con dispositivo/emulador conectado)
.\gradlew logcatO desde Android Studio, usa Logcat tool window y filtra por el paquete com.dls.pymetask o por AndroidRuntime.
- Recomendación: cuando algo "rompe" al seleccionar una app para SMS/Email, reproduzca el crash y copie el stacktrace completo de Logcat para localizar la excepción exacta.
- Añadir comprobaciones con
resolveActivity()antes destartActivity()para intents implícitos. - Manejar locales en parsing numérico: normalizar separador decimal.
- Crear un channel de notificaciones en la inicialización de la app (
Application.onCreate) y comprobar que el usuario haya concedido permisos de notificación. - Mantener los
BroadcastReceiverregistrados en el manifiesto o dinámicamente según necesidad y conandroid:exportedcorrecto para Android 12+.
- Fijar parsing de importes (coma -> punto) en
CrearMovimientoScreen.ktyEditarMovimientoScreen.kt(alta prioridad). - Añadir
resolveActivity()defensivo en los intents de SMS/Email y probar en device físico (alta prioridad). - Implementar botón "Eliminar" en
EditarContactoScreencon diálogo de confirmación (media). - Añadir acciones en la notificación de alarma para "Cancelar" y "Abrir" (media).
- Crear tests unitarios para el parsing de importes y tests instrumentados para flujo de notificación (opcional).
Si quieres que haga los cambios de código (p. ej. aplicar reemplazo , -> . en los Screens, añadir el botón eliminar contacto, o mejorar la notificación con acciones), indícalo y los aplicaré directamente en el código, ejecutaré las pruebas y validaré la build.
Revisa el fichero LICENSE incluido en el repositorio.
Si quieres que haga alguno de los cambios listados (o todos), dime por cuál empezar y lo implemento y pruebo localmente en el workspace.
He incluido instrucciones concretas y fragmentos de código mínimos para las correcciones más urgentes. Dime si quieres que aplique ya alguna de las soluciones (por ejemplo: 1) editar CrearMovimientoScreen.kt y EditarMovimientoScreen.kt para normalizar el separador decimal, 2) añadir botón de eliminar contacto en EditarContactoScreen, o 3) añadir acciones en la notificación de alarma). Haré los cambios, ejecutaré compilación y pruebas unitarias en el workspace y te regresaré con los resultados.