⎇ 48189204c5355e06c0ce239629f0b9437a09415f
vela/src/main/java/com/rizoma/vela/VelaViewModel.kt
History
raw
vela: grabadora inteligente (VAD + compacta silencios + vigilia nocturna)
1package com.rizoma.vela
2
3import android.app.Application
4import android.content.ComponentName
5import android.content.Context
6import android.content.Intent
7import android.content.ServiceConnection
8import android.os.IBinder
9import androidx.compose.runtime.getValue
10import androidx.compose.runtime.mutableStateOf
11import androidx.compose.runtime.setValue
12import androidx.lifecycle.AndroidViewModel
13import androidx.lifecycle.viewModelScope
14import com.rizoma.vela.audio.GrabadoraHolder
15import com.rizoma.vela.data.Ajustes
16import com.rizoma.vela.data.AjustesActuales
17import com.rizoma.vela.data.Modo
18import com.rizoma.vela.data.Repositorio
19import com.rizoma.vela.data.Sesion
20import com.rizoma.vela.service.VigiliaService
21import kotlinx.coroutines.Dispatchers
22import kotlinx.coroutines.flow.collectLatest
23import kotlinx.coroutines.launch
24import kotlinx.coroutines.withContext
25
26sealed interface Pantalla {
27 data object Sesiones : Pantalla
28 data object Grabando : Pantalla
29 data class Ver(val id: Long) : Pantalla
30 data object Ajustes : Pantalla
31}
32
33class VelaViewModel(app: Application) : AndroidViewModel(app) {
34
35 private val repo = Repositorio(app)
36 val ajustes = Ajustes(app)
37
38 var pantalla by mutableStateOf<Pantalla>(Pantalla.Sesiones); private set
39 var permiso by mutableStateOf(false)
40 var errorMic by mutableStateOf<String?>(null); private set
41 var sesiones by mutableStateOf<List<Sesion>>(emptyList()); private set
42 var cfg by mutableStateOf(AjustesActuales()); private set
43
44 private var servicio: VigiliaService? by mutableStateOf(null)
45 val holder: GrabadoraHolder? get() = servicio?.holder
46
47 private var modoPendiente: Modo? = null
48
49 private val conexion = object : ServiceConnection {
50 override fun onServiceConnected(name: ComponentName?, binder: IBinder?) {
51 val svc = (binder as? VigiliaService.LocalBinder)?.service ?: return
52 servicio = svc
53 if (svc.holder.activa) {
54 pantalla = Pantalla.Grabando
55 } else modoPendiente?.let { arrancar(it) }
56 modoPendiente = null
57 }
58
59 override fun onServiceDisconnected(name: ComponentName?) { servicio = null }
60 }
61
62 init {
63 val app = getApplication<Application>()
64 app.bindService(
65 Intent(app, VigiliaService::class.java), conexion, Context.BIND_AUTO_CREATE,
66 )
67 recargar()
68 viewModelScope.launch {
69 ajustes.flujo.collectLatest { cfg = it }
70 }
71 }
72
73 fun recargar() {
74 viewModelScope.launch {
75 val lista = withContext(Dispatchers.IO) { repo.listar() }
76 sesiones = lista
77 }
78 }
79
80 // ---- Grabación ----------------------------------------------------
81
82 fun grabar(modo: Modo) {
83 errorMic = null
84 if (!permiso) { errorMic = "hace falta permiso de micrófono"; return }
85 val app = getApplication<Application>()
86 app.startForegroundService(Intent(app, VigiliaService::class.java))
87 val svc = servicio
88 if (svc != null) arrancar(modo) else modoPendiente = modo
89 pantalla = Pantalla.Grabando
90 }
91
92 private fun arrancar(modo: Modo) {
93 servicio?.iniciar(modo) {
94 // fallo al abrir el micrófono (en hilo de fondo): vuelve a la lista
95 viewModelScope.launch {
96 errorMic = "no se pudo abrir el micrófono"
97 pantalla = Pantalla.Sesiones
98 }
99 }
100 }
101
102 fun detener() {
103 val id = holder?.sesionId ?: 0L
104 servicio?.detener()
105 recargar()
106 pantalla = if (id != 0L) Pantalla.Ver(id) else Pantalla.Sesiones
107 }
108
109 // ---- Navegación ---------------------------------------------------
110
111 fun abrir(id: Long) { pantalla = Pantalla.Ver(id) }
112 fun irAjustes() { pantalla = Pantalla.Ajustes }
113 fun volver() {
114 pantalla = if (holder?.activa == true) Pantalla.Grabando else Pantalla.Sesiones
115 }
116
117 fun cargar(id: Long): Sesion? = repo.cargar(id)
118
119 fun borrar(id: Long) {
120 repo.borrar(id)
121 recargar()
122 pantalla = Pantalla.Sesiones
123 }
124
125 // ---- Ajustes ------------------------------------------------------
126
127 fun setSensibilidad(v: Float) = viewModelScope.launch { ajustes.setSensibilidad(v) }
128 fun setSampleRate(v: Int) = viewModelScope.launch { ajustes.setSampleRate(v) }
129 fun setPreRoll(v: Int) = viewModelScope.launch { ajustes.setPreRoll(v) }
130 fun setCola(v: Int) = viewModelScope.launch { ajustes.setCola(v) }
131 fun setMantenerPantalla(v: Boolean) = viewModelScope.launch { ajustes.setMantenerPantalla(v) }
132
133 override fun onCleared() {
134 runCatching { getApplication<Application>().unbindService(conexion) }
135 super.onCleared()
136 }
137}