Skip to content

alopezdeharo/ZenMeditation

Repository files navigation

🧘 Zen Meditation

Kotlin Android Jetpack Compose Status


Una app de meditación minimalista, construida completamente en Jetpack Compose, con un selector de tiempo circular único, estadísticas detalladas y experiencia visual cuidada al detalle.


✨ Descripción

Zen Meditation es una aplicación Android nativa desarrollada íntegramente en Kotlin y Jetpack Compose que permite a los usuarios cronometrar y gestionar sus sesiones de meditación sin fricciones. Diseñada con una estética zen coherente -paleta dorada sobre fondos oscuros y naturales-, combina una UX minimalista con funcionalidades avanzadas como presets personalizados, estadísticas históricas, campanas configurables y sistema de logros.

Toda la información se almacena localmente en el dispositivo: sin cuentas, sin servidores, sin publicidad.


🎯 Problema que resuelve

La mayoría de apps de meditación del mercado pecan de dos extremos: o son demasiado simples (un timer básico) o están sobrecargadas de suscripciones, anuncios y funcionalidades que distraen del objetivo principal. Zen Meditation cubre el punto medio: ofrece una experiencia visualmente cuidada y funcionalmente completa, sin comprometer la privacidad ni la simplicidad.

Además, implementa un selector de tiempo circular táctil con cuenco tibetano animado —un componente custom desarrollado desde cero en Compose Canvas— que hace que el acto de elegir la duración sea en sí mismo una experiencia meditativa.


🚀 Características principales

⏱️ Temporizador

  • Selector circular táctil con cuenco y mallet animados (Canvas custom)
  • Inicio, pausa, reanudación y reset
  • Cuenta atrás configurable antes de iniciar (5, 10 o 15 segundos)
  • Modo pantalla encendida durante la sesión
  • Servicio en primer plano con notificación persistente y controles de media

🔔 Campanas

  • Campana al inicio, a mitad de sesión y al final
  • Campanas de intervalo configurables (cada N minutos)
  • 4 sonidos disponibles: Cuenco Zen, Campana Templo, Gong, Singing Bowl
  • Vibración al inicio y fin de sesión

📊 Estadísticas

  • Historial de hasta 500 sesiones
  • Racha actual y mejor racha
  • Tiempo total, sesión más larga, promedio y hora habitual
  • Desglose por semana, mes y año
  • Gráfico de actividad mensual (barras, modo landscape)
  • Sistema de logros con 15 badges desbloqueables
  • Objetivo diario de minutos con barra de progreso

🎨 Personalización

  • 7 temas visuales (fondo + cuenco): Montañas, Playa, Bosque, Desierto, Templo Zen, Estrellas, Galaxia
  • Presets guardables con nombre, tiempo, sonido y configuración de campanas
  • Opción de compartir presets

⚙️ Ajustes y calidad de vida

  • Recordatorio diario configurable por hora y días de la semana
  • Modo No Molestar automático durante la meditación
  • Long press en play para resetear (opcionalmente)
  • Idioma: Español e Inglés

📚 Contenido

  • Sección de consejos y curiosidades científicas sobre meditación
  • Contenido cargado desde JSON en assets (editable sin tocar código)

🛠️ Stack tecnológico

Categoría Tecnología
Lenguaje Kotlin 1.9+
UI Jetpack Compose (Material 3)
Arquitectura Single Activity + ForegroundService + StateFlow
Estado StateFlow + collectAsState (patrón MVI ligero)
Persistencia SharedPreferences + JSON en assets
Concurrencia Coroutines + CoroutineScope en Service
Notificaciones NotificationManager + AlarmManager
Animaciones animateFloatAsState, Canvas, AnimatedVisibility
Gráficos Compose Canvas (barras custom)
Audio MediaPlayer
Gestos táctiles combinedClickable, detectDragGestures, pointerInput
DND NotificationPolicy API
Background ForegroundService

⚙️ Instalación

# 1. Clona el repositorio
git clone https://github.com/adrisdev/zen-meditation.git

# 2. Abre el proyecto en Android Studio (Hedgehog o superior)

# 3. Conecta un dispositivo físico o inicia un emulador (API 26+)

# 4. Ejecuta el proyecto
# Build > Run 'app'  /  Shift + F10

⚠️ Requisitos mínimos: Android 8.0 (API 26) · Android Studio Hedgehog o superior · JDK 17


▶️ Uso

  1. Elige la duración — arrastra el mallet alrededor del cuenco para seleccionar los minutos
  2. Pulsa ▶ — la sesión comienza (con cuenta atrás opcional si está configurada)
  3. Pausa / Reanuda — con el mismo botón central; la notificación también tiene controles
  4. Finaliza — suena la campana configurada y la sesión se guarda automáticamente en estadísticas
  5. Explora el menú — desliza hacia arriba desde las tres líneas para acceder a campanas, presets, estadísticas, consejos y ajustes

📁 Estructura del proyecto

app/src/main/
├── java/com/example/zenmeditation/
│   ├── MainActivity.kt          # Entry point, modo inmersivo
│   ├── MeditationScreen.kt      # Pantalla principal, lógica de UI
│   ├── MeditationService.kt     # ForegroundService: timer, campanas, DND
│   ├── TimerState.kt            # StateFlow global (Service ↔ UI)
│   ├── CircularTimePicker.kt    # Componente Canvas custom: cuenco + mallet
│   ├── MenuDrawer.kt            # Bottom sheet animado con tabs
│   ├── BellScreen.kt            # Configuración de campanas
│   ├── PresetsScreen.kt         # Gestión de presets (CRUD + compartir)
│   ├── StatsScreen.kt           # Estadísticas, logros y gráfico
│   ├── TipsScreen.kt            # Consejos cargados desde JSON
│   ├── SettingsScreen.kt        # Ajustes, temas, recordatorio, DND
│   ├── BackupScreen.kt          # Exportar/importar datos
│   └── ReminderReceiver.kt      # BroadcastReceiver para recordatorio diario
│
├── assets/
│   └── tips.json                # Contenido de consejos (editable sin recompilar)
│
└── res/
    ├── drawable/                # Fondos y cuencos por tema (bg_*, bowl_*)
    └── raw/                     # Sonidos de campanas (zen_bell, gong, etc.)

🔐 Configuración

Este proyecto no requiere API keys ni variables de entorno. Todos los datos son locales.

Para añadir o editar consejos sin recompilar:

app/src/main/assets/tips.json

🧪 Testing

El proyecto actualmente no incluye tests automatizados. La hoja de ruta incluye:

// Tests unitarios prioritarios
- TimerState: emisión correcta de StateFlow en START / PAUSE / RESUME / STOP
- saveCompletedSession(): cálculo de racha, acumulados y JSON de historial
- loadPresets() / savePresets(): serialización y deserialización de presets
- scheduleReminder(): selección correcta del próximo día válido

// Tests de UI con Compose Testing
- CircularTimePicker: onMinutesChange al detectar drag gestures
- PresetsScreen: flujo completo guardar → activar → borrar
- StatsScreen: renderizado condicional de objetivo diario y logros

Dependencias necesarias para añadir testing:

testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.compose.ui:ui-test-junit4'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'

🧠 Decisiones técnicas destacadas

ForegroundService como fuente de verdad del timer

El timer vive en MeditationService, no en la UI. Esto garantiza que la sesión continúa aunque el usuario minimice la app o el sistema presione la UI. La comunicación con Compose se realiza a través de TimerState -objeto singleton con MutableStateFlow- siguiendo un patrón similar a MVI sin la complejidad de un ViewModel completo. El tiempo se ancla a SystemClock.elapsedRealtime() en lugar de incrementos delta, lo que lo hace resistente a delays de coroutine.

Canvas custom para el selector circular

CircularTimePicker está construido íntegramente con Canvas de Compose y detectDragGestures. Calcula el ángulo del toque respecto al centro del componente, lo normaliza a minutos y actualiza el estado en tiempo real. El mallet se anima con animateFloatAsState para transiciones suaves entre estados (editando / corriendo / pausado). El cuenco reproduce un sonido de bowl al arrastrar, con fade out automático al detenerse.

Separación de gestos en el bottom sheet

El MenuDrawer usa una doble capa de pointerInput: el overlay exterior captura taps con detectTapGestures para cerrar el menú, mientras el sheet interior usa awaitPointerEventScope para absorber el ciclo completo DOWN+UP antes de propagarlo, evitando que los eventos lleguen al CircularTimePicker subyacente y bloqueen la UI.

Persistencia sin base de datos

Se optó por SharedPreferences + JSONArray para el historial de sesiones dado el volumen de datos manejado (máx. 500 sesiones ≈ ~50KB). Esta decisión prioriza la simplicidad y la ausencia de dependencias externas sobre la escalabilidad. Una migración a Room está contemplada en el roadmap.

Contenido desacoplado del código

Los consejos de la sección Tips se cargan desde assets/tips.json en runtime. Esto permite actualizar el contenido sin recompilar ni publicar una nueva versión, y sienta las bases para soportar múltiples idiomas en ese contenido de forma independiente al sistema de localización de Android.

Modo inmersivo persistente

La app oculta las barras del sistema con WindowInsetsControllerCompat y las restaura con BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE. Se reaplica en onWindowFocusChanged para que Samsung y otros fabricantes con capas de personalización agresivas no lo cancelen al volver de segundo plano.


📈 Roadmap

  • Modo meditación infinita — contador ascendente sin límite de tiempo
  • Room Database — migración del historial desde SharedPreferences
  • Widget — acceso rápido al timer desde la pantalla de inicio
  • Sonido ambiente — lluvia, naturaleza, cuencos en loop durante la sesión
  • Exportar/Importar datos — backup completo en JSON
  • Google Play Billing — donaciones nativas (compras únicas)
  • Localización completa — EN/ES con soporte i18n en tips.json
  • Tests unitarios y de UI — cobertura de lógica de negocio y componentes clave
  • ViewModel + Hilt — refactor de arquitectura para mayor testabilidad

🤝 Contribuciones

Las contribuciones son bienvenidas. Para cambios importantes:

  1. Haz fork del repositorio
  2. Crea una rama: git checkout -b feature/nueva-funcionalidad
  3. Commitea tus cambios: git commit -m 'Add: descripción clara'
  4. Haz push: git push origin feature/nueva-funcionalidad
  5. Abre un Pull Request

Por favor, sigue las convenciones de Kotlin y mantén la coherencia visual con la paleta y los componentes existentes.


👨‍💻 Autor

Adrián — Desarrollador Android

Ko-fi GitHub

Proyecto desarrollado como parte de mi portfolio Android. Construido con Kotlin y Jetpack Compose, enfocado en UX minimalista, calidad de código y experiencia de usuario real.


Hecho con 🧘 y Kotlin · Si te resulta útil, considera apoyar el proyecto en Ko-fi

About

App de meditación Android con timer circular custom en Jetpack Compose, estadísticas, presets y temas visuales. Sin ads, sin cuentas, 100% local.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages