Files
subtracks/app/src/main/kotlin/com/subtracks/ui/settings/SettingsViewModel.kt
T
austinried 229d6de4c6 settings: add the replay gain controls
Final slice: the screen that drives the mode and preamp preferences the
playback side already reads. Until now `setReplayGainMode` and
`setReplayGainPreampDb` had no production caller, so Off and the preamp
were unreachable.

- `SettingsViewModel` exposes both preferences and writes them back.
- The Playback section gains a "Replay gain" row opening an Off / Track /
  Album choice, and a "Preamp" row opening a slider across the +-15 dB
  range in 0.5 dB steps.
- `ReplayGainMode` is ordered Off, Track, Album so the choice list reads
  that way; the stored value is the name, so the order is not persisted
  and the default is still Track.
- The labels live in their own file so the signed decibel formatting can
  be tested, as `formatTrackTime` does.
2026-10-16 13:07:11 +00:00

138 lines
4.9 KiB
Kotlin

package com.subtracks.ui.settings
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.subtracks.data.model.Source
import com.subtracks.data.net.NetworkMode
import com.subtracks.data.prefs.DEFAULT_SYNC_INTERVAL_MINUTES
import com.subtracks.data.prefs.ReplayGainMode
import com.subtracks.data.prefs.StreamQuality
import com.subtracks.data.prefs.SyncMode
import com.subtracks.data.prefs.UserPreferences
import com.subtracks.data.repo.SourceRepository
import com.subtracks.data.source.DEFAULT_FETCH_CONCURRENCY
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch
class SettingsViewModel(
private val sourceRepository: SourceRepository,
private val userPreferences: UserPreferences,
) : ViewModel() {
val sources: StateFlow<List<Source>> =
sourceRepository.sources().stateIn(viewModelScope, SharingStarted.WhileSubscribed(5_000), emptyList())
val activeSourceId: StateFlow<Long?> =
sourceRepository.activeSourceId().stateIn(viewModelScope, SharingStarted.WhileSubscribed(5_000), null)
val wifiQuality: StateFlow<StreamQuality> =
userPreferences
.streamQuality(NetworkMode.Wifi)
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5_000), StreamQuality())
val mobileQuality: StateFlow<StreamQuality> =
userPreferences
.streamQuality(NetworkMode.Mobile)
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5_000), StreamQuality())
val downloadQuality: StateFlow<StreamQuality> =
userPreferences
.downloadQuality()
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5_000), StreamQuality())
val downloadOverMetered: StateFlow<Boolean> =
userPreferences
.downloadOverMetered()
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5_000), false)
val syncConcurrency: StateFlow<Int> =
userPreferences
.syncConcurrency()
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5_000), DEFAULT_FETCH_CONCURRENCY)
val syncMode: StateFlow<SyncMode> =
userPreferences
.syncMode()
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5_000), SyncMode.WifiOnly)
val syncIntervalMinutes: StateFlow<Int> =
userPreferences
.syncIntervalMinutes()
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5_000), DEFAULT_SYNC_INTERVAL_MINUTES)
val scrobbling: StateFlow<Boolean> =
userPreferences
.scrobbling()
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5_000), true)
val replayGainMode: StateFlow<ReplayGainMode> =
userPreferences
.replayGainMode()
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5_000), ReplayGainMode.Track)
val replayGainPreamp: StateFlow<Float> =
userPreferences
.replayGainPreampDb()
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5_000), 0f)
val offline: StateFlow<Boolean> = sourceRepository.offline
val verboseLogging: StateFlow<Boolean> =
userPreferences
.verboseLogging()
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5_000), false)
fun setOfflineMode(enabled: Boolean) {
sourceRepository.setOfflineMode(enabled)
}
fun setVerboseLogging(enabled: Boolean) {
viewModelScope.launch { userPreferences.setVerboseLogging(enabled) }
}
fun selectSource(id: Long) {
viewModelScope.launch { sourceRepository.selectSource(id) }
}
fun setWifiQuality(quality: StreamQuality) {
viewModelScope.launch { userPreferences.setStreamQuality(NetworkMode.Wifi, quality) }
}
fun setMobileQuality(quality: StreamQuality) {
viewModelScope.launch { userPreferences.setStreamQuality(NetworkMode.Mobile, quality) }
}
fun setDownloadQuality(quality: StreamQuality) {
viewModelScope.launch { userPreferences.setDownloadQuality(quality) }
}
fun setDownloadOverMetered(allowed: Boolean) {
viewModelScope.launch { userPreferences.setDownloadOverMetered(allowed) }
}
fun setSyncConcurrency(value: Int) {
viewModelScope.launch { userPreferences.setSyncConcurrency(value) }
}
fun setSyncMode(mode: SyncMode) {
viewModelScope.launch { userPreferences.setSyncMode(mode) }
}
fun setSyncIntervalMinutes(value: Int) {
viewModelScope.launch { userPreferences.setSyncIntervalMinutes(value) }
}
fun setScrobbling(enabled: Boolean) {
viewModelScope.launch { userPreferences.setScrobbling(enabled) }
}
fun setReplayGainMode(mode: ReplayGainMode) {
viewModelScope.launch { userPreferences.setReplayGainMode(mode) }
}
fun setReplayGainPreamp(value: Float) {
viewModelScope.launch { userPreferences.setReplayGainPreampDb(value) }
}
}