feat(eq): настоящий эквалайзер + улучшайзеры звука (audiofx)

Раньше пресет эквалайзера в настройках был косметикой (лежал в DataStore, к звуку
не подключён). Теперь — реальные системные эффекты на фикс. аудиосессии плеера:
- AudioEffectsController: графический Equalizer (полосы устройства), BassBoost,
  Virtualizer (объём), LoudnessEnhancer (громкость тихих, до +12 дБ). Привязка к
  generateAudioSessionId() в PlayerController, переживает смену станций. Применение
  в реальном времени, сохранение в DataStore (commit на отпускании слайдера).
- Отдельный экран EqualizerScreen (Настройки → ЗВУК → Эквалайзер): тумблер,
  системные пресеты + «Свой», слайдеры полос (±дБ), bass/virtualizer/loudness.
- Эффекты best-effort: при отсутствии поддержки блок недоступен (null), UI скрывает.
- Убран фейковый чип-пресет Flat/Rock/Pop/Jazz/Bass.
This commit is contained in:
nk
2026-06-06 21:14:38 +03:00
parent 0c01eaab2d
commit e736c2393f
9 changed files with 679 additions and 33 deletions

View File

@@ -33,6 +33,12 @@ class SettingsRepositoryImpl @Inject constructor(
private val COUNTRY_CODE = stringPreferencesKey("country_code")
private val VISUALIZER_STYLE = stringPreferencesKey("visualizer_style")
private val THEME_PALETTE = stringPreferencesKey("theme_palette")
private val EQ_ENABLED = booleanPreferencesKey("eq_enabled")
private val EQ_PRESET = intPreferencesKey("eq_preset")
private val EQ_BANDS = stringPreferencesKey("eq_bands")
private val EQ_BASS = intPreferencesKey("eq_bass")
private val EQ_VIRTUALIZER = intPreferencesKey("eq_virtualizer")
private val EQ_LOUDNESS = intPreferencesKey("eq_loudness")
}
override fun getLastStationId(): Flow<Int?> = dataStore.data.map { it[LAST_STATION_ID] }
@@ -65,4 +71,22 @@ class SettingsRepositoryImpl @Inject constructor(
override fun getThemePalette(): Flow<String> = dataStore.data.map { it[THEME_PALETTE] ?: "forest" }
override suspend fun setThemePalette(id: String) { dataStore.edit { it[THEME_PALETTE] = id } }
override fun getEqEnabled(): Flow<Boolean> = dataStore.data.map { it[EQ_ENABLED] ?: false }
override suspend fun setEqEnabled(enabled: Boolean) { dataStore.edit { it[EQ_ENABLED] = enabled } }
override fun getEqPreset(): Flow<Int> = dataStore.data.map { it[EQ_PRESET] ?: -1 }
override suspend fun setEqPreset(index: Int) { dataStore.edit { it[EQ_PRESET] = index } }
override fun getEqBands(): Flow<String> = dataStore.data.map { it[EQ_BANDS] ?: "" }
override suspend fun setEqBands(csv: String) { dataStore.edit { it[EQ_BANDS] = csv } }
override fun getEqBass(): Flow<Int> = dataStore.data.map { it[EQ_BASS] ?: 0 }
override suspend fun setEqBass(value: Int) { dataStore.edit { it[EQ_BASS] = value } }
override fun getEqVirtualizer(): Flow<Int> = dataStore.data.map { it[EQ_VIRTUALIZER] ?: 0 }
override suspend fun setEqVirtualizer(value: Int) { dataStore.edit { it[EQ_VIRTUALIZER] = value } }
override fun getEqLoudness(): Flow<Int> = dataStore.data.map { it[EQ_LOUDNESS] ?: 0 }
override suspend fun setEqLoudness(value: Int) { dataStore.edit { it[EQ_LOUDNESS] = value } }
}