mirror of
https://github.com/austinried/subtracks.git
synced 2026-11-11 07:29:14 +01:00
add network-dependent stream quality
Combine max bitrate and transcode format into one StreamQuality and store a separate value per network mode (Wi-Fi vs mobile data). NetworkMonitor reports metered vs unmetered via ConnectivityManager, SourceRepository selects and exposes the active quality, and PlaybackController reloads the window at the current position when it changes, so a network switch re-issues stream URLs with the new settings. Reset Coil's singleton in SubtracksApp.onCreate alongside Koin, since ArtworkSeedCache's background scope can call get() across Robolectric tests and poison the next Application.
This commit is contained in:
@@ -4,9 +4,9 @@ import android.content.Context
|
||||
import androidx.datastore.core.DataStore
|
||||
import androidx.datastore.preferences.core.Preferences
|
||||
import androidx.datastore.preferences.core.edit
|
||||
import androidx.datastore.preferences.core.intPreferencesKey
|
||||
import androidx.datastore.preferences.core.stringPreferencesKey
|
||||
import androidx.datastore.preferences.preferencesDataStore
|
||||
import com.subtracks.data.net.NetworkMode
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.map
|
||||
|
||||
@@ -34,6 +34,11 @@ data class ListQuery(
|
||||
val starred: StarredFilter = StarredFilter.Any,
|
||||
)
|
||||
|
||||
data class StreamQuality(
|
||||
val maxBitrate: Int = 0,
|
||||
val format: String? = null,
|
||||
)
|
||||
|
||||
private val Context.preferences: DataStore<Preferences> by preferencesDataStore("user_prefs")
|
||||
|
||||
class UserPreferences(
|
||||
@@ -48,24 +53,32 @@ class UserPreferences(
|
||||
store.edit { prefs -> prefs[listQueryKey(tab)] = encode(query) }
|
||||
}
|
||||
|
||||
val maxBitrate: Flow<Int> = store.data.map { prefs -> prefs[MAX_BITRATE] ?: 0 }
|
||||
fun streamQuality(mode: NetworkMode): Flow<StreamQuality> =
|
||||
store.data.map { prefs -> decodeStreamQuality(prefs[streamQualityKey(mode)]) }
|
||||
|
||||
suspend fun setMaxBitrate(kbps: Int) {
|
||||
store.edit { prefs -> prefs[MAX_BITRATE] = kbps }
|
||||
suspend fun setStreamQuality(
|
||||
mode: NetworkMode,
|
||||
quality: StreamQuality,
|
||||
) {
|
||||
store.edit { prefs -> prefs[streamQualityKey(mode)] = encode(quality) }
|
||||
}
|
||||
|
||||
val streamFormat: Flow<String?> = store.data.map { prefs -> prefs[STREAM_FORMAT] }
|
||||
|
||||
suspend fun setStreamFormat(format: String?) {
|
||||
store.edit { prefs ->
|
||||
if (format.isNullOrEmpty()) prefs.remove(STREAM_FORMAT) else prefs[STREAM_FORMAT] = format
|
||||
}
|
||||
}
|
||||
private fun streamQualityKey(mode: NetworkMode) = stringPreferencesKey("stream_quality_${mode.key}")
|
||||
|
||||
private fun listQueryKey(tab: LibraryListTab) = stringPreferencesKey("list_query_${tab.key}")
|
||||
|
||||
private fun encode(query: ListQuery) = "${query.sort}|${if (query.descending) 1 else 0}|${query.starred.ordinal}"
|
||||
|
||||
private fun encode(quality: StreamQuality) = "${quality.maxBitrate}|${quality.format.orEmpty()}"
|
||||
|
||||
private fun decodeStreamQuality(stored: String?): StreamQuality {
|
||||
val parts = stored?.split("|") ?: return StreamQuality()
|
||||
return StreamQuality(
|
||||
maxBitrate = parts.getOrNull(0)?.toIntOrNull() ?: 0,
|
||||
format = parts.getOrNull(1)?.takeIf { it.isNotEmpty() },
|
||||
)
|
||||
}
|
||||
|
||||
private fun decode(
|
||||
stored: String?,
|
||||
defaultSort: String,
|
||||
@@ -78,11 +91,6 @@ class UserPreferences(
|
||||
starred = StarredFilter.entries.getOrElse(parts[2].toIntOrNull() ?: 0) { StarredFilter.Any },
|
||||
)
|
||||
}
|
||||
|
||||
private companion object {
|
||||
val MAX_BITRATE = intPreferencesKey("max_bitrate")
|
||||
val STREAM_FORMAT = stringPreferencesKey("stream_format")
|
||||
}
|
||||
}
|
||||
|
||||
fun createUserPreferences(context: Context): UserPreferences = UserPreferences(context.preferences)
|
||||
|
||||
Reference in New Issue
Block a user