MiTensión provides a streamlined interface for recording blood pressure measurements throughout the day. The app automatically detects the current time period (morning, afternoon, or evening) and allows up to 3 measurements per period, following medical best practices.
Each measurement is stored as a simple entity with essential information:
@Entitydata class Medicion( @PrimaryKey(autoGenerate = true) val id: Int = 0, val sistolica: Int, // Systolic pressure val diastolica: Int, // Diastolic pressure val timestamp: Long = System.currentTimeMillis())
Measurements are organized into three daily periods:
Morning
00:01 - 12:30First measurement period of the day
Afternoon
12:31 - 19:00Midday measurement period
Evening
19:01 - 00:00Evening measurement period
The current period is automatically determined based on the device time:
fun obtenerPeriodoActual(): PeriodoDelDia { val calendario = Calendar.getInstance() val hora = calendario.get(Calendar.HOUR_OF_DAY) val minuto = calendario.get(Calendar.MINUTE) val tiempoEnMinutos = hora * 60 + minuto return when { tiempoEnMinutos in 1..750 -> PeriodoDelDia.MAÑANA tiempoEnMinutos in 751..1140 -> PeriodoDelDia.TARDE else -> PeriodoDelDia.NOCHE }}
Tap the diastolic (low) pressure field and enter the value using the same numeric dialog.Both fields display placeholder text “Pulsa para añadir” when empty, making it clear they are interactive.
4
Save Measurement
Tap the “Guardar” (Save) button to store the measurement.The ViewModel validates and saves the data:
fun guardarMedicion(mensajeErrorCampos: String, mensajeErrorPeriodoLleno: String, mensajeExito: String) { viewModelScope.launch { // Validation 1: Empty fields if (_uiState.value.sistolica.isBlank() || _uiState.value.diastolica.isBlank()) { _evento.emit(UiEvento.MostrarMensaje(mensajeErrorCampos)) return@launch } // Validation 2: Period full (3 measurements) if (_uiState.value.numeroMedicion > 3) { val tiempoRestante = obtenerTiempoRestanteParaSiguientePeriodo( _uiState.value.periodo ) val mensajeFormateado = String.format( mensajeErrorPeriodoLleno, tiempoRestante ) _evento.emit(UiEvento.MostrarMensaje(mensajeFormateado)) return@launch } val nuevaMedicion = Medicion( sistolica = sistolica.toInt(), diastolica = diastolica.toInt(), ) repository.insertarMedicion(nuevaMedicion) _evento.emit(UiEvento.GuardadoConExito(mensajeExito)) }}
Source: MedicionViewModel.kt:60-98
5
View Confirmation
A Toast message confirms the save, and the form resets for the next measurement.
The numeric input dialog automatically focuses the text field and selects all text for quick editing:
var text by remember { mutableStateOf( TextFieldValue( text = valorInicial, selection = TextRange(valorInicial.length) ) )}LaunchedEffect(Unit) { focusRequester.requestFocus()}
The measurement screen uses a clean MVVM architecture with UI state:
data class MedicionUiState( val sistolica: String = "", val diastolica: String = "", val periodo: PeriodoDelDia = obtenerPeriodoActual(), val numeroMedicion: Int = 1 // From 1 to 3)
Source: MedicionViewModel.kt:17-22Events are handled through a shared flow to ensure one-time consumption:
sealed class UiEvento { data class MostrarMensaje(val mensaje: String) : UiEvento() data class GuardadoConExito(val mensaje: String) : UiEvento()}LaunchedEffect(key1 = true) { viewModel.evento.collectLatest { evento -> when (evento) { is MedicionViewModel.UiEvento.MostrarMensaje -> { Toast.makeText(context, evento.mensaje, Toast.LENGTH_LONG).show() } is MedicionViewModel.UiEvento.GuardadoConExito -> { Toast.makeText(context, evento.mensaje, Toast.LENGTH_SHORT).show() viewModel.onGuardadoExitoso() } } }}