gioser

sergio/humanoid

HTML 38Markdown 1TOML 10 Definitions

⎇ 48189204c5355e06c0ce239629f0b9437a09415f vela/src/main/java/com/rizoma/vela/VelaViewModel.kt 137 lines · 4.6 KB History raw

vela: grabadora inteligente (VAD + compacta silencios + vigilia nocturna) 48189204c · sergio ·

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}