EstadoAlarmas, EstadoGrabacion and EstadoRadio defaulted `esPremium` to
`() => true`, so any construction site that forgot to wire entitlement
compiled fine and silently ran ungated — failing OPEN to premium and
disabling the paywall with no test able to catch it.
The parameter is now required with no default. Production wiring in
app.dart was already correct and is unchanged; the 184 pre-existing test
call sites now pass `() => true` explicitly, which is exactly the old
implicit default, so every assertion is untouched.
EstadoRadio has no gate of its own but constructs EstadoGrabacion, so it
inherits the same contract.
The one test that existed to pin the old default is renamed to describe
what it still covers (the premium path through iniciar() with no
duracion); its assertions are unchanged.
Pre-existing bug, reproduces identically before this branch's changes:
_editarGrupo (pantalla_ajustes_grupos_favoritos.dart) and
_editarTamanoMaximo (pantalla_ajustes_grabaciones.dart) each created a
TextEditingController, awaited showModalBottomSheet, then disposed the
controller immediately on resolve - racing the sheet's own close
animation, which still holds a bound TextField for a couple more
frames. Manifests as "A TextEditingController was used after being
disposed" plus a couple of cascading framework-internal symptoms.
Fix: extract each sheet's content into its own StatefulWidget
(_HojaEditarGrupo, _HojaTamanoMaximo) that owns the controller in its
own State. Flutter only calls State.dispose() once the widget is
actually removed from the tree, i.e. after the close animation
finishes, so there is no dispose-timing decision left for the caller
to get wrong.
_editarGrupo's own test previously suppressed the crash via a
FlutterError.onError override instead of fixing it; that suppression
is removed here. _editarTamanoMaximo had no coverage at all for this
interaction; added it. Strict TDD: confirmed both sites fail without
the fix (RED) before applying it (GREEN).