feat(eq): add per-device equalizer with 4-level preset resolution
Introduce multi-device EQ support allowing each audio output device (built-in speaker, wired, USB, individual Bluetooth by MAC) to have its own equalizer preset, combined with existing per-station presets for a full station×device matrix. - Add DispositivoAudio model and ServicioDispositivoAudio interface - Add Android platform channel (AudioDeviceCallback) for device detection - Add iOS AudioDevicesPlugin (AVAudioSession route tracking) - Extend ServicioEcualizador with device and matrix persistence keys - Implement 4-level resolution: matrix > station > device > global - Add advanced EQ settings section with feature toggle (off by default) - Extend export/import to v3 with backward compatibility - 184 tests passing, zero analyzer issues
This commit is contained in:
@@ -2269,6 +2269,42 @@ abstract class AppLocalizations {
|
||||
/// In es, this message translates to:
|
||||
/// **'https://stream.example.com:8000/radio'**
|
||||
String get streamUrlHint;
|
||||
|
||||
/// No description provided for @advancedEqSectionTitle.
|
||||
///
|
||||
/// In es, this message translates to:
|
||||
/// **'Opciones avanzadas de ecualización'**
|
||||
String get advancedEqSectionTitle;
|
||||
|
||||
/// No description provided for @advancedEqEnableToggle.
|
||||
///
|
||||
/// In es, this message translates to:
|
||||
/// **'Activar EQ por dispositivo'**
|
||||
String get advancedEqEnableToggle;
|
||||
|
||||
/// No description provided for @advancedEqEnableToggleSubtitle.
|
||||
///
|
||||
/// In es, this message translates to:
|
||||
/// **'Aplica automáticamente un preset de EQ distinto al cambiar la salida de audio.'**
|
||||
String get advancedEqEnableToggleSubtitle;
|
||||
|
||||
/// No description provided for @advancedEqKnownDevicesTitle.
|
||||
///
|
||||
/// In es, this message translates to:
|
||||
/// **'Dispositivos de audio conocidos'**
|
||||
String get advancedEqKnownDevicesTitle;
|
||||
|
||||
/// No description provided for @advancedEqKnownDevicesEmpty.
|
||||
///
|
||||
/// In es, this message translates to:
|
||||
/// **'No hay dispositivos registrados. Conectá uno para empezar.'**
|
||||
String get advancedEqKnownDevicesEmpty;
|
||||
|
||||
/// No description provided for @advancedEqDevicePresetLabel.
|
||||
///
|
||||
/// In es, this message translates to:
|
||||
/// **'Preset: {presetName}'**
|
||||
String advancedEqDevicePresetLabel(Object presetName);
|
||||
}
|
||||
|
||||
class _AppLocalizationsDelegate
|
||||
|
||||
@@ -1225,4 +1225,26 @@ class AppLocalizationsAr extends AppLocalizations {
|
||||
|
||||
@override
|
||||
String get streamUrlHint => 'https://stream.example.com:8000/radio';
|
||||
|
||||
@override
|
||||
String get advancedEqSectionTitle => 'Opciones avanzadas de ecualización';
|
||||
|
||||
@override
|
||||
String get advancedEqEnableToggle => 'Activar EQ por dispositivo';
|
||||
|
||||
@override
|
||||
String get advancedEqEnableToggleSubtitle =>
|
||||
'Aplica automáticamente un preset de EQ distinto al cambiar la salida de audio.';
|
||||
|
||||
@override
|
||||
String get advancedEqKnownDevicesTitle => 'Dispositivos de audio conocidos';
|
||||
|
||||
@override
|
||||
String get advancedEqKnownDevicesEmpty =>
|
||||
'No hay dispositivos registrados. Conectá uno para empezar.';
|
||||
|
||||
@override
|
||||
String advancedEqDevicePresetLabel(Object presetName) {
|
||||
return 'Preset: $presetName';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1232,4 +1232,26 @@ class AppLocalizationsBn extends AppLocalizations {
|
||||
|
||||
@override
|
||||
String get streamUrlHint => 'https://stream.example.com:8000/radio';
|
||||
|
||||
@override
|
||||
String get advancedEqSectionTitle => 'Opciones avanzadas de ecualización';
|
||||
|
||||
@override
|
||||
String get advancedEqEnableToggle => 'Activar EQ por dispositivo';
|
||||
|
||||
@override
|
||||
String get advancedEqEnableToggleSubtitle =>
|
||||
'Aplica automáticamente un preset de EQ distinto al cambiar la salida de audio.';
|
||||
|
||||
@override
|
||||
String get advancedEqKnownDevicesTitle => 'Dispositivos de audio conocidos';
|
||||
|
||||
@override
|
||||
String get advancedEqKnownDevicesEmpty =>
|
||||
'No hay dispositivos registrados. Conectá uno para empezar.';
|
||||
|
||||
@override
|
||||
String advancedEqDevicePresetLabel(Object presetName) {
|
||||
return 'Preset: $presetName';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1242,4 +1242,26 @@ class AppLocalizationsDe extends AppLocalizations {
|
||||
|
||||
@override
|
||||
String get streamUrlHint => 'https://stream.example.com:8000/radio';
|
||||
|
||||
@override
|
||||
String get advancedEqSectionTitle => 'Opciones avanzadas de ecualización';
|
||||
|
||||
@override
|
||||
String get advancedEqEnableToggle => 'Activar EQ por dispositivo';
|
||||
|
||||
@override
|
||||
String get advancedEqEnableToggleSubtitle =>
|
||||
'Aplica automáticamente un preset de EQ distinto al cambiar la salida de audio.';
|
||||
|
||||
@override
|
||||
String get advancedEqKnownDevicesTitle => 'Dispositivos de audio conocidos';
|
||||
|
||||
@override
|
||||
String get advancedEqKnownDevicesEmpty =>
|
||||
'No hay dispositivos registrados. Conectá uno para empezar.';
|
||||
|
||||
@override
|
||||
String advancedEqDevicePresetLabel(Object presetName) {
|
||||
return 'Preset: $presetName';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1228,4 +1228,26 @@ class AppLocalizationsEn extends AppLocalizations {
|
||||
|
||||
@override
|
||||
String get streamUrlHint => 'https://stream.example.com:8000/radio';
|
||||
|
||||
@override
|
||||
String get advancedEqSectionTitle => 'Advanced Equalization Options';
|
||||
|
||||
@override
|
||||
String get advancedEqEnableToggle => 'Enable per-device EQ';
|
||||
|
||||
@override
|
||||
String get advancedEqEnableToggleSubtitle =>
|
||||
'Automatically apply a different EQ preset when your audio output changes.';
|
||||
|
||||
@override
|
||||
String get advancedEqKnownDevicesTitle => 'Known audio devices';
|
||||
|
||||
@override
|
||||
String get advancedEqKnownDevicesEmpty =>
|
||||
'No audio devices recorded yet. Connect a device to get started.';
|
||||
|
||||
@override
|
||||
String advancedEqDevicePresetLabel(Object presetName) {
|
||||
return 'Preset: $presetName';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1237,4 +1237,26 @@ class AppLocalizationsEs extends AppLocalizations {
|
||||
|
||||
@override
|
||||
String get streamUrlHint => 'https://stream.example.com:8000/radio';
|
||||
|
||||
@override
|
||||
String get advancedEqSectionTitle => 'Opciones avanzadas de ecualización';
|
||||
|
||||
@override
|
||||
String get advancedEqEnableToggle => 'Activar EQ por dispositivo';
|
||||
|
||||
@override
|
||||
String get advancedEqEnableToggleSubtitle =>
|
||||
'Aplica automáticamente un preset de EQ distinto al cambiar la salida de audio.';
|
||||
|
||||
@override
|
||||
String get advancedEqKnownDevicesTitle => 'Dispositivos de audio conocidos';
|
||||
|
||||
@override
|
||||
String get advancedEqKnownDevicesEmpty =>
|
||||
'No hay dispositivos registrados. Conectá uno para empezar.';
|
||||
|
||||
@override
|
||||
String advancedEqDevicePresetLabel(Object presetName) {
|
||||
return 'Preset: $presetName';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1247,4 +1247,26 @@ class AppLocalizationsFr extends AppLocalizations {
|
||||
|
||||
@override
|
||||
String get streamUrlHint => 'https://stream.example.com:8000/radio';
|
||||
|
||||
@override
|
||||
String get advancedEqSectionTitle => 'Opciones avanzadas de ecualización';
|
||||
|
||||
@override
|
||||
String get advancedEqEnableToggle => 'Activar EQ por dispositivo';
|
||||
|
||||
@override
|
||||
String get advancedEqEnableToggleSubtitle =>
|
||||
'Aplica automáticamente un preset de EQ distinto al cambiar la salida de audio.';
|
||||
|
||||
@override
|
||||
String get advancedEqKnownDevicesTitle => 'Dispositivos de audio conocidos';
|
||||
|
||||
@override
|
||||
String get advancedEqKnownDevicesEmpty =>
|
||||
'No hay dispositivos registrados. Conectá uno para empezar.';
|
||||
|
||||
@override
|
||||
String advancedEqDevicePresetLabel(Object presetName) {
|
||||
return 'Preset: $presetName';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1231,4 +1231,26 @@ class AppLocalizationsHi extends AppLocalizations {
|
||||
|
||||
@override
|
||||
String get streamUrlHint => 'https://stream.example.com:8000/radio';
|
||||
|
||||
@override
|
||||
String get advancedEqSectionTitle => 'Opciones avanzadas de ecualización';
|
||||
|
||||
@override
|
||||
String get advancedEqEnableToggle => 'Activar EQ por dispositivo';
|
||||
|
||||
@override
|
||||
String get advancedEqEnableToggleSubtitle =>
|
||||
'Aplica automáticamente un preset de EQ distinto al cambiar la salida de audio.';
|
||||
|
||||
@override
|
||||
String get advancedEqKnownDevicesTitle => 'Dispositivos de audio conocidos';
|
||||
|
||||
@override
|
||||
String get advancedEqKnownDevicesEmpty =>
|
||||
'No hay dispositivos registrados. Conectá uno para empezar.';
|
||||
|
||||
@override
|
||||
String advancedEqDevicePresetLabel(Object presetName) {
|
||||
return 'Preset: $presetName';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1236,4 +1236,26 @@ class AppLocalizationsId extends AppLocalizations {
|
||||
|
||||
@override
|
||||
String get streamUrlHint => 'https://stream.example.com:8000/radio';
|
||||
|
||||
@override
|
||||
String get advancedEqSectionTitle => 'Opciones avanzadas de ecualización';
|
||||
|
||||
@override
|
||||
String get advancedEqEnableToggle => 'Activar EQ por dispositivo';
|
||||
|
||||
@override
|
||||
String get advancedEqEnableToggleSubtitle =>
|
||||
'Aplica automáticamente un preset de EQ distinto al cambiar la salida de audio.';
|
||||
|
||||
@override
|
||||
String get advancedEqKnownDevicesTitle => 'Dispositivos de audio conocidos';
|
||||
|
||||
@override
|
||||
String get advancedEqKnownDevicesEmpty =>
|
||||
'No hay dispositivos registrados. Conectá uno para empezar.';
|
||||
|
||||
@override
|
||||
String advancedEqDevicePresetLabel(Object presetName) {
|
||||
return 'Preset: $presetName';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1242,4 +1242,26 @@ class AppLocalizationsIt extends AppLocalizations {
|
||||
|
||||
@override
|
||||
String get streamUrlHint => 'https://stream.example.com:8000/radio';
|
||||
|
||||
@override
|
||||
String get advancedEqSectionTitle => 'Opciones avanzadas de ecualización';
|
||||
|
||||
@override
|
||||
String get advancedEqEnableToggle => 'Activar EQ por dispositivo';
|
||||
|
||||
@override
|
||||
String get advancedEqEnableToggleSubtitle =>
|
||||
'Aplica automáticamente un preset de EQ distinto al cambiar la salida de audio.';
|
||||
|
||||
@override
|
||||
String get advancedEqKnownDevicesTitle => 'Dispositivos de audio conocidos';
|
||||
|
||||
@override
|
||||
String get advancedEqKnownDevicesEmpty =>
|
||||
'No hay dispositivos registrados. Conectá uno para empezar.';
|
||||
|
||||
@override
|
||||
String advancedEqDevicePresetLabel(Object presetName) {
|
||||
return 'Preset: $presetName';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1192,4 +1192,26 @@ class AppLocalizationsJa extends AppLocalizations {
|
||||
|
||||
@override
|
||||
String get streamUrlHint => 'https://stream.example.com:8000/radio';
|
||||
|
||||
@override
|
||||
String get advancedEqSectionTitle => 'Opciones avanzadas de ecualización';
|
||||
|
||||
@override
|
||||
String get advancedEqEnableToggle => 'Activar EQ por dispositivo';
|
||||
|
||||
@override
|
||||
String get advancedEqEnableToggleSubtitle =>
|
||||
'Aplica automáticamente un preset de EQ distinto al cambiar la salida de audio.';
|
||||
|
||||
@override
|
||||
String get advancedEqKnownDevicesTitle => 'Dispositivos de audio conocidos';
|
||||
|
||||
@override
|
||||
String get advancedEqKnownDevicesEmpty =>
|
||||
'No hay dispositivos registrados. Conectá uno para empezar.';
|
||||
|
||||
@override
|
||||
String advancedEqDevicePresetLabel(Object presetName) {
|
||||
return 'Preset: $presetName';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1234,4 +1234,26 @@ class AppLocalizationsPt extends AppLocalizations {
|
||||
|
||||
@override
|
||||
String get streamUrlHint => 'https://stream.example.com:8000/radio';
|
||||
|
||||
@override
|
||||
String get advancedEqSectionTitle => 'Opciones avanzadas de ecualización';
|
||||
|
||||
@override
|
||||
String get advancedEqEnableToggle => 'Activar EQ por dispositivo';
|
||||
|
||||
@override
|
||||
String get advancedEqEnableToggleSubtitle =>
|
||||
'Aplica automáticamente un preset de EQ distinto al cambiar la salida de audio.';
|
||||
|
||||
@override
|
||||
String get advancedEqKnownDevicesTitle => 'Dispositivos de audio conocidos';
|
||||
|
||||
@override
|
||||
String get advancedEqKnownDevicesEmpty =>
|
||||
'No hay dispositivos registrados. Conectá uno para empezar.';
|
||||
|
||||
@override
|
||||
String advancedEqDevicePresetLabel(Object presetName) {
|
||||
return 'Preset: $presetName';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1238,4 +1238,26 @@ class AppLocalizationsRu extends AppLocalizations {
|
||||
|
||||
@override
|
||||
String get streamUrlHint => 'https://stream.example.com:8000/radio';
|
||||
|
||||
@override
|
||||
String get advancedEqSectionTitle => 'Opciones avanzadas de ecualización';
|
||||
|
||||
@override
|
||||
String get advancedEqEnableToggle => 'Activar EQ por dispositivo';
|
||||
|
||||
@override
|
||||
String get advancedEqEnableToggleSubtitle =>
|
||||
'Aplica automáticamente un preset de EQ distinto al cambiar la salida de audio.';
|
||||
|
||||
@override
|
||||
String get advancedEqKnownDevicesTitle => 'Dispositivos de audio conocidos';
|
||||
|
||||
@override
|
||||
String get advancedEqKnownDevicesEmpty =>
|
||||
'No hay dispositivos registrados. Conectá uno para empezar.';
|
||||
|
||||
@override
|
||||
String advancedEqDevicePresetLabel(Object presetName) {
|
||||
return 'Preset: $presetName';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1187,4 +1187,26 @@ class AppLocalizationsZh extends AppLocalizations {
|
||||
|
||||
@override
|
||||
String get streamUrlHint => 'https://stream.example.com:8000/radio';
|
||||
|
||||
@override
|
||||
String get advancedEqSectionTitle => 'Opciones avanzadas de ecualización';
|
||||
|
||||
@override
|
||||
String get advancedEqEnableToggle => 'Activar EQ por dispositivo';
|
||||
|
||||
@override
|
||||
String get advancedEqEnableToggleSubtitle =>
|
||||
'Aplica automáticamente un preset de EQ distinto al cambiar la salida de audio.';
|
||||
|
||||
@override
|
||||
String get advancedEqKnownDevicesTitle => 'Dispositivos de audio conocidos';
|
||||
|
||||
@override
|
||||
String get advancedEqKnownDevicesEmpty =>
|
||||
'No hay dispositivos registrados. Conectá uno para empezar.';
|
||||
|
||||
@override
|
||||
String advancedEqDevicePresetLabel(Object presetName) {
|
||||
return 'Preset: $presetName';
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user